Concepts
Last updated 29 October 2026
Read this before you build: it names the parts of a stream that every other page refers to, then lists every operation and the page that documents it.
A stream is an append-only log at an HTTPS URL. The difference from a table you insert into is that nothing appended changes, and an append retried by a producer applies once; the difference from a queue is that reading takes nothing away, since each reader keeps its own offset.
How it differs from a table or a queue you know
- Against a table: no update and no delete of a message. Every reader sees one order, the order the stream took the appends in, at offsets that never change.
- Against an insert you retry by hand: an append with a producer id, an epoch and a sequence number applies once, however often it is sent.
- Against a message queue: no consumer groups, acknowledgements or leases. A reader reads a message as often as it reads its offset.
- Against a database: no local copy and no package. Every append and read is an HTTPS request, from any language.
A stream
An ordered sequence of messages, or of bytes, that Tonbo keeps in one region, at its own HTTPS URL. You create it with a name, a region and a content type, and it only grows: nothing appended to it changes (see Create a stream).
A message
On a stream of application/json, each append is one JSON message, or one per element of a JSON array, and reads return one message per line. On any other content type, application/octet-stream when none is named, a stream holds bytes as they were appended (see Content types).
An offset
A position in the stream. Every append ends at one, and a read starts at one and says where to read next, so a reader that stops resumes from the last offset it saw, on this machine or another. Offsets are opaque strings that sort in stream order: keep them as the stream returns them (see Read).
A producer
A writer that names itself in each append with an id, an epoch and a sequence number, so a retry applies once: the same append sent again answers with the first one’s offsets and appends nothing (see Append). Any number of producers write one stream, in one order that every reader sees.
A tail
A read at the end of the stream that waits for the next append: a long-poll answers once something arrives, and a Server-Sent Events read stays open and pushes each append (see Tail). Tonbo keeps no state for readers: each reader keeps its own offset.
Closing
A stream closed by its writer refuses appends for good and stays readable, and every reader at the end learns that it is over (see Close).
A snapshot and retention
A snapshot is a summary of the stream up to an offset, such as a count or a state, that a writer publishes so a new reader starts from it instead of from the beginning, and bootstrap is one request that answers the latest snapshot and every message after it. Retention is where the stream’s readable history starts: advancing it to a snapshot stops keeping, and paying for, the history before it (see Snapshots and retention).
An expiry
A time, set when the stream is created, after which Tonbo deletes the stream and everything in it. A stream without one lives until it is deleted.
A key, a token, and a public stream
Every request to a private stream carries an API key of the stream’s account, or an access token of up to 10 minutes made from one; a key can be narrowed to some streams, and made read-only, and a token for a web page can be narrowed further. A public stream is read and tailed by anyone with its URL, and appends still need a key or a token (see Access).
A stream deleted and created again
Under the same name, it is a new stream at the same URL, with new offsets. Each answer names which stream answered in Stream-Incarnation, so a reader can tell (see A stream deleted and created again).
How it reaches your program
Your program appends with POST to the stream’s URL and reads with GET from an offset, with a key or a token, from any machine. Each request goes to Tonbo in the stream’s region.
PRODUCERS, on any machine READERS, on any machine
POST {url}: append GET {url}?offset=...: read or tail
| ^
v |
TONBO, in the stream's region: three replicas, one per zone
+--------------------------------------------------------+
| message | message | message | ... | the end |
+--------------------------------------------------------+
an append answers 200 once two of the three hold it;
every reader sees one order and keeps its own offsetAn append is durable once it answers 200: two of the stream’s three replicas, each in its own zone of the region, hold it, which is why any reader on any machine finds it at the same offset, in the one order every reader sees (see Delivery guarantees).
A stream, a database and a Machine
| A stream | A database | A Machine (Not open yet) | |
|---|---|---|---|
| Question it answers | How do many programs share one ordered log? | Where does my program’s state live, so another machine carries on from it? | Where does my service run, asleep until a request comes? |
| Your program reaches it | HTTPS requests to its URL, from any language | SQL on a local copy, opened by name | HTTPS requests to its name |
| Who writes | Any number of producers, each retried append once | One process at a time: the last one to open it | Your program, writing its own database |
| Durable when | The append answers 200 | synced() resolves | In its database, once synced() resolves; never in memory |
Every operation
Everything a stream supports, in two places: the stream’s own URL, written {url} below, where programs append and read with a key or token, and the Management API at https://api.tonbo.dev, where members create, publish and delete streams with a key. There is no operation to acknowledge or lease a message: readers keep their own offsets.
| Operation | Request | What it does |
|---|---|---|
| Create | POST /v1/streams | Creates a stream with its name, region, content type and an optional expiry. |
| List | GET /v1/streams | Lists the account’s streams, by name, with a prefix and pages. |
| Show | GET /v1/streams/{name} | Reads one stream: its URL, state, content type and expiry. |
| Exchange a key | POST https://tonbo.dev/api/iam/token | Exchanges an API key for a short-lived access token, or a narrower token for a web page. |
| Append | POST {url} | Appends the body, exactly once with producer headers. |
| Close | POST {url} with Stream-Closed: true | Ends the stream for good: it stays readable and refuses appends. |
| Read | GET {url}?offset=… | Reads from an offset to the end. |
| Long-poll | GET {url}?offset=…&live=long-poll | Waits at the end for the next append. |
| SSE tail | GET {url}?offset=…&live=sse | Stays open and pushes every new append as a Server-Sent Event. |
| HEAD | HEAD {url} | Reads the end, closure, retention and latest snapshot, without the contents. |
| Immutable chunk | GET {url}/incarnation/{token}/chunk/{offset} | Reads up to 4 MiB of history at a URL whose answer never changes. |
| Immutable snapshot | GET {url}/incarnation/{token}/snapshot/{offset} | Reads the latest snapshot at a URL whose answer never changes. |
| Publish a snapshot | PUT {url}/snapshot/{offset} | Publishes a summary of the stream up to an offset; larger ones go up in parts. |
| Read a snapshot | GET {url}/snapshot/{offset} | Reads the latest snapshot. |
| Advance retention | PUT {url}/retention/{offset} | Drops the history before a snapshot; reads before it then answer 410. |
| Bootstrap | GET {url}/bootstrap | Reads the latest snapshot and every message after it in one answer. |
| Public or private | PATCH /v1/streams/{name} | Lets anyone read and tail the stream without a token, or stops that. |
| Narrow a key | POST /v1/api-keys | Issues a key that reaches only the streams it names or the prefixes it lists, read-only if asked. |
| Usage | GET /v1/usage/streams | Each stream’s writes and storage this month, at list price. |
| Delete | DELETE /v1/streams/{name} | Deletes the stream and everything in it; expiry does the same on its own. |
| Not at the URL | PUT {url}, DELETE {url} | Refused with 403 STREAM_LIFECYCLE: streams are created and deleted only through the Management API. |