VectorDB quickstart
In about five minutes you will create a vector index, insert two points, run a similarity search, browse what is stored, and clean up.
Before you begin
-
You have a platform account and can sign in. If not, ask your administrator for an account or an invitation link — see Create an account.
-
You have installed the platformctl CLI and run
platformctl login. -
For the
curltabs, you need your project ID. It is a UUID — a 36-character random identifier such as7f3c1e02-9b5d-4a11-8c6f-2d0e5a91b4cc. Read it out of the console URL (#/projects/<uuid>/...), or runplatformctl projects list.export VDB="https://api.codyhill.dev" # VectorDB is served on the shared public APIexport CAI_PROJECT="00000000-0000-0000-0000-000000000000" # your project UUIDexport CAI_TOKEN="<your session token or API key>"The
platformctltabs need none of this.
vectordb upsert and query take their JSON through --points and --vector. Each of those flags accepts a literal string, @file to read a file, or - to read standard input. So any body written for the curl tabs pipes straight in.
Step 1: Create an index
Only the name is required. This example uses 4 dimensions so the demo vectors are short enough to type by hand. Real embedding models produce hundreds or thousands of numbers per vector, which is what you get if you leave dimensions out — the width of the platform's own hosted model.
- platformctl
- curl
- Console
platformctl vectordb create docs --dimensions 4 --distance cosine
curl -sX POST "$VDB/v1/projects/$CAI_PROJECT/indexes" \
-H "Authorization: Bearer $CAI_TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"docs","dimensions":4,"distance":"cosine"}'
You should see (HTTP 201):
{"name":"docs","resource_path":"projects/<short>/indexes/docs","collection":"p_<short>_docs","dimensions":4,"distance":"cosine","state":"pending","ready":false,...}
Go to Data services → VectorDB in your project and click Create index. Set dimensions to 4 and distance to cosine in the Create vector index dialog.
The API answers before the index is usable. state starts at pending, then moves to ready once the platform has finished building the storage behind it.
Distance accepts cosine, dot, or euclid, and the usual aliases (dot_product, l2) are understood. dimensions and distance cannot be changed later — only replicas and payload_on_disk are mutable.
dimensions is 4096 — not the defaultThis walkthrough uses 4 dimensions so the vectors are short enough to type. For real work, omit dimensions entirely: you get the width of the platform's hosted model, qwen-embedding, which is what POST /v1/embeddings returns. Set a width explicitly only when your vectors come from somewhere else.
Take the default while embedding with qwen-embedding and every upsert fails:
{"error":"point 0 has 4096 dimensions; index \"my-corpus\" expects 4","request_id":"..."}
Since dimensions is fixed at creation, recovery means deleting the index and loading the whole corpus again. Set it up front:
platformctl vectordb create my-corpus --dimensions 4096 --distance cosine
Measure any model's width rather than trusting a number — platformctl inference embed "hello" prints a DIMENSIONS column. See Inference.
Step 2: Wait for it to be ready
- platformctl
- curl
- Console
platformctl vectordb get docs
Repeat until READY reads yes.
curl -s "$VDB/v1/projects/$CAI_PROJECT/indexes/docs" \
-H "Authorization: Bearer $CAI_TOKEN"
You should see:
{"name":"docs","state":"ready","ready":true,"collection_status":"green","points_count":0,...}
Repeat until "ready": true.
The index list shows the state and refreshes on its own while the index is pending.
If you write points before that, the API answers with a clear 409:
{"error":"index is not ready yet; its collection has not been created","request_id":"..."}
Step 3: Insert points
A point is a vector plus an optional JSON payload and an optional id. An id must be either an unsigned integer — a whole number, zero or greater — or a UUID string. Leave the id out and the platform generates a UUID for you.
- platformctl
- curl
- Console
platformctl vectordb upsert docs --points '{"points":[
{"id":1,"vector":[0.1,0.2,0.3,0.4],"payload":{"tag":"alpha"}},
{"vector":[0.9,0.8,0.7,0.6],"payload":{"tag":"beta"}}]}'
curl -sX POST "$VDB/v1/projects/$CAI_PROJECT/indexes/docs:upsert" \
-H "Authorization: Bearer $CAI_TOKEN" -H 'Content-Type: application/json' \
-d '{"points":[
{"id":1,"vector":[0.1,0.2,0.3,0.4],"payload":{"tag":"alpha"}},
{"vector":[0.9,0.8,0.7,0.6],"payload":{"tag":"beta"}}]}'
You should see:
{"index":"docs","upserted_count":2}
Note the :upsert suffix. Writing and searching points are custom methods: a literal :verb on the end of the index path, always with POST. There is no query parameter form.
The console does not write points, by design — a browser form is the wrong place to type hundreds of floats per vector, and embeddings should come from your code rather than a textarea.
Use the platformctl or curl tab for this step. The console's job here is the read side: once points exist, its Data browser and Query panel are how you check that the index actually answers, and how you remove a single bad point.
What failure looks like
Every vector must match the index's width exactly. Send a 3-number vector into this 4-dimension index and the whole batch is rejected. Nothing is partially written:
{"error":"point 0 has 3 dimensions; index \"docs\" expects 4","request_id":"..."}
This is the most common first-run error with real embeddings too, and the usual cause is an index whose width does not match the model that produced the vectors. Fix it by creating a new index with the right dimensions — or by omitting dimensions, which sizes the index for the platform's own model. You cannot change that value later.
Step 4: Search
Query with a vector, ask for the top 5 nearest, and filter to points whose payload has tag = alpha.
- platformctl
- curl
- Console
platformctl vectordb query docs \
--vector '[0.1,0.2,0.3,0.4]' --top-k 5 \
--filter '{"must":[{"key":"tag","match":{"value":"alpha"}}]}'
You should see:
ID SCORE PAYLOAD
1 1.0000 {"tag":"alpha"}
curl -sX POST "$VDB/v1/projects/$CAI_PROJECT/indexes/docs:query" \
-H "Authorization: Bearer $CAI_TOKEN" -H 'Content-Type: application/json' \
-d '{"vector":[0.1,0.2,0.3,0.4],"top_k":5,
"filter":{"must":[{"key":"tag","match":{"value":"alpha"}}]}}'
You should see:
{"index":"docs","results":[{"id":1,"score":1.0,"payload":{"tag":"alpha"}}]}
Open the index and use its search panel: paste the query vector, set the result count, and add the payload filter.
The query vector is identical to point 1's vector, so with cosine distance its score is a perfect 1.0. Point 2 exists but is filtered out by the payload filter.
Step 5: Browse what is stored
Scroll lists points in id order and needs no query vector. Use it to eyeball what is actually there.
- platformctl
- curl
- Console
platformctl vectordb scroll docs --limit 50
And confirm the index itself:
platformctl vectordb list
You should see:
NAME DIMENSIONS DISTANCE STATE READY POINTS
docs 4 cosine ready yes 2
curl -sX POST "$VDB/v1/projects/$CAI_PROJECT/indexes/docs:scroll" \
-H "Authorization: Bearer $CAI_TOKEN" -H 'Content-Type: application/json' \
-d '{"limit":50}'
You should see:
{"index":"docs","points":[{"id":1,"payload":{"tag":"alpha"}},{"id":"<generated-uuid>","payload":{"tag":"beta"}}]}
Scroll returns no vectors by design — a page of raw vectors is large and is not what a browser shows. A next_offset comes back when there is another page.
The index detail page lists its points with their payloads, and pages through them.
points_count is a periodic sweep, not a live counterThe points_count on an index — the POINTS column above — is refreshed on a schedule rather than updated on every write. Immediately after an upsert it can still read the old number. scroll reads the points themselves and is always current.
Clean up
Deleting an index destroys the index and every vector in it. There is no undo and no snapshot. Index deletion requires the project admin role.
- platformctl
- curl
- Console
platformctl vectordb delete docs
curl -sX DELETE "$VDB/v1/projects/$CAI_PROJECT/indexes/docs" \
-H "Authorization: Bearer $CAI_TOKEN" -w '%{http_code}\n'
You should see:
204
Open the index and click Delete index, then confirm.
To remove points without dropping the index, use :delete-points with either ids or a filter.
Next steps
- Indexes and points — dimensions, distance metrics, ids, payloads, and what's immutable.
- Search — filters, scores, thresholds, and browsing in depth.
- Use with agents — give a deployed agent long-term memory.
- API reference — the complete endpoint list.