Documents

Insert Document

Add a document to your database. Vecstore automatically generates embeddings and indexes the content for semantic search.

POST/databases/{id}/documents
Database type

Request

Replace {id} in the path with your database ID and send a JSON body like this one.

Example request
{
  "id": "article-1042",
  "content": "How to fix a leaky kitchen faucet",
  "metadata": {
    "category": "home-repair",
    "tags": ["plumbing", "DIY"]
  }
}

Document ·required

content string
Text to insert and index

Optional

id string
Your own ID for the document, such as a SKU or a row ID from your database. Up to 255 characters. If a document with this ID exists, it is updated. Leave it out to get a generated ID
metadata object
Any JSON fields to store with the document. You get them back in search results and can filter by them

Response

Documents are indexed in the background and become searchable within a few seconds.

Example response
{
  "status": "processing",
  "id": "article-1042"
}
status string
processing while the document is being indexed, or completed when only its metadata changed
id string
The ID you sent, or a generated one. Use it to check its status, update it, delete it, or find similar documents

Updating Documents

Insert a document again with the same id to replace it. Its content, embedding and metadata are all replaced, so send every metadata key you want to keep. Your IDs work everywhere: status, update, delete and find similar, so you never need to store ours.

Example request
{
  "id": "article-1042",
  "content": "How to fix a leaky kitchen faucet",
  "metadata": {
    "category": "home-repair",
    "tags": ["plumbing", "DIY"],
    "featured": true
  }
}

What it costs

  • Content changed: the document is embedded again and costs one credit, like a new insert.
  • Content unchanged: only the metadata is replaced, instantly and for free. The response says completed. Images count as unchanged only if the file is byte-for-byte identical.

This makes re-importing a whole catalog cheap: you pay only for the documents whose text or image changed.

Tip: to change a few metadata keys without sending the content, use Update Document. If you send several updates to the same ID quickly, the last one you sent wins.

Batch Insert

Insert up to 100 documents in one request. Each document still costs one credit, but you make far fewer requests, so it's the fastest way to import large datasets.

POST/databases/{id}/documents/batch
Example request
{
  "documents": [
    { "id": "article-1042", "content": "How to fix a leaky kitchen faucet", "metadata": { "category": "home-repair" } },
    { "id": "article-1043", "content": "Replacing a broken window latch", "metadata": { "category": "home-repair" } },
    { "content": "No id given, so one is generated" }
  ]
}
documents array required
1–100 documents, each with the same fields as a single insert
Example response
{
  "status": "processing",
  "ids": [
    "article-1042",
    "article-1043",
    "9b1c2f7e-0d44-4a51-8f3e-6c2a1d9e7b30"
  ],
  "unchanged": 1
}
ids string[]
IDs of the documents, in the same order as documents
unchanged integer
Documents whose content was unchanged, so only their metadata was replaced, free of charge

Limits

  • The whole request, including images fetched from image_url, must stay under 10 MB.
  • If any document is invalid, the whole request is rejected and the error names the item, e.g. documents[3]: ...
  • Each id can appear only once per request.

Insert Status FREE

Check whether a document has been indexed using its id. Use GET for one document, or POST for up to 1,000 at once.

GET/databases/{id}/documents/{doc_id}/statusPOST/databases/{id}/documents/status
Example request (POST)
{
  "ids": [
    "article-1042",
    "9b1c2f7e-0d44-4a51-8f3e-6c2a1d9e7b30"
  ]
}
Example response (POST)
{
  "documents": [
    { "id": "article-1042", "status": "completed" },
    { "id": "9b1c2f7e-0d44-4a51-8f3e-6c2a1d9e7b30", "status": "failed", "reason": "Embedding failed" }
  ]
}

GET returns a single status object. POST returns them in a documents array.

Statuses

StatusMeaning
processing Still being indexed.
completed Indexed and searchable.
failed Indexing failed. The credit is refunded and a reason field says why. Kept for 7 days.
not_found Unknown ID, a deleted document, or a failure older than 7 days.

Tips for Faster Inserts

Resize images before sending

Vecstore looks at every image at 384×384 pixels, so larger images are downscaled anyway. Resizing to 384×384 on your side turns a 1–3 MB photo into a ~40 KB JPEG with no loss in search quality. Uploads finish faster, processing is quicker, and far more images fit into each batch under the 10 MB limit. If you use image_url, point it at a resized version of the image for the same benefit.

Python (Pillow)
import base64, io
from PIL import Image

def prepare_image(path):
    img = Image.open(path).convert("RGB").resize((384, 384))
    buf = io.BytesIO()
    img.save(buf, "JPEG", quality=90)
    return base64.b64encode(buf.getvalue()).decode()
JavaScript (browser)
async function prepareImage(file) {
  const bitmap = await createImageBitmap(file);
  const canvas = document.createElement("canvas");
  canvas.width = canvas.height = 384;
  canvas.getContext("2d").drawImage(bitmap, 0, 0, 384, 384);
  return canvas.toDataURL("image/jpeg", 0.9).split(",")[1];
}

Use batch inserts

Send up to 100 documents per request with /documents/batch. Documents in a batch are embedded together on the GPU, which is much faster than inserting them one at a time. For large imports, run a few batch requests in parallel.