quiver
Documentation menu

REST API

JSON over HTTP, on port 6900 by default. Request bodies must be sent with content-type: application/json (except snapshot uploads), and may not contain unknown fields. With API keys configured, every route except / and /health needs one, in Authorization: Bearer <key> or x-api-key: <key>: read routes take any key, write routes a read-write key. See security.

Server

Method and routeRoleAnswers
GET /public{"name", "version", "docs"}
GET /healthpublic{"status": "ok", "version"}
GET /inforead{"version", "storage", "snapshots_enabled", "collections", "points"}
GET /metricsreadPrometheus text format; see monitoring
curl localhost:6900/health
curl localhost:6900/info
{"status":"ok","version":"0.1.0"}
{"collections":0,"points":0,"snapshots_enabled":true,"storage":"file","version":"0.1.0"}

Collections

Method and routeRoleBodyAnswers
GET /collectionsread{"collections": [CollectionInfo]}
POST /collectionswrite{"name", "dimension", "metric"?, "index"?, "quantization"?, "on_disk"?, "vectors"?, "sparse_vectors"?, "field_indexes"?}201 CollectionInfo
GET /collections/{name}readCollectionInfo
PATCH /collections/{name}write{"index"?, "quantization"?, "on_disk"?, "vectors"?: {name: {"index"?, "quantization"?, "on_disk"?}}, "sparse_vectors"?: {name: {"modifier"}}}CollectionInfo, after rebuilding what changed
POST /collections/{name}/renamewrite{"name"}CollectionInfo under the new name
DELETE /collections/{name}write204; also removes its aliases
POST /collections/{name}/flushwrite204: checkpoint now
POST /collections/{name}/compactwriteCollectionInfo, after reclaiming deleted slots
POST /collections/{name}/indexeswrite{"field"}CollectionInfo; indexing an indexed field does nothing
DELETE /collections/{name}/indexes/{field}writeCollectionInfo, or 404 not_found if the field has no index

A CollectionInfo is {"name", "dimension", "metric", "index", "quantization"?, "on_disk"?, "vectors"?, "sparse_vectors"?, "count", "tombstones", "field_indexes"}, where index is {"type": "hnsw", "m", "ef_construction", "ef_search", "seed"}, {"type": "flat"} or {"type": "kd_tree", "balance_factor"}, and quantization is "scalar" or left out. vectors maps names to {"dimension", "metric", "index", "quantization"?, "on_disk"?}, and sparse_vectors names to {"modifier"?: "idf"}; both, and on_disk, are left out when unset. In PATCH, index is merged into the current settings as a JSON Merge Patch. See collections & points, indexes & metrics and field indexes.

Aliases

Method and routeRoleBodyAnswers
GET /aliasesread{"aliases": [{"alias", "collection"}]}
PUT /aliases/{alias}write{"collection"}{"alias", "collection"}; creates or atomically re-points
DELETE /aliases/{alias}write204, or 404 not_found

An alias works in place of a collection name on every /collections/{name}/… route except DELETE and rename. See aliases.

Points

Method and routeRoleBody or queryAnswers
POST /collections/{name}/pointswrite{"points": [{"id"?, "vector", "vectors"?, "sparse_vectors"?, "metadata"?}]}{"upserted", "ids"}
GET /collections/{name}/pointsread?cursor=&limit=100&with_vectors=false{"points", "next_cursor"}
GET /collections/{name}/points/{id}read?with_vectors=truea point
POST /collections/{name}/points/lookupread{"ids", "with_vectors"?: true}{"points"}: the ids that exist, in request order
POST /collections/{name}/points/scrollread{"cursor"?, "limit"?: 100, "filter"?, "order_by"?: {"field", "direction"?: "asc"}, "with_vectors"?: false}{"points", "next_cursor"}
POST /collections/{name}/points/countread{"filter"?}{"count"}
POST /collections/{name}/points/facetread{"field", "filter"?, "limit"?: 10}{"values": [{"value", "count"}]}
POST /collections/{name}/points/metadatawrite{"ids" or "filter", "metadata", "mode"?: "merge"}{"updated"}
POST /collections/{name}/points/deletewrite{"ids" or "filter"}{"deleted"}
DELETE /collections/{name}/points/{id}write204, or 404 point_not_found

Points whose id is lookup, count, scroll, facet, metadata or delete cannot be read with GET /points/{id}, which those routes shadow; use points/lookup. A point is {"id", "vector", "vectors"?, "sparse_vectors"?, "metadata"}; vectors maps names to dense vectors and sparse_vectors names to {"indices", "values"}. metadata is left out when the point has none, and the vectors when with_vectors is false. Lookups and deletes take at most 10,000 ids, and limit is at most 10,000. See data operations and listing points.

curl -X POST localhost:6900/collections -H 'content-type: application/json' \
  -d '{"name": "places", "dimension": 2, "metric": "euclidean"}' > /dev/null
curl -X POST localhost:6900/collections/places/points -H 'content-type: application/json' \
  -d '{"points": [{"id": "brussels", "vector": [4.35, 50.85]}, {"id": "lille", "vector": [3.06, 50.63]}]}'
