Canonical contract for VelesQL server endpoints and payloads.
- Contract version:
3.8.0 - Last updated:
2026-07-06
This document is the normative REST contract baseline for VelesQL. When behavior differs between docs and runtime, runtime must be fixed or this document must be updated in the same PR.
Unified endpoint for SELECT and top-level MATCH queries.
Request body:
{
"query": "SELECT * FROM docs WHERE vector NEAR $v LIMIT 10",
"params": { "v": [0.1, 0.2, 0.3] },
"collection": "docs"
}Aggregation queries are accepted on /query for backward compatibility, but
/aggregate is the explicit endpoint for aggregation workloads.
Aggregation-only endpoint for GROUP BY/HAVING/aggregate queries.
Request body:
{
"query": "SELECT category, COUNT(*) FROM docs GROUP BY category",
"params": {},
"collection": "docs"
}Rules:
- Query must be aggregation-shaped (
GROUP BYor aggregate functions inSELECT). - Non-aggregation queries return
422withVELESQL_AGGREGATION_ERROR. - Collection is resolved from
FROM <collection>first, then optional bodycollection.
Success response shape:
{
"result": [{ "category": "tech", "count": 42 }],
"timing_ms": 1.12,
"meta": {
"velesql_contract_version": "3.3.0",
"count": 1
}
}Rules:
collectionis optional forSELECT ... FROM <collection> ....collectionis mandatory for top-levelMATCH (...) ...sent to/query.- For graph-only execution,
/collections/{name}/matchremains supported. SELECT ... WHERE ... AND MATCH (...)is supported and does not requirecollectionin body whenFROM <collection>is present.- The MATCH anchor (first node of the pattern) must carry an alias; when the
FROM/JOINclauses declare aliases, the anchor alias either is one of them (explicit binding) or — when no pattern alias matches a declared alias — binds implicitly to the FROM rows, guarded by G1/G2/G3 (see the spec's "Anchor rule (V011)"). Violations fail validation with error codeV011. WhenFROMhas no alias, any anchor alias is accepted. - Execution note: graph predicates that are AND-required by the WHERE clause
take the GraphFirst anchored fetch — the pattern is evaluated first and
retrieval is exhaustive within its anchor set (NEAR, metadata-only,
sparse-only and
NOT similarity()shapes). Residual shapes (predicates underOR/NOT,similarity()cascades, BM25 text-MATCHfusion, hybrid dense+sparse fusion) keep the windowed execution: a ranked fetch filters an over-fetched window ofmax(LIMIT, min(LIMIT × 10, 10 000))candidates (rows ranked beyond it are not returned); unranked shapes scan up to 100 000 points in storage order.
Success response shape:
{
"results": [{ "id": 1, "score": 0.98, "payload": { "title": "Doc" } }],
"timing_ms": 1.42,
"took_ms": 1,
"rows_returned": 1,
"meta": {
"velesql_contract_version": "3.3.0",
"count": 1
}
}DDL statements (CREATE COLLECTION, DROP COLLECTION, CREATE INDEX, DROP INDEX,
ANALYZE, TRUNCATE, ALTER COLLECTION) and graph/delete mutation statements
(INSERT EDGE, DELETE EDGE, DELETE FROM, INSERT NODE, SELECT EDGES) are
submitted through the same POST /query endpoint.
Request body (DDL example):
{
"query": "CREATE COLLECTION documents (dimension = 768, metric = 'cosine') WITH (storage = 'sq8')",
"params": {},
"collection": ""
}Request body (graph mutation example — collection is optional, extracted from SQL):
{
"query": "INSERT EDGE INTO knowledge (source = 1, target = 2, label = 'AUTHORED_BY') WITH PROPERTIES (year = 2026)",
"params": {}
}DDL success response shape (standard QueryResponse with zero rows):
{
"results": [],
"timing_ms": 2.31,
"took_ms": 2,
"rows_returned": 0,
"meta": {
"velesql_contract_version": "3.3.0",
"count": 0
}
}DDL error response shape uses the standard VelesQL error model (see below).
Rules:
- DDL and graph/delete mutation statements always route to
/query, never to/aggregate. - DDL statements (
CREATE COLLECTION,DROP COLLECTION,CREATE INDEX,DROP INDEX,ANALYZE,TRUNCATE,ALTER COLLECTION) do not require acollectionfield in the body (the collection name is embedded in the SQL statement). DROP COLLECTION IF EXISTSreturns success even if the collection does not exist.- Graph/delete mutation statements (
INSERT EDGE,DELETE EDGE,DELETE FROM,INSERT NODE,SELECT EDGES) extract the collection name from the SQL statement; thecollectionfield in the request body is ignored. INSERT INTOandUPDATEstatements flow through the standard query path and return result rows in theresultsarray.
Collection-scoped endpoint for graph MATCH queries.
Success response shape:
{
"results": [
{
"bindings": { "a": 1, "b": 2 },
"score": 0.91,
"depth": 1,
"projected": { "a.name": "Alice" }
}
],
"took_ms": 4,
"count": 1,
"meta": {
"velesql_contract_version": "3.3.0"
}
}Semantic/runtime errors for VelesQL endpoints use:
{
"error": {
"code": "VELESQL_MISSING_COLLECTION",
"message": "MATCH query via /query requires `collection` in request body",
"hint": "Add `collection` to the /query JSON body or use /collections/{name}/match",
"details": {
"field": "collection",
"endpoint": "/query",
"query_type": "MATCH"
}
}
}Current codes:
VELESQL_MISSING_COLLECTIONVELESQL_COLLECTION_NOT_FOUNDVELESQL_EXECUTION_ERRORVELESQL_AGGREGATION_ERRORVELESQL_VALIDATION_ERRORVELESQL_MUTATION_ERRORVELESQL_EXPLAIN_ANALYZE_ERROR
/collections/{name}/match no longer emits the bespoke *_ERROR
strings (COLLECTION_NOT_FOUND / PARSE_ERROR / EXECUTION_ERROR / …).
It now returns the canonical { "error", "code" } body with a
VELES-XXX code (e.g. VELES-002 for a missing collection, VELES-010
for a parse error or unbound parameter, VELES-019 for a duplicate
edge), and the HTTP status is derived from the error variant. Guard-rail
rejections (rate limit 429, circuit breaker 503) and query timeouts
(408) carry the VELES-027 code.
Syntax errors still use parser-specific payload (QueryErrorResponse with type/message/position/query).
These limits are part of the runtime contract and apply to every VelesQL query:
| Limit | Value | Behavior on breach |
|---|---|---|
| Query length | configurable max_query_length |
Rejected before parsing (pre-scan), parse error. |
Bracket / NOT nesting depth |
64 | Rejected before parsing (pre-scan), parse error. Prevents a parser stack-overflow DoS. |
| GROUP BY groups | server ceiling 1,000,000 (default 10,000) | WITH (max_groups = N) may lower the budget but N is clamped down to the ceiling; exceeding the effective budget returns an aggregation error. |
NOT similarity() scan |
5,000,000 vectors | Rejected with guidance (no index acceleration for NOT similarity()). |
Both pre-scan rejections are evaluated before pest is invoked, so they fire
regardless of how the query nests.
These syntax profiles are frozen for this contract version:
- Top-level query:
SELECT ...orMATCH (...) ... - Hybrid WHERE predicate:
SELECT ... FROM <collection> WHERE ... AND MATCH (...) - Text predicate:
<field> MATCH 'text'
Reference grammar:
docs/VELESQL_SPEC.md(canonical, v3.6)
| Capability | Contract state | Runtime state |
|---|---|---|
SELECT ... FROM ... WHERE ... |
Stable | Stable |
SELECT ... WHERE ... AND MATCH (...) |
Stable | Stable |
top-level MATCH (...) RETURN ... |
Stable | Stable |
top-level MATCH via /query with body collection |
Stable | Stable |
aggregation via /aggregate |
Stable | Stable |
JOIN ... ON |
Stable | Stable |
JOIN ... USING (...) |
Stable | Stable for single-column USING |
LEFT/RIGHT/FULL JOIN |
Stable | Stable |
GROUP BY / HAVING |
Stable | Stable |
UNION/INTERSECT/EXCEPT |
Stable | Stable |
CREATE COLLECTION |
Stable | Stable |
DROP COLLECTION [IF EXISTS] |
Stable | Stable |
CREATE INDEX ON |
Stable | Stable |
DROP INDEX ON |
Stable | Stable |
ANALYZE |
Stable | Stable |
TRUNCATE |
Stable | Stable |
ALTER COLLECTION ... SET |
Stable | Stable |
INSERT INTO |
Stable | Stable |
UPSERT INTO |
Stable | Stable |
UPDATE ... SET |
Stable | Stable |
INSERT EDGE INTO |
Stable | Stable |
DELETE FROM |
Stable | Stable |
DELETE EDGE ... FROM |
Stable | Stable |
SELECT EDGES FROM |
Stable | Stable |
INSERT NODE INTO |
Stable | Stable |
SHOW COLLECTIONS |
Stable | Stable |
DESCRIBE COLLECTION |
Stable | Stable |
EXPLAIN |
Stable | Stable |
FLUSH |
Stable | Stable |
Contract test cases are listed in:
conformance/velesql_parser_cases.json(parser conformance, v3.6)conformance/velesql_contract_cases.json(runtime contract)conformance/velesql_executor_cases.json(executor result rows/counts/ordering, goldens derived fromvelesdb-core)
Each invalid case maps to an expected HTTP status and an expected error shape.
| Feature | Parser | Executor |
|---|---|---|
JOIN ... ON |
Supported | Supported (inner join) |
JOIN ... USING (...) |
Supported | Supported for single-column USING |
LEFT/RIGHT/FULL JOIN |
Supported | Supported |
GROUP BY, HAVING |
Supported | Supported |
ORDER BY similarity() |
Supported | Supported |
UNION/INTERSECT/EXCEPT |
Supported | Supported |
CREATE COLLECTION |
Supported | Supported |
DROP COLLECTION [IF EXISTS] |
Supported | Supported |
CREATE INDEX ON |
Supported | Supported |
DROP INDEX ON |
Supported | Supported |
ANALYZE |
Supported | Supported |
TRUNCATE |
Supported | Supported |
ALTER COLLECTION ... SET |
Supported | Supported |
INSERT INTO |
Supported | Supported |
UPSERT INTO |
Supported | Supported |
UPDATE ... SET |
Supported | Supported |
INSERT EDGE INTO |
Supported | Supported |
DELETE FROM |
Supported | Supported |
DELETE EDGE ... FROM |
Supported | Supported |
SELECT EDGES FROM |
Supported | Supported |
INSERT NODE INTO |
Supported | Supported |
SHOW COLLECTIONS |
Supported | Supported |
DESCRIBE COLLECTION |
Supported | Supported |
EXPLAIN |
Supported | Supported |
FLUSH |
Supported | Supported |
- Existing clients reading
timing_ms+rows_returnedcontinue to work. - New clients should prefer
meta.velesql_contract_versionfor contract-aware handling.