api.md 8.3 KB

smartbotic-vectorapi — API Reference

Version 0.1.0. This is the human-readable reference. Machine-readable equivalents are served live by the running service and shipped in the package:

  • GET /openapi.json — OpenAPI 3.1 spec (source: api/openapi.json).
  • GET /llms.txt — a compact, agent-friendly summary following the llmstxt.org convention (source: api/llms.txt).
  • GET /docs — this reference rendered as an interactive page (Redoc).

Base & authentication

  • Base path: /api/v1. All /api/v1/* routes require authentication.
  • API clients send an API key as a bearer token: Authorization: Bearer <KEY>.
  • The web UI logs in with a key (POST /ui/login) and rides a cookie session thereafter (credentials: include).
  • Public (no auth): GET /healthz, GET /readyz, GET /openapi.json, GET /llms.txt, GET /docs, and the static UI.

Authorization model (MySQL-like grants)

Each API key carries grants: a set of project names it may access (or "*" for all) plus an admin flag.

Route class Requirement On failure
/api/v1/projects/{project}/… (collections, documents, vectors, search, project stats) key is admin, or holds "*", or lists {project} 403
POST/DELETE /api/v1/projects, all /api/v1/keys, GET /api/v1/stats admin 403
GET /api/v1/projects any valid key (result filtered to granted projects)
any /api/v1/* with a missing/unknown key 401

On first run with no keys, the service generates one admin key (projects:["*"], admin:true) and logs it once.

Errors

All errors return JSON {"error": {"code": "<slug>", "message": "<text>"}} with a standard HTTP status: 400 malformed request, 401 unauthenticated, 403 forbidden (valid key lacking the grant), 404 not found, 422 validation (bad body, dimension mismatch, reserved name), 503 database/embedding unavailable, 500 unexpected.


Projects

A project is an isolated namespace (collections in one project are invisible to others). default always exists and cannot be deleted.

Method Path Auth Body / notes
GET /api/v1/projects any key {"projects": ["default", ...]} (only granted projects)
POST /api/v1/projects admin {"name":"acme"} — name ^[a-zA-Z_][a-zA-Z0-9_-]{0,62}$201 {"name":"acme"}
GET /api/v1/projects/{project} project access {"name","collections"}
DELETE /api/v1/projects/{project} admin drops the project + its collections (not default)
curl -s -X POST $BASE/api/v1/projects -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' -d '{"name":"acme"}'

API keys (admin only)

Keys are referenced by a stable, non-secret id (from the list); the secret value is only shown once, at creation.

Method Path Body / notes
GET /api/v1/keys {"keys":[{id,label,projects,admin,created_at,key_prefix}]} (secret masked)
POST /api/v1/keys {"label":"n8n","projects":["acme"],"admin":false}201 with the full key once
PATCH /api/v1/keys/{id} {label?,projects?,admin?} — update grants
DELETE /api/v1/keys/{id} revoke (rejected with 422 if it's the last admin)
# create a scoped key for n8n, limited to project "acme"
curl -s -X POST $BASE/api/v1/keys -H "Authorization: Bearer $ADMIN" \
  -H 'Content-Type: application/json' \
  -d '{"label":"n8n-acme","projects":["acme"],"admin":false}'
# → {"id":"...","label":"n8n-acme","projects":["acme"],"admin":false,"key":"<shown once>"}

Collections

Collections are admin-managed: create one before writing. kind is json (documents) or vector (RAG; fixed vector_dimension). Names may not start with _ or the reserved vectorapi_ prefix.

Method Path Body / notes
POST /api/v1/projects/{p}/collections {"name","kind":"json"\|"vector","vector_dimension"?,"embedding_model"?}
GET /api/v1/projects/{p}/collections {"collections":[{name,kind,vector_dimension,embedding_model,document_count,size_bytes}]}
GET /api/v1/projects/{p}/collections/{name} one collection's info
DELETE /api/v1/projects/{p}/collections/{name} drop it

embedding_model (vector collections) is the OpenAI model used when storing/ searching by text; its output dimension must equal vector_dimension (text-embedding-3-small = 1536, text-embedding-3-large = 3072).

curl -s -X POST $BASE/api/v1/projects/acme/collections -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"memories","kind":"vector","vector_dimension":1536,"embedding_model":"text-embedding-3-small"}'

JSON documents

Under /api/v1/projects/{p}/collections/{name}/documents.

Method Path Body / notes
POST .../documents {"id"?,"data":{...}} (or the raw doc) → 201 {"id"}
GET .../documents/{id} the document
GET .../documents find — query params below → {"documents":[...],"count"}
PATCH .../documents/{id} merge fields → {"id","version"}
PUT .../documents/{id} replace the whole document
DELETE .../documents/{id} delete

Find query params: filter (repeatable, field:op:value, AND-combined), limit, offset, sort, desc (true/false). Operators (op): eq, ne, gt, gte, lt, lte, in, contains, exists, regex, search. The value is parsed as JSON when possible, else as a string.

curl -s -X POST $BASE/api/v1/projects/acme/collections/users/documents -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' -d '{"data":{"name":"Alice","age":30}}'

curl -s "$BASE/api/v1/projects/acme/collections/users/documents?filter=age:gte:18&filter=name:search:Ali&limit=20&sort=age&desc=true" \
  -H "Authorization: Bearer $KEY"

RAG: vectors & similarity search

Under /api/v1/projects/{p}/collections/{name} (vector collections only).

Method Path Body
POST .../vectors {"id"?,"text"?,"vector"?,"metadata"?} — provide vector to store as-is, or text to embed (OpenAI) → 201 {"id"}
POST .../search {"query_text"?\|"query_vector"?,"top_k":5,"min_score":0.0}{"results":[{id,score,data}]} ordered by descending cosine similarity

A provided/generated vector's length must equal the collection's vector_dimension (else 422). Storing by text or searching by query_text requires OPENAI_API_KEY to be configured (else 422/503).

curl -s -X POST $BASE/api/v1/projects/acme/collections/memories/vectors -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' -d '{"text":"user prefers dark mode","metadata":{"src":"n8n"}}'

curl -s -X POST $BASE/api/v1/projects/acme/collections/memories/search -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' -d '{"query_text":"dark mode","top_k":5,"min_score":0.7}'

Stats & ops

Method Path Auth Returns
GET /api/v1/projects/{p}/stats project access {project, collections, documents}
GET /api/v1/stats admin server-wide: documents, collections, memory, pressure level, project count
GET /healthz public {"status":"ok"} (liveness)
GET /readyz public {"ready":bool}200 if the database is reachable, else 503

Web UI session

Method Path Body / notes
POST /ui/login {"key":"<API key>"} → sets an HttpOnly svapi_session cookie; body {ok,admin,projects}
POST /ui/logout clears the session cookie

n8n usage notes

  • Use an HTTP Request node with Header Auth / a generic Authorization: Bearer <key> header.
  • Give each workflow (or tenant) its own project and a scoped key granted only that project — so a leaked key can't reach other tenants' data.
  • For RAG: create a vector collection with the embedding model matching your dimension, POST .../vectors with text to ingest, and POST .../search with query_text to retrieve context for the LLM node.
  • For everything else: a json collection with POST .../documents (store) and GET .../documents?filter=... (query).