curl -X POST localhost:6900/collections/places/points/lookup -H 'content-type: application/json' \
  -d '{"ids": ["lille", "paris", "brussels"], "with_vectors": false}'
{"ids":["brussels","lille"],"upserted":2}
{"points":[{"id":"lille"},{"id":"brussels"}]}
Method and routeRoleBodyAnswers
POST /collections/{name}/searchread{"vector", "id" or "sparse", "using"?, "k"?: 10, "offset"?: 0, "filter"?, "ef"?, "max_distance"?, "with_vectors"?: false, "with_metadata"?: true}{"results": [hit]}
POST /collections/{name}/search/batchread{"searches": [search body]}, at most 256{"results": [[hit]]}
POST /collections/{name}/search/groupsread{"vector", "id" or "sparse", "group_by", "groups"?: 10, "group_size"?: 3, "using"?, "filter"?, "ef"?, "max_distance"?, "with_vectors"?, "with_metadata"?}{"groups": [{"key", "hits": [hit]}]}
POST /collections/{name}/recommendread{"positive", "negative"?, "using"?, "k"?, "offset"?, "filter"?, "ef"?, "max_distance"?, "with_vectors"?, "with_metadata"?}{"results": [hit]}
POST /collections/{name}/discoverread{"target"?, "context"?: [{"positive", "negative"}], "using"?, "k"?, "offset"?, "filter"?, "ef"?, "max_distance"?, "with_vectors"?, "with_metadata"?}; examples are ids or vectors{"results": [hit]}
POST /collections/{name}/queryread{"prefetch": [{"vector" or "sparse", "using"?, "limit"?, "weight"?, "ef"?, "max_distance"?}], "fusion"?: {"type": "rrf", "k": 60} or {"type": "relative_score"} or {"type": "dbsf"}, "rescore"?: {"vector", "using"?}, "k"?, "offset"?, "filter"?, "with_vectors"?, "with_metadata"?}{"results": [scored hit]}

A hit is {"id", "distance", "metadata"?, "vector"?, "vectors"?, "sparse_vectors"?}, closest first; for a sparse search, distance is the negated score. A scored hit has a score instead, highest first. using names a named vector; sparse needs it. See searching.

curl -X POST localhost:6900/collections/places/search -H 'content-type: application/json' \
  -d '{"vector": [5.5, 50.5], "k": 1}'
{"results":[{"distance":1.2020812034606934,"id":"brussels"}]}

Snapshots

Method and routeRoleBody or queryAnswers
POST /collections/{name}/snapshotswrite201 SnapshotInfo
GET /collections/{name}/snapshotsread{"snapshots": [SnapshotInfo]}, oldest first
GET /snapshotsread?collection={"snapshots": [SnapshotInfo]}
GET /snapshots/{id}readSnapshotInfo
GET /snapshots/{id}/downloadreadthe archive, application/gzip
POST /snapshotswritethe raw archive, up to 16 GiB201 SnapshotInfo
POST /snapshots/{id}/restorewrite{"collection"?, "replace"?: false}, or emptyCollectionInfo
DELETE /snapshots/{id}write204

A SnapshotInfo is {"format_version", "id", "collection", "created_at_ms", "quiver_version", "config": {"dimension", "metric", "index", "quantization"?, "on_disk"?, "vectors"?, "sparse_vectors"?}, "points", "data_bytes", "data_sha256", "archive_bytes", "field_indexes"?}. See snapshots & backups.

Errors

Every error has the same shape:

{"error": {"code": "not_found", "message": "collection `nope` not found"}}
StatusCodeMeaning
400invalid_argumenta value is out of range or the request is inconsistent: a bad name or dimension, k out of range, not exactly one of vector/id/sparse or of ids/filter, an unknown using, an empty delete filter, a point that fails validation, a settings change that is not allowed, dropping or renaming by alias, a bad query string
400invalid_bodymalformed JSON, a wrongly typed or unknown field, a missing required field
400invalid_filterthe filter does not parse
400dimension_mismatcha query vector of the wrong length
400invalid_snapshotan uploaded archive that cannot be read or fails its checks
401unauthorizedno API key, or an unknown one
403forbiddena read-only key on a write route
404not_foundno such collection, alias, snapshot or route
404point_not_foundno such point (a get, a single delete, search by id, a recommend example)
409already_existsthe name is taken by a collection or an alias (create, rename, alias, or restore without replace)
413invalid_bodya JSON body over --max-body-mb
413payload_too_largea snapshot upload over 16 GiB
415invalid_bodya JSON route without content-type: application/json
500internalan I/O or storage failure; the server logs it
501unsupportedsnapshots on a server without a snapshot directory

A route that exists but not for that method answers 405 with an empty body.

curl localhost:6900/collections/nope
curl -X POST localhost:6900/collections/places/search -H 'content-type: application/json' -d '{"vector": [1.0]}'
curl -X POST localhost:6900/collections/places/search -H 'content-type: application/json' -d '{"vector": [1.0, 2.0], "top_k": 3}'
{"error":{"code":"not_found","message":"collection `nope` not found"}}
{"error":{"code":"dimension_mismatch","message":"dimension mismatch: expected 2, got 1"}}
{"error":{"code":"invalid_body","message":"Failed to deserialize the JSON body into the target type: top_k: unknown field `top_k`, expected one of `vector`, `id`, `sparse`, `using`, `k`, `filter`, `ef`, `max_distance`, `with_vectors`, `with_metadata` at line 1 column 30"}}

Limits

LimitValue
JSON request body64 MiB, --max-body-mb
Snapshot upload16 GiB
k1–10,000, and k + offset at most 10,000
groups × group_size10,000
Context pairs per discovery64
Values per facet1,000
Searches per batch256
Searches fused per query16
Non-zero values per sparse vector65,536
Named dense vectors, sparse vectors per collection16 each
Ids per lookup or delete, examples per recommend10,000
limit when listing10,000

--cors allows cross-origin requests from any origin; leave it off unless a browser application on another origin needs the API.