Reference
Last updated 2 November 2026
Every interface Tonbo serves, one module at a time: the HTTP APIs, the SDKs that call them and the CLIs. This page says where each module answers, which credential it takes and the conventions they share. Each module’s own pages list its operations, every parameter and every error.
Modules
| Module | Where it answers | Credential | What it does |
|---|---|---|---|
| Management API | https://api.tonbo.dev/v1 | A personal key, or a token for https://api.tonbo.dev | Creates, lists, changes and deletes the account’s databases, streams and keys, and reads the account and its usage. |
| Token exchange | POST https://tonbo.dev/api/iam/token | Any key, or a Streams token to narrow | Exchanges a key for a token that expires within 10 minutes, and narrows a token for one client such as a web page. |
| Streams HTTP | A stream’s or a database’s url, on its region’s Streams origin | A personal key, or a token for https://streams.tonbo.dev | Appends to a stream and reads it: catch-up reads, long-polls, Server-Sent Events and snapshots. |
| Node.js SDK | @tonbo/sdk 1.0.0 with @tonbo/sqlite-ursula 0.11.3, in your process | The apiKey option, else TONBO_API_KEY, else the login tonbo login saved | Opens a database by name as a node:sqlite connection, and Pi Durable’s storage on one. |
| Python SDK | sqlite-ursula 0.11.3.dev0, in your process | The api_key option, else TONBO_API_KEY, else the login tonbo login saved | Opens a database by name as a sqlite3 connection, with asyncio and LangGraph. |
tonbo CLI | Your terminal; it calls the Management API | tonbo login, or a key in TONBO_API_KEY, which overrides it | One command for each operation of the Management API, with --json for scripts. |
yield CLI | Your terminal | yield login | Captures your coding agents’ sessions and answers why a file is the way it is. |
Origins
Two origins are fixed: the Management API’s, https://api.tonbo.dev/v1, and the token exchange’s, https://tonbo.dev. A stream or a database lives on its region’s Streams origin, and the Management API returns its full URL as url; take the URL from there rather than building it (see Regions and URLs).
The SDKs read TONBO_API_ORIGIN for another Management API origin and TONBO_AUTH_ORIGIN for another token exchange origin. Each must be https, or http only to localhost, since requests to it carry the key.
Credentials
| Credential | What it is | Accepted by |
|---|---|---|
A personal key, tbo_… | Acts as you, with your current role in the account and the key’s narrowing, read again on every request. | The Management API, a stream’s URL and the token exchange, directly. |
| An Agent’s key | Acts as an Agent of the account. | The token exchange only. Sent anywhere else, it answers 401 exchange_required, whose token_endpoint names the exchange. |
| An access token | A token exchanged from a key, for one audience: https://api.tonbo.dev or https://streams.tonbo.dev. It reaches what its key reaches and expires within 10 minutes. | The API its audience names. |
| A token for a web page | A Streams token narrowed to the streams and databases it names, read-only unless it asks otherwise, and shorter-lived. | The URLs of the streams and databases it names. |
Every credential is sent as Authorization: Bearer. API keys and tokens explains how to create a key, narrow it and exchange it.
Errors
- The Management API refuses with
application/problem+json: a Problem withtype,title,status,codeandrequest_id, and adetailwhen one exists. Match the status and thecode, never the title or the detail, and quote therequest_idwhen you ask for help (see Errors). - The token exchange refuses with JSON
{"error": …}and, for some refusals, acodebeside it. Match the status and the code, never the message. - A stream’s URL answers as the durable streams protocol does: a status, sometimes with a code such as
PAYMENT_REQUIRED, and its headers. Troubleshooting lists each refusal, when it happens and whether to send the request again. - The SDKs throw errors with a
kindto match (see Node.js errors). ThetonboCLI prints the refusal and exits with status 1.
Retries and idempotency
The Management API’s creations below require an Idempotency-Key header of 1 to 255 characters. Send the same key again and the API answers what the first request created; send it with a different request and it answers 409. Make one key for each creation you intend, and reuse it on every retry of that creation:
POST /agentsCreate an Agent, an identity with a role in the accountPOST /databasesCreate a databasePOST /streamsCreate a stream
Creating an API key takes no such header: its secret is shown only once, so a retry of the same name answers 409 rather than creating a second key. When a 429 or a 503 carries Retry-After, wait that many seconds and send the same request again. An append to a stream is made safe to retry by its producer headers, which make a retried append land once (see Rules: writers).
Conditional updates
A read of a resource answers its version as ETag. An update may send it back in If-Match, of at most 500 characters, to change only that version: a stale one answers 412 precondition_failed, and without the header the last write wins. An operation that needs the header says so, and answers 428 precondition_required without it.
Pagination
A list answers data and next_cursor. It takes limit, from 1 to 200 items, by default 50, and cursor, the next_cursor of the page before. A cursor is opaque and tied to the query it came from, so send it with the same other parameters. next_cursor is null on the last page. The CLI prints one page and names on stderr the --cursor to run it again with.
Rate limits
- The Management API answers
429withRetry-Afterpast its rate limit. - The token exchange counts 600 tokens a minute for each key and 3000 requests a minute from each address, and answers
429rate_limitedpast either (see the exchange’s limits). - Streams and databases take at least 50 requests a second and 16 open tails for each account in each region (see Limits).
Versions and compatibility
The Management API’s version is in its path, /v1.
Responses may gain fields; clients ignore fields they do not know. Request bodies stay closed: an unknown field is refused. A breaking change to an enforced operation ships as a new version, or with a compatibility window that names its consumer and removal condition.
A stream’s URL serves the durable streams protocol of Ursula 0.11.3. Pin each SDK at the exact release its reference names: a later release can change its options, its cache format and the server releases it works with.