API reference · v1 (frozen)

The complete /v1 surface.

Base URL http://localhost:4382 (self-host) or your cloud endpoint. Every request: Authorization: Bearer <token>. Errors return { error: { code, message, details?, retry_after_ms? } }; 429/503 and idempotent 500 are safely retryable.

Docs · L1 (append & subscribe)
POST/v1/tables/{table}/docs

Append one JSON doc or an array (≤1000 & ≤8MB). Auto-creates the table. Send Idempotency-Key for free exactly-once. 200 ⇒ fsync'd to WAL; offsets strictly monotonic & immediately readable.

MALFORMED_JSONRESERVED_FIELDPAYLOAD_TOO_LARGERATE_LIMITEDQUOTA_EXCEEDEDBACKPRESSURE
GET/v1/tables/{table}/docs?from_offset&max_count&max_wait_ms

Pull by offset, transparently across hot memtable and cold S3 Parquet. max_wait_ms>0 long-polls until new data or timeout.

TABLE_NOT_FOUNDOFFSET_OUT_OF_RANGEINVALID_ARGUMENT
GET/v1/tables/{table}/tail?from_offset=<u64|latest>

Real-time subscribe (SSE). id:<offset> + data:<doc>; 15s heartbeat; reconnect via Last-Event-ID. WebSocket variant on the same path.

TABLE_NOT_FOUNDOFFSET_OUT_OF_RANGERATE_LIMITED
KV · L2 (linearizable single key)
GET/v1/kv/{bucket}/{key}

Read value + version + expires_at. Expired keys read as absent (lazy expiry).

KEY_NOT_FOUND
PUT/v1/kv/{bucket}/{key}?ttl_seconds

Write / CAS (If-Match) / create-only (If-None-Match: *). No condition = last-write-wins. ttl_seconds sets TTL; omit to clear it.

CAS_CONFLICTALREADY_EXISTSPAYLOAD_TOO_LARGEKEY_NOT_FOUNDQUOTA_EXCEEDED
DELETE/v1/kv/{bucket}/{key}

Delete (optional If-Match). Version sequence is not reused (G-NO-ABA).

KEY_NOT_FOUNDCAS_CONFLICT
POST/v1/kv/{bucket}/{key}/increment

Atomic increment by i64 delta. No lost updates under concurrency. Never blindly retried by SDKs.

INVALID_ARGUMENT
GET/v1/kv/{bucket}?prefix&cursor&limit

Prefix list in key order (snapshot-consistent). Expired entries omitted.

POST/v1/kv/{bucket}/{key}/expire

Set / reset / clear TTL on a live key (ttl_seconds number or null). Bumps version.

KEY_NOT_FOUNDINVALID_ARGUMENT
Query · SQL over your tables
POST/v1/query

Single-statement SELECT. Positional params $1..$n. JSON paths data['a']['b'], full-text contains/token_match/regexp_like, vector_distance kNN. Snapshot-consistent (includes committed mutations). JSON or Arrow output.

INVALID_SQLUNSUPPORTED_SQLUNSUPPORTED_TRANSACTIONSCAN_LIMIT_EXCEEDEDRATE_LIMITEDTABLE_NOT_FOUND
Mutations · L3 (batch UPDATE/DELETE)
POST/v1/tables/{table}/mutations

Submit batch update/delete (op, where, params, set, dry_run). 202 async; commit = manifest version bump, atomically visible. 10/min per table, serial FIFO.

INVALID_SQLINVALID_ARGUMENTTABLE_NOT_FOUND
GET/v1/mutations/{mutation_id}

Poll mutation state (pending|running|applied|failed) + affected_rows + committed_manifest_version.

MUTATION_NOT_FOUND
Tables · management
PUT/v1/tables/{table}

Create / configure (ttl_days, description). Idempotent.

INVALID_ARGUMENT
GET/v1/tables

List tables with name, doc_count, bytes, max_offset, ttl_days.

GET/v1/tables/{table}

Single table detail + current inferred schema.

TABLE_NOT_FOUND
DELETE/v1/tables/{table}

Async whole-table delete (irreversible). Requires header X-Confirm-Delete: {table}.

INVALID_ARGUMENT
System
GET/v1/usage

Current usage + tier limits (ingest/scan/storage/kv).

GET/healthz

Liveness probe (no auth). Returns 200 "ok".

Start here