HTTP API reference

August 6, 2026 · View on GitHub

Zvec Studio speaks a single versioned REST API under /api/v1. The authoritative schema is served live from the running backend:

This document is a stable highlight reel. For exact field types and examples, hit the live OpenAPI and use pnpm gen:api to regenerate the typed client.


Conventions

  • Base URL: http://127.0.0.1:7860/api/v1
  • Every response carries X-Trace-Id: <ULID>.
  • Errors follow RFC 7807 (application/problem+json), extended with code and sdkException fields — see overview.md and backend.md §9.
  • Action verbs use AIP-136 :action suffix (e.g. :browse, :upsert).

Error shape

{
  "type": "about:blank",
  "title": "Collection Not Found",
  "status": 404,
  "code": "COLLECTION_NOT_FOUND",
  "detail": "Collection 'demo' is not open.",
  "traceId": "01HZX…",
  "sdkException": "CollectionNotFoundError",
  "name": "demo"
}
HTTPCommon codeMeaning
400INVALID_FILTER_EXPRESSIONFilter DSL failed to parse
400DIMENSION_MISMATCHQuery vector ≠ collection dim
404COLLECTION_NOT_FOUNDCollection not open
404DOCUMENT_NOT_FOUNDPrimary key missing
404AI_FUNCTION_NOT_FOUNDEmbedding/reranker name not found
409COLLECTION_ALREADY_EXISTSDuplicate open / create call
409AI_FUNCTION_ALREADY_EXISTSDuplicate AI function name
422INVALID_SCHEMASchema validation error
500INTERNAL_ERRORUnhandled; file an issue with traceId
503AI_DEPENDENCY_MISSINGOptional ML package not installed

Health

VerbPathDescription
GET/api/v1/healthzLiveness — always {status: "ok"} when the process is up
GET/api/v1/readyzReadiness — 200 once the registry is initialised

Collections — Lifecycle

VerbPathPurpose
GET/collectionsList open collections
POST/collectionsCreate and open a collection
POST/collections/openOpen an existing on-disk collection
GET/collections/{name}Detail (schema + stats in one call)
GET/collections/{name}/schemaSchema only
GET/collections/{name}/statsStats only (document count, index status, storage size)
DELETE/collections/{name}Remove from in-process registry (does not delete files on disk)

Collections — Recent (workspace persistence)

VerbPathPurpose
GET/collections/recentList recently opened paths (persisted in ~/.zvec-studio/config.json, max 10)
DELETE/collections/recentClear the recent list
POST/collections/recent:forgetRemove a single {path} from recents

Collections — Maintenance verbs

VerbPathPurpose
POST/collections/{name}:flushPersist pending writes
POST/collections/{name}:optimizeSegment merge + index rebuild
POST/collections/{name}:destroyPermanently delete on-disk data

Collections — DDL (Schema Evolution)

VerbPathPurpose
POST/collections/{name}/fieldsAdd a scalar field (with optional expression for backfill)
DELETE/collections/{name}/fields/{field}Drop a scalar field
PATCH/collections/{name}/fields/{field}Rename a scalar field
POST/collections/{name}/indexesCreate / rebuild a vector index
DELETE/collections/{name}/indexes/{vector_field}Drop a vector index

Create payload

{
  "name": "demo",
  "path": "./data/demo",
  "schema": {
    "fields": [
      {"name": "title", "dataType": "STRING"}
    ],
    "vectors": [
      {
        "name": "dense",
        "dataType": "VECTOR_FP32",
        "dimension": 768,
        "indexParam": {
          "indexType": "HNSW",
          "metric": "COSINE",
          "params": {
            "M": 50,
            "efConstruction": 500,
            "quantizeType": "INT8",
            "quantizerParam": {"enableRotate": true}
          }
        }
      },
      {
        "name": "sparse",
        "dataType": "VECTOR_FP32",
        "dimension": 128,
        "indexParam": {
          "indexType": "FLAT",
          "metric": "L2"
        }
      }
    ]
  }
}

Multiple vector fields are supported, each with its own index type (FLAT, HNSW, IVF, HNSW_RABITQ), metric (L2, IP, COSINE), and optional quantization (FP16, INT8, INT4, RABITQ). Zvec 0.6 random rotation is available for INT8/INT4 through quantizerParam.enableRotate on FLAT, HNSW, and VAMANA indexes. FTS scalar indexes accept lowercase, ascii_folding, and stemmer filters; configure the stemmer language through extraParams, for example {"stemmer_lang":"english"}.


Documents

VerbPathPurpose
POST/collections/{name}/documentsInsert single or batch
PATCH/collections/{name}/documentsBatch partial update (by id)
GET/collections/{name}/documents/{id}Fetch by primary key
DELETE/collections/{name}/documents/{id}Delete by primary key
POST/collections/{name}/documents:browseFilter browser (filter + limit)
POST/collections/{name}/documents:upsertUpsert by id; missing id auto-generates ULID
POST/collections/{name}/documents:deleteBatchBatch delete by {ids: [...]}
POST/collections/{name}/documents:deleteByFilterDelete by filter expression

