Reference
Every call, claim, code, path, variable, limit and time bound, with the page that explains it.
The hosted service
The values the operator publishes for the hosted service:
| Value | |
|---|---|
| Relay URL | Not published yet |
| Manager API address | Not published yet |
| Console address | Not published yet |
| Ingress host | Not published yet |
| SRT port of the Ingress host | Not published yet |
| Egress host | Not published yet |
MoQ versions
Tablebox uses exactly pinned moq-dev releases. The SDK in TypeScript: @moq/net 0.4.2 (with one patched line, applied at install), @moq/json 0.4.2, @moq/publish 0.5.2, @moq/watch 0.6.2 and, in Node, @moq/web-transport 0.1.5. The SDK in Rust: moq-net 0.3.10, moq-tokio 0.19.22 and moq-json 0.5.8. Relay is built on moq-relay 0.17.1 with moq-auth 0.2.1; the programs also use moq-mux 0.10.11, moq-audio 0.1.10, moq-rtmp and moq-srt 0.3.11.
A session speaks MoQ as those releases do: moq-lite, or a draft of IETF moq-transport, in the version the two ends negotiate when the session opens. The pinned releases speak moq-lite-06, which the TypeScript SDK offers first, followed by older moq-lite versions and the IETF drafts moqt-22 down to moqt-15. Three things are kept apart:
| What it is | |
|---|---|
| The IETF draft | moq-transport, the protocol of the IETF MoQ working group, published as numbered drafts |
| The moq-dev profile | moq-lite, the protocol of the moq-dev project |
| The negotiated version | What one session speaks: one version of either, which the client and Relay agree on when the session opens |
SDK
The package tablebox.io (TypeScript, browsers and Node 22) and the crate tablebox (Rust, on a tokio runtime) have the same calls.
| Call | TypeScript | Rust | Page |
|---|---|---|---|
| Connect | connect({ url, token }), { url, getToken } or { url, link, secret }, with serverCertificateHashes |
connect(ConnectOptions::token(url, token)), ConnectOptions::get_token(url, f) or ConnectOptions::link(url, link, secret), with server_certificate_hashes |
Ways to connect |
| State | status, reason, transport: signals with peek() and subscribe() |
status(), reason(), transport(): tokio::sync::watch receivers |
Status |
| Link ID | identity |
identity() |
Links |
| Publish | publish(path): a Broadcast.Producer |
publish(path): a broadcast::Producer |
Publishing |
| Read | read(path): a Broadcast.Consumer once published |
read(path).await: a broadcast::Consumer |
Reading |
| List | list(prefix, { hidden }): an Announce.Consumer |
list(prefix, hidden): an announce::Consumer |
Listing |
| Serve | serve(prefix, handler): { close() }; request.path, accept(broadcast), refuse(name) |
serve(prefix, handler): a Serving; request.path(), accept(&broadcast), refuse(reason) |
Serving |
| Media | origin, for publish and watch (browsers) |
origin() |
Media |
| Close | close() |
close().await, or dropping it |
|
| Codes | Reason: code, name, Reason.of(error) |
Reason: code(), name(), Reason::of(&error) |
Codes |
| Pinned packages | moq (@moq/net), json (@moq/json); in browsers publish and watch |
moq (moq-net), json (moq-json) |
Token claims
| Claim | Type | Meaning |
|---|---|---|
root |
path, default empty | The session's root, relative to the project root |
publish, subscribe |
moq-pattern lists, relative to root |
What the session may publish and read; at least one pattern in all |
sub |
string, required | The participant's ID |
iat |
seconds, required | Issue time, at most 60 s ahead of Relay's clock |
exp |
seconds, required | Expiry, checked at admission |
nbf |
seconds, optional | Not before, checked at admission |
The moq-auth 0.2.1 format: a JWT signed with HS256, HS384 or HS512 by a project key's secret, header kid the key's ID; any other claim is refused. Tokens.
Codes
| Code | Name | From | The SDK |
|---|---|---|---|
| 64 | invalid-token |
Relay | Stops |
| 65 | expired |
Relay | Reconnects with getToken |
| 66 | removed |
Relay | Stops |
| 67 | closed |
Relay | Stops |
| 68 | limit |
Relay | Stops |
| 69 | unavailable |
Relay | Retries |
| 80 | bad-request |
A server of paths | Ends the read or track |
| 81 | missing-variable |
A server of paths | Ends the read or track |
| 82 | failed |
A server of paths | Ends the read or track |
| 83 | too-large |
A server of paths | Ends the read or track |
When each applies: Connecting and Serving.
Program paths
Relative to the reader's root.
| Path | Tracks | Written by | Page |
|---|---|---|---|
{name}/.aggregation/{writer} |
patch.json, value.json |
A writer | Aggregation |
.aggregation/{name} |
state.json, writers.json, applied/{writer} |
Aggregation | Aggregation |
.persistence/{path} |
{track}, the saved document of {path}'s {track} |
Persistence | Persistence |
.egress/{source}/{dest}, .egress/{prefix}/.composite/{dest} |
status.json |
Egress | Egress |
{source} |
hang audio, context.json, input.json |
The Agent's caller | Agent |
.agent/{source} |
hang voice, transcript.json, calls.json, status.json |
Agent | Agent |
The stream key's publish path |
a hang broadcast | Ingress | Ingress |
Project variables
| Variable | Read by | Meaning |
|---|---|---|
STORAGE_BUCKET, STORAGE_ACCESS_KEY_ID, STORAGE_SECRET_ACCESS_KEY |
Persistence, Egress (and Aggregation through Persistence) | The bucket and its credentials, required |
STORAGE_ENDPOINT, STORAGE_REGION, STORAGE_PREFIX |
the same | An https:// endpoint (AWS S3 when unset), the region (us-east-1), a key prefix (empty) |
EXPORT_{NAME}_URL |
Egress | An rtmp://, rtmps:// or srt:// destination named {name} |
AGENT_PROVIDER |
Agent | openai (default) or gemini |
OPENAI_API_KEY, GEMINI_API_KEY |
Agent | The chosen provider's key |
AGENT_MODEL, AGENT_VOICE |
Agent | The model (gpt-realtime-2.1 or gemini-3.8-live when unset) and the voice |
AGENT_INSTRUCTIONS, AGENT_TOOLS |
Agent | The instructions, and a JSON array of tools |
Management API
| Call | Credential |
|---|---|
GET, POST /v1/projects |
Console session |
GET, PATCH, DELETE /v1/projects/{p} |
Console session or the project's key |
/v1/projects/{p}/keys, /links, /variables, /removals, /closings, /usage |
Console session or the project's key |
Bodies, results and errors: The management API.
Limits and time bounds
| Value | What | Page |
|---|---|---|
| 32 segments | A path | Paths |
| 60 s | How far iat may be ahead of Relay's clock |
Tokens |
| 32 to 128 characters | A link's secret; the joiner's ID is 22 | Links |
| 500 ms | A browser's WebTransport attempt before the WebSocket fallback joins | Transports |
| 1 s, doubling to 30 s | The SDK's reconnect delays, back to 1 s after a session of 5 s | Status |
| 2 s | A session waits this long for a Relay that has not read the project's state, then unavailable |
Codes |
| 10 s | A silent connection ends | Status |
| 5 s | Removals and closings take effect; changes reach Relays and programs | Removals |
| 10 s | Relays report usage; limits may be passed by what they carry in it | Limits |
| 1 minute | Usage becomes visible | Limits |
| 70 characters, 16 KiB, 100 | A variable's name, a variable's value, the variables of a project | Variables |
| 20 s | A program stops after its last reader leaves | Calling |
| 16 MiB | Aggregation's merged document | Aggregation |
| 2 s, 10 s | Persistence saves 2 s after a change, and at least every 10 s | Persistence |
| 5 s; 30 s | Egress waits this long for a second rendition; its retry delays grow to 30 s | Egress |
| 1280x720, 30 fps; 48 kHz stereo | A composite's video and audio | Egress |
| 10 s; 64 KiB | The Agent's wait for a tool's answer; its context | Agent |
| 496 bytes | A stream key for SRT | Ingress |
| 1 s | Ingress waits this long before it accepts a stream | Ingress |