HTTP API: vectors and embeddings
Vector columns and indexes in your tables, similarity and hybrid search, automatic embeddings, and vector collections with their records.
Embeddings and similarity search over HTTP: pgvector in your own tables (recommended), automatic embeddings, and simpler vector collections. Guide: Vector search and embeddings.
| Base URL | https://<project-ref>.sovarias.in — your project URL from Connect. |
| Keys | Send the project's key as apikey. Calls made for a signed-in user also send Authorization: Bearer <access token>. |
| Errors | A status code and {"detail": …} — a sentence, or {code, message} for errors your code may branch on (HTTP API). |
Vectors in your tables (pgvector)
GET/api/v1/data/rel/vector/status
Whether pgvector is installed and which vector columns exist.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/status
Returns
availableboolean- The extension can be installed.
enabledboolean- It is installed.
versionstring- pgvector version.
columnsarray<object>- Vector columns: table, column, dimensions.
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/data/rel/vector/status" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"available": true,
"enabled": true,
"version": "0.8.0",
"columns": [
{
"table": "documents",
"column": "embedding",
"dimensions": 1536
}
]
}POST/api/v1/data/rel/vector/enable
Install (or check) the pgvector extension.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/enable
Body
enabledbooleanoptionaldefaulttruetrueto install.
Responses
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/data/rel/vector/enable" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"enabled": true}'Response
{
"available": true,
"enabled": true,
"version": "0.8.0",
"columns": [
{
"table": "documents",
"column": "embedding",
"dimensions": 1536
}
]
}POST/api/v1/data/rel/vector/tables
Create a table for embeddings: id, content, metadata and a vector column.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/tables
Body
table_namestringrequired- The new table.
- 1–63 characters
dimensionsintegerrequired- Vector size of your embedding model (e.g. 1536).
- 1.0–16000.0
owner_rowsbooleanoptionaldefaultfalse- Add
owner_idand row-level security so each user only sees their own rows.
Responses
- 200Success.
- 400Bad name or dimensions, or the table exists.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/data/rel/vector/tables" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "dimensions": 1536, "owner_rows": true}'Response
{
"status": "ok",
"table": "documents",
"dimensions": 1536,
"owner_rows": true
}POST/api/v1/data/rel/vector/columns
Add a vector column to an existing table.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/columns
Body
table_namestringrequired- The table.
- 1–63 characters
column_namestringoptionaldefaultembedding- The new column (default
embedding). - 1–63 characters
dimensionsintegerrequired- Vector size (1–16,000; HNSW indexes work up to 2,000).
- 1.0–16000.0
Responses
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/data/rel/vector/columns" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "products", "column_name": "embedding", "dimensions": 768}'Response
{
"status": "ok",
"table": "products",
"column": "embedding",
"dimensions": 768
}POST/api/v1/data/rel/vector/indexes
Create an HNSW index on a vector column for fast similarity search.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/indexes
Body
table_namestringrequired- The table.
- 1–63 characters
column_namestringoptionaldefaultembedding- The vector column.
- 1–63 characters
metricstringoptionaldefaultcosinecosine,l2orinner_product— use the one you search with.- One of
cosine,l2,inner_product
Responses
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/data/rel/vector/indexes" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "metric": "cosine"}'Response
{
"status": "ok",
"index": "documents_embedding_cosine_idx",
"method": "hnsw",
"metric": "cosine"
}POST/api/v1/data/rel/vector/rows
Insert rows with their vectors (up to 500 per request).
Vectors are bound as parameters. A vector of the wrong size fails with an error naming the expected size.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/rows
Body
table_namestringrequired- The table.
- 1–63 characters
column_namestringoptionaldefaultembedding- The vector column.
- 1–63 characters
rowsarray<object>required- 1–500 objects: column values, with the vector under
column_name. - 1–500 items
Responses
- 200Success.
- 400Wrong vector size, or a column that doesn't exist.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/data/rel/vector/rows" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "rows": [{"content": "How to reset your password", "metadata": {"lang": "en"}, "embedding": [0.012, -0.044, "…"]}]}'Response
{
"status": "ok",
"inserted": 1
}POST/api/v1/data/rel/vector/search
Find the rows closest to a vector — or to text, with keyword and hybrid ranking.
Runs as the caller, so row-level security applies, and still returns k results: the index keeps scanning past rows the caller can't see. Send vector for similarity search, text for keyword (full-text) search, or both (hybrid, the default when text is given): results are fused by rank.
- Who
- Your app: the project's anon key (
apikey: <anon key>), with the user's access token once they are signed in. - Also at
/rest/rel/vector/search
Body
table_namestringrequired- The table.
- 1–63 characters
column_namestringoptionaldefaultembedding- The vector column.
- 1–63 characters
vectorarray<number> | nulloptional- The query vector (same size as the column).
textstring | nulloptional- Query text for keyword / hybrid search; with auto-embeddings on, it's embedded for you.
- 1–2,000 characters
modestring | nulloptionalvector,keywordorhybrid.- One of
vector,keyword,hybrid text_columnsarray<string> | nulloptional- Columns for keyword search (default: the auto-embedding sources, else
content). - 1–10 items
languagestringoptionaldefaultsimple- Postgres text-search configuration (
simple,english…). - pattern `^[a-z_]{1,32}
HTTP API: vectors and embeddings | Sovaria Docs kintegeroptionaldefault5- How many results (1–100).
- 1.0–100.0
metricstringoptionaldefaultcosinecosine,l2orinner_product.- One of
cosine,l2,inner_productselectarray<string> | nulloptional- Columns to return (default: all but the vector).
- 0–50 items
filterobject<string, string | integer | number | boolean | null>optional- Exact-match filters on columns, e.g.
{"lang": "en"}.max_distancenumber | nulloptional- Drop results farther than this.
resultsarray<object>- The selected columns plus
distance(smaller is closer; inner product is reported positive). Hybrid addsscore(fused),vector_rankandkeyword_rank; keyword mode addskeyword_score. mode, metric, kstring, string, integer- What ran.
- 200Success.
- 400Neither
vectornortext, a size mismatch, or an unknown column. - 403Refused by your access policies.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/auto- 200Success.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/autotable_namestringrequired- The table.
- 1–63 characters
column_namestringoptionaldefaultembedding- Vector column (created if missing).
- 1–63 characters
source_columnsarray<string>required- 1–10 text columns to embed (joined).
- 1–10 items
rebuildbooleanoptionaldefaultfalse- Clear every vector and embed the table again.
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/auto/synctable_namestring | nulloptional- One table (default: all).
- 1–63 characters
limitintegeroptionaldefault128- Rows per call (1–256).
- 1.0–256.0
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - Also at
/rest/rel/vector/auto/{table_name}table_namestringrequired- The table.
- 200Success.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection (created on first use).
- 1–64 characters
docsarray<object>required- 1–256 documents.
- 1–256 items
3 fields
idstring | nulloptional- Your id; a new one is generated when left out.
textstringrequired- The text to embed.
metadataobjectoptional- Any JSON, for filtering.
inserted, updatedintegerdiminteger- Vector size.
sizeinteger- Records in the collection now.
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your app: the project's anon key (
apikey: <anon key>), with the user's access token once they are signed in. collectionstringrequired- The collection.
- 1–64 characters
querystringrequired- The search text.
- 1–2,000 characters
top_kintegeroptionaldefault5- How many results (1–100).
- 1.0–100.0
metadata_filterobjectoptional- Only records whose metadata has these values.
modestring | nulloptionalvector,keywordorhybrid.- One of
vector,keyword,hybrid resultsarray<object>{id, text, metadata, score}, best first.semanticboolean- Whether the model captures meaning (a real embedding model) or is hash-based.
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. textsarray<string>required- 1–512 texts.
- 1–512 items
vectorsarray<array<number>>requireddimintegerrequiredcountintegerrequiredmodelstringoptional- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. - 200Success.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection.
app_searchboolean | nulloptional- Let signed-in app users search it.
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection.
limitintegeroptionaldefault100- How many.
- 1–500
offsetintegeroptionaldefault0- How many to skip.
- 0–…
- 200Success.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection.
record_idstringrequired- The record's id.
- 204Success, with no body.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection.
- 204Success, with no body.
- 401No valid session or key.
- Who
- Your team or your backend: a member's session, or a server key (
apikey: <service role or custom key>). Never from a browser or app. collectionstringrequired- The collection.
- 200Success.
- 401No valid session or key.
Returns
Responses
curl -s -X POST "$URL/api/v1/data/rel/vector/search" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "text": "I forgot my login", "k": 3, "select": ["id", "content"], "filter": {"lang": "en"}}'Response
{
"table": "documents",
"metric": "cosine",
"k": 3,
"mode": "hybrid",
"results": [
{
"id": 12,
"content": "How to reset your password",
"distance": 0.182,
"score": 0.0325,
"vector_rank": 1,
"keyword_rank": 1
},
{
"id": 7,
"content": "Signing in with a magic link",
"distance": 0.247,
"score": 0.0317,
"vector_rank": 2,
"keyword_rank": 3
}
]
}Automatic embeddings
GET/api/v1/data/rel/vector/auto
Tables that embed their rows automatically, and the embedding model.
The model is openai/<model>@<dims> or gemini/<model>@<dims> when an embedding provider is configured, otherwise local-hash-<dims> (hash-based: matches words, not meaning).
Responses
curl -s "$URL/api/v1/data/rel/vector/auto" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"model": {
"model": "openai/text-embedding-3-small@1536",
"dim": 1536,
"semantic": true
},
"tables": [
{
"table": "documents",
"column": "embedding",
"source_columns": [
"title",
"content"
],
"model": "openai/text-embedding-3-small@1536",
"embedded": 3120,
"pending": 0,
"synced_at": "2026-10-17T13:10:00Z",
"last_error": null
}
]
}POST/api/v1/data/rel/vector/auto
Embed a table's rows automatically from text columns (and keep them up to date).
Adds the vector column if needed and embeds existing rows in the background; new and changed rows are embedded as they are written. Recorded as a migration you can roll back.
Body
Responses
curl -s -X POST "$URL/api/v1/data/rel/vector/auto" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "source_columns": ["title", "content"]}'Response
{
"status": "ok",
"table": "documents",
"column": "embedding",
"source_columns": [
"title",
"content"
],
"model": "openai/text-embedding-3-small@1536",
"dimensions": 1536,
"created_column": true,
"background": true,
"embedded": 128,
"migration_version": "20261017131500",
"reversible": true
}POST/api/v1/data/rel/vector/auto/sync
Embed rows that are still waiting (up to 256 per call).
Body
Responses
curl -s -X POST "$URL/api/v1/data/rel/vector/auto/sync" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"table_name": "documents", "limit": 128}'Response
{
"tables": [
{
"table": "documents",
"embedded": 64
}
],
"embedded": 64
}DELETE/api/v1/data/rel/vector/auto/{table_name}
Stop embedding a table automatically (the vectors stay).
Path parameters
Responses
curl -s -X DELETE "$URL/api/v1/data/rel/vector/auto/documents" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"status": "ok",
"table": "documents",
"enabled": false,
"migration_version": "20261017132000",
"reversible": true
}Vector collections
POST/api/v1/vectors/upsert
Add or update texts in a vector collection; Sovaria embeds them.
The collections API embeds for you with the project's embedding model (see semantic in the list response: without a configured provider the built-in embeddings are hash-based, fine for exact-ish matching, not for meaning — Vector search and embeddings).
Body
Returns
Responses
curl -s -X POST "$URL/api/v1/vectors/upsert" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"collection": "help-articles", "docs": [{"id": "a1", "text": "How to reset your password", "metadata": {"lang": "en"}}, {"id": "a2", "text": "Exporting invoices as PDF", "metadata": {"lang": "en"}}]}'Response
{
"inserted": 2,
"updated": 0,
"dim": 1536,
"size": 2
}POST/api/v1/vectors/search
Search a vector collection by text.
App users can search a collection when it has app_search on (PATCH /api/v1/collections/{collection}).
Body
Returns
Responses
curl -s -X POST "$URL/api/v1/vectors/search" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"collection": "help-articles", "query": "I forgot my login", "top_k": 2, "metadata_filter": {"lang": "en"}}'Response
{
"results": [
{
"id": "a1",
"text": "How to reset your password",
"metadata": {
"lang": "en"
},
"score": 0.83
}
],
"count": 1,
"mode": "vector",
"model": "openai/text-embedding-3-small@1536",
"semantic": true
}POST/api/v1/embed
Get embedding vectors for texts (up to 512).
Body
Returns
Responses
curl -s -X POST "$URL/api/v1/embed" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"texts": ["red running shoes", "blue sandals"]}'Response
{
"vectors": [
[
0.012,
-0.044,
"…"
],
[
0.031,
0.007,
"…"
]
],
"dim": 1536,
"count": 2,
"model": "openai/text-embedding-3-small@1536"
}GET/api/v1/collections
The project's vector collections and the embedding model.
Responses
curl -s "$URL/api/v1/collections" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"collections": [
{
"name": "help-articles",
"dim": 1536,
"size": 2,
"model": "openai/text-embedding-3-small@1536",
"app_search": false
}
],
"model": "openai/text-embedding-3-small@1536",
"semantic": true
}PATCH/api/v1/collections/{collection}
Change a collection's settings.
Path parameters
Body
Responses
curl -s -X PATCH "$URL/api/v1/collections/help-articles" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"app_search": true}'Response
{
"collection": "help-articles",
"settings": {
"app_search": true
}
}GET/api/v1/collections/{collection}/records
A collection's records.
Path parameters
Query parameters
Responses
curl -s "$URL/api/v1/collections/help-articles/records" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"collection": "help-articles",
"dim": 1536,
"total": 2,
"records": [
{
"id": "a1",
"text": "How to reset your password",
"metadata": {
"lang": "en"
}
}
]
}DELETE/api/v1/collections/{collection}/records/{record_id}
Delete one record.
Path parameters
Responses
curl -s -X DELETE "$URL/api/v1/collections/help-articles/records/a2" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"DELETE/api/v1/collections/{collection}
Delete a collection and its records.
Path parameters
Responses
curl -s -X DELETE "$URL/api/v1/collections/help-articles" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"POST/api/v1/collections/{collection}/reembed
Embed every record again with the current model (after changing models).
Path parameters
Responses
curl -s -X POST "$URL/api/v1/collections/help-articles/reembed" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"collection": "help-articles",
"records": 2,
"model": "openai/text-embedding-3-small@1536"
}