Skip to main content
DB
ProductProtocol and drivers

Plain SQL over HTTP and one WebSocket

A node’s client listener speaks two transports. HTTP carries sign-in, one-shot statements and bulk writes, with JSON in and out. One WebSocket session multiplexes everything else, including queries that stay open, with every request told apart by its id. A TypeScript client covers both, in the browser and in Node.

Authentication

A secret becomes a bearer, then a session

Every request runs under a session, and a session is opened from a bearer. A password or an API key does not replace the bearer: each is an issuer that checks a secret and issues a short-lived bearer for its principal.

01

Ask which issuers the node offers

The issuers route lists the credential issuers this node offers. It doubles as the readiness probe, answering 200 while the node serves and 503 while it drains.

GET /auth/issuers

the issuers this node offers
GET /auth/issuers
# → the issuers the node offers: password, api_key
02

Exchange the secret for a bearer

Send a user name and password, or an API key, and receive a short-lived Ed25519 bearer for the principal. Passwords are stored as Argon2id verifiers, and an API key’s secret is returned once, when the key is created.

POST /auth/password · POST /auth/api-key

two issuers, one kind of bearer
POST /auth/password
# a user name and a password
POST /auth/api-key
# an API key
# → a short-lived Ed25519 bearer for the principal
03

Exchange the bearer for a session

Send the bearer in the Authorization header with an empty JSON object as the body. The answer carries the session token, the principal and tenant ids, when it expires and whether it is renewable. The session token goes on every later request; on a WebSocket it travels only in the first frame.

POST /auth/session

from bearer to session
POST /auth/session
Authorization: Bearer <bearer>
Content-Type: application/json
{}
# → session_token, principal_id, tenant_id, expires_at, renewable
# then, on every later request
Authorization: Bearer <session_token>

HTTP

One statement in, the whole result out

Send one statement and the most rows the answer may carry, and the gateway collects the whole result and answers once. A read comes back as a result document with the column definitions, the rows and a receipt; a definition or a write answers with a command receipt.

Bulk rows take their own routes: a bounded batch of rows to one table, native columnar bulk-load frames, or logical insert blocks.

sql
one statement
maximum_rows
required: the most rows the answer may carry
parameters
values for ? placeholders, each with a kind and a text
POST /write/batch · POST /bulk-load/frame · POST /insert/logical-block
bulk rows, three ways
one statement, the whole result
POST /sql
Authorization: Bearer <session_token>
Content-Type: application/json
{
"sql": "SELECT address, token, amount FROM balances WHERE chain_id = 1 LIMIT 10",
"maximum_rows": 10
}
# → a nyxdb.query-result/2 document: the columns, the rows, a receipt

WebSocket

One connection, many requests, each with its own id

Upgrade once, then run finite reads and streaming queries side by side. The client chooses a request id and the server echoes it on every frame, so a slow or streaming request never blocks an unrelated read on the same connection.

Opening01 / 04
route, subprotocol, first frame
GET /client
# an HTTP/1.1 upgrade; wss:// for any host other than loopback
subprotocol: nyxdb.public.v1
OpenSession
# carries the session token, first frame only
SessionOpened

@nyxdb/client

Both transports, in the browser and in Node

The TypeScript client covers the whole public protocol, so your application code sees sessions, statements, write batches and live queries, not routes and frames.

  • nyxdb.query-result/201

    Every value arrives lossless

    The client decodes the HTTP result document and the WebSocket exact result batches and keeps every value intact: integers as bigint, decimals with their precision and scale, binary values as bytes.

    integers → bigint · decimals → precision and scale kept · binary → Uint8Array

  • Sessions and writes02

    Sign in, open sessions, send rows

    It exchanges a bearer for a session, logs in with a password or an API key when the node has an issuer, and sends bounded write batches and resumable bulk-load frames. A secret goes only over https, or over http to a loopback host, and a redirect is never followed.

    https only · loopback http · no redirects

  • One socket03

    Cancellable queries, side by side

    It multiplexes independently cancellable queries over one WebSocket session, replenishes demand as your code consumes results, reports progress, and decodes system relations, including the federation relations.

    multiplex · demand · progress · cancel

Reference

Every route and frame, in one place

The names below are the ones the gateway uses. Session settings, federation statements and system relations run on the WebSocket session, where their effect lasts for the session.

The HTTP routes of a node and what each one does.
GET /auth/issuersLists the credential issuers this node offers. An empty list means bearer login only.
POST /auth/passwordExchanges a user name and password for a short-lived bearer.
POST /auth/api-keyExchanges an API key for a short-lived bearer.
POST /auth/sessionExchanges a bearer for a session. The body is an empty JSON object.
GET /auth/sessionReports the session named by the Authorization header.
DELETE /auth/sessionCloses the session. Later requests with its token answer 401.
POST /auth/session/refreshRenews a renewable session.
POST /sqlRuns one statement and returns its whole result.
POST /write/batchWrites a bounded batch of rows to one table.
POST /bulk-load/frameSends one native columnar bulk-load frame.
POST /insert/logical-blockSends one logical insert block.

Every frame carries its request id. JSON routes take application/json; every other HTTP target answers 404.

Protocol reference

Questions about the protocol

What a technical buyer asks about transports, sessions and flow control, answered from the docs.

No. One-shot statements over tables and views run over HTTP, where the gateway collects the whole result and answers once. Use the WebSocket session for results that should arrive page by page, for streaming queries, and for session settings, federation statements and system relations.

Two transports, one SQL, every value intact

Open a session, send a statement over HTTP and follow a live query over the socket. The drivers docs name every route and frame.