Docs · Reference
Read the relay field by field.
Every request the clients make, with the exact shapes the server reads — and, field by field, what it can never read.
Point at the base URL
Authorization: Bearer <jwt> # on every authenticated request
This reference documents the surface the clients speak, mirrored from the server's own request structures. A field that is not listed is not read — the server rejects unknown fields on credential payloads rather than silently accepting them.
Authenticate
An account is a derived Profile ID and an account secret. Those two fields, plus the connecting address the relay sees to answer at all, are the identity surface — there is no name, no number, and no address book.
POST /auth/register — request and response
{
"serpent_id": "string — 3–64 chars: letters, digits, - and _",
"password": "string — 8–128 chars"
}
// 200 —
{
"token": "<jwt>",
"user_id": "<uuid — internal routing id>",
"profile_id": "PROFILE-XXXXXXXX-XXXXXXXX"
}
The relay stores the sign-in secret as an Argon2id hash (relay m=64 MiB, t=3, p=4 — RFC 9106, with a rolling rehash on sign-in). The Profile ID is derived on your device; the server stores it verbatim and routes by it.
Publish and fetch keys
Everything under /keys is public material. The relay is a
bulletin board for public keys; private keys never appear in any
payload on this page.
Why you can trust a fetched bundle
Bundles are signed (the signed-prekey binding closes the classic substitution attack), identity keys are appended to the KTS transparency log, and the safety-number ritual in Key verification lets two humans confirm the relay served the same keys to both sides.
Open a session
A session opens with one round trip: init carries the
hybrid handshake, respond completes it. The server
validates structure and bindings; the secrets are born on the two
devices.
POST /sessions/init — request shape
{
"responder_id": "<uuid>",
"handshake_init": "<base64 — serialized hybrid HandshakeInit>",
"bell_transcript": "<base64 — canonical Q-Entangle-Bell v1 bytes>",
"bell_transcript_hash": "<base64 — SHA3-256 of the canonical bytes>",
"bell_op_sig": "<base64 — operator signature over the transcript; optional>"
}
The Bell fields are optional. When present, the server recomputes SHA3-256 over the transcript bytes and re-checks the CHSH window; a mismatch is counted and, once enforcement is armed on the deployment, refused with X-Qeryx-Bell-Missing: 1. The messenger bootstraps its sessions through the pre-key bundle path, not this endpoint.
This is not QKD. Not quantum networking. Not quantum teleportation. We do not violate the no-communication theorem. Above an X25519 + ML-KEM-1024 floor that alone provides confidentiality, a session can fold a Tsirelson-bounded CHSH witness transcript into its key derivation — a deterministic classical co-possession witness, not physical entanglement; security never depends on it.
Send a message
The envelope the relay carries is ciphertext plus routing. Group names and descriptions and all content are end-to-end encrypted; the group avatar, the admin and owner identifiers, and the roster of accounts each conversation delivers to are held by the relay for routing. Sender identifiers are stripped from the stored message row (sealed sender), though the relay authenticates the sender at send time and keeps a per-direction pair counter for up to 180 days. Sealed sender covers text-class messages and small payloads: an image, and any voice or video frame over the envelope budget, is delivered on a lane that does name the sender to the relay for as long as the row lives. Undelivered messages queue with routing metadata under a published retention ladder.
POST /messages — request shape
{
"recipient_id": "PROFILE-… or <uuid>",
"encrypted_content": "<base64 — ciphertext; opaque to the relay>",
"nonce": "<base64>",
"message_type": "text | image | video | file | location | voice",
"reply_to_id": "<uuid, optional>",
"conversation_id": "<string, optional — group routing>",
"idempotency_key": "<string, optional — client-side dedup>"
}
encrypted_content and nonce are opaque
bytes to the relay. message_type is a routing hint for
notifications; the content behind it is indistinguishable
ciphertext.
Audit the transparency log
The endpoints an auditor uses. Inclusion proofs, auditor keys, signed audit receipts, and the build attestation are readable without any special access — verification is a public capability, not a support ticket.
What the log guarantees
KTS is an append-only key log anchored by a 2-of-3 multi-witness quorum that starts dormant — all three ML-DSA-87 slots and all three external Ed25519 auditor slots hold placeholder keys, so no cosignature is carried and no witness check runs yet. Every root, until the witnesses enroll, is signed by one operator ML-DSA-87 key, which your device verifies against a SHA-384 anchor compiled into the app and cross-checks peer-to-peer through gossiped log roots. Enrolling a witness takes a new app release, by design.
Hold the socket open
GET /ws
Authorization: Bearer <jwt>
# ?token=<jwt> is accepted as a fallback and deprecated —
# tokens in URLs end up in logs.
One socket carries typed frames, dispatched on
msg_type: delivery (delivered,
delivery_ack, read), call signaling
(call_ready, call_accept,
call_reject, call_end and their video
variants), group media control, and transparency gossip. Message
payloads inside frames are the same opaque ciphertext as the REST
surface.
08The developer questions — answered against the server
Push on the reference.
Is there a third-party app program or API keys?
No. This reference exists so you can verify what the clients send — and what the relay can read — not to onboard bots. There are no bots and no server-side AI in the messenger core, by design. The Qaduceus assistant is a separate opt-in surface with its own documented path.
Why document an API nobody can register apps for?
Because the API surface is the privacy claim. Anyone can read these shapes and, once QERYX arrives, capture their own traffic and confirm the two match. A privacy policy asks for trust; a field list can be checked.
Where are rate limits documented?
The relay enforces per-route rate limits (auth endpoints are the strictest). Exact thresholds are operational tuning and move with load; the error you get is HTTP 429 with a retry hint.