Browse

POST /api/v1/collections/demo/documents:browse
Content-Type: application/json

{
  "filter": "title = 'cat'",
  "limit": 50,
  "outputFields": ["id", "title"],
  "includeVector": false
}

Response: { items: [...], truncated: true/false }.

Filter DSL

The filter string is passed through to the Zvec SDK unchanged. Examples:

title = 'cat'
score > 0.8 and category in ['animal', 'pet']

Note: Zvec uses single = (not ==) and single-quoted strings.


Request

POST /api/v1/collections/{name}/searches
Content-Type: application/json

{
  "vector":        [0.10, 0.20, 0.30, 0.40],
  "topK":          10,
  "filter":        "title = 'cat'",
  "outputFields":  ["id", "title"]
}

Multi-vector queries (advanced)

{
  "queries": [
    { "field": "dense", "vector": [0.1, 0.2, "..."], "param": { "type": "HNSW", "ef": 256 } },
    { "field": "sparse", "id": "doc-001" }
  ],
  "topK": 20,
  "rerankerName": "rrf-default"
}
  • queries[] supports 1–8 vector queries; each may specify vector (raw array) or id (use an existing document's vector).
  • Per-query param allows index-specific tuning: HNSW(ef), IVF(nprobe), HNSW_RABITQ(ef, ...), VAMANA(efSearch).
  • rerankerName references a registered reranker (see AI Extension below).
  • Legacy single-vector form (vector + vectorField) is still supported; mutually exclusive with queries.

Zvec 0.6 can return the nearest documents per scalar-field group for a single vector query:

{
  "queries": [
    { "field": "dense", "vector": [0.1, 0.2, "..."] }
  ],
  "groupByField": "category",
  "groupCount": 10,
  "topKPerGroup": 3
}

Group-by is supported for FLAT, HNSW, and HNSW_RABITQ indexes. It cannot be combined with FTS, multi-query, rerankers, or refiner search. Each returned result includes groupByValue.

Response

{
  "results": [
    {"id": "cat",    "score": 0.98, "fields": {"title": "cat"}},
    {"id": "kitten", "score": 0.92, "fields": {"title": "kitten"}}
  ],
  "took_ms": 3,
  "traceId": "01HQY8R2FJDN5WXBN2RY5MQZ1T"
}

AI Extension

Zvec Studio surfaces the Zvec SDK's AI capabilities (embeddings, rerankers) as first-class CRUD resources with persistent registration and :embed / :rerank action verbs.

Embeddings

VerbPathPurpose
GET/ai/embeddingsList registered embedding functions
POST/ai/embeddingsCreate (409 on duplicate name)
GET/ai/embeddings/{name}Detail
PUT/ai/embeddings/{name}Update (allows name change; 409 on collision)
DELETE/ai/embeddings/{name}Delete
POST/ai/embeddings/{name}:embedEncode texts[] → vectors

Supported embedding types: default_local_dense, default_local_sparse, bm25, qwen_dense, qwen_sparse, openai_dense.

Rerankers

VerbPathPurpose
GET/ai/rerankersList registered reranker functions
POST/ai/rerankersCreate (409 on duplicate name)
GET/ai/rerankers/{name}Detail
PUT/ai/rerankers/{name}Update
DELETE/ai/rerankers/{name}Delete
POST/ai/rerankers/{name}:rerankCross-encoder reranking (not for fusion types)

Supported reranker types: default_local (cross-encoder), qwen, rrf (fusion), weighted (fusion).

Fusion rerankers (rrf, weighted) cannot be invoked via :rerank — they operate inside Collection.query when referenced by rerankerName in a multi-vector search.

Example: register + use

# Register an RRF reranker
curl -X POST http://127.0.0.1:7860/api/v1/ai/rerankers \
  -H 'Content-Type: application/json' \
  -d '{"name": "rrf-default", "config": {"type": "rrf", "rankConstant": 60}}'

# Use in a multi-vector search
curl -X POST http://127.0.0.1:7860/api/v1/collections/demo/searches \
  -H 'Content-Type: application/json' \
  -d '{"queries": [{"field": "dense", "vector": [...]}, {"field": "sparse", "vector": [...]}], "topK": 10, "rerankerName": "rrf-default"}'

Filesystem

VerbPathPurpose
GET/fs/list?path=...&show_hidden=falseList subdirectories (for the directory picker UI)

Regenerating the client

# While a backend is running:
pnpm gen:api

This pulls the live /openapi.json, generates packages/api-client/src/index.ts, and the frontend type-checks against it. CI fails if regeneration produces a diff — keep API changes + generated client in the same commit.