> Fetch the index of every Tonbo docs page as Markdown at https://tonbo.dev/llms.txt

# 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](https://tonbo.dev/docs/streams/manage.md#create)).

## 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](https://tonbo.dev/docs/streams/append.md#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](https://tonbo.dev/docs/streams/read.md#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](https://tonbo.dev/docs/streams/append.md#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](https://tonbo.dev/docs/streams/read.md#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](https://tonbo.dev/docs/streams/append.md#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](https://tonbo.dev/docs/streams/snapshots.md)).

## 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](https://tonbo.dev/docs/streams/access.md)).

## 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](https://tonbo.dev/docs/streams/read.md#incarnation)).

## 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.

```text
  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 offset
```

An 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](https://tonbo.dev/docs/streams/guarantees.md)).

## A stream, a database and a Machine

|  | A stream | [A database](https://tonbo.dev/docs/databases/concepts.md) | [A Machine](https://tonbo.dev/docs/machines/concepts.md) (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](https://tonbo.dev/docs/streams/manage.md#create) | `POST /v1/streams` | Creates a stream with its name, region, content type and an optional expiry. |
| [List](https://tonbo.dev/docs/streams/manage.md#list) | `GET /v1/streams` | Lists the account’s streams, by name, with a prefix and pages. |
| [Show](https://tonbo.dev/docs/streams/manage.md#list) | `GET /v1/streams/{name}` | Reads one stream: its URL, state, content type and expiry. |
| [Exchange a key](https://tonbo.dev/docs/streams/access.md#token) | `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](https://tonbo.dev/docs/streams/append.md#append) | `POST {url}` | Appends the body, exactly once with producer headers. |
| [Close](https://tonbo.dev/docs/streams/append.md#close) | `POST {url} with Stream-Closed: true` | Ends the stream for good: it stays readable and refuses appends. |
| [Read](https://tonbo.dev/docs/streams/read.md#read) | `GET {url}?offset=…` | Reads from an offset to the end. |
| [Long-poll](https://tonbo.dev/docs/streams/read.md#tail) | `GET {url}?offset=…&live=long-poll` | Waits at the end for the next append. |
| [SSE tail](https://tonbo.dev/docs/streams/read.md#tail) | `GET {url}?offset=…&live=sse` | Stays open and pushes every new append as a Server-Sent Event. |
| [HEAD](https://tonbo.dev/docs/streams/read.md#head) | `HEAD {url}` | Reads the end, closure, retention and latest snapshot, without the contents. |
| [Immutable chunk](https://tonbo.dev/docs/streams/read.md#immutable) | `GET {url}/incarnation/{token}/chunk/{offset}` | Reads up to 4 MiB of history at a URL whose answer never changes. |
| [Immutable snapshot](https://tonbo.dev/docs/streams/read.md#immutable) | `GET {url}/incarnation/{token}/snapshot/{offset}` | Reads the latest snapshot at a URL whose answer never changes. |
| [Publish a snapshot](https://tonbo.dev/docs/streams/snapshots.md#publish) | `PUT {url}/snapshot/{offset}` | Publishes a summary of the stream up to an offset; larger ones go up in parts. |
| [Read a snapshot](https://tonbo.dev/docs/streams/snapshots.md#read-snapshot) | `GET {url}/snapshot/{offset}` | Reads the latest snapshot. |
| [Advance retention](https://tonbo.dev/docs/streams/snapshots.md#retention) | `PUT {url}/retention/{offset}` | Drops the history before a snapshot; reads before it then answer 410. |
| [Bootstrap](https://tonbo.dev/docs/streams/snapshots.md#bootstrap) | `GET {url}/bootstrap` | Reads the latest snapshot and every message after it in one answer. |
| [Public or private](https://tonbo.dev/docs/streams/manage.md#visibility) | `PATCH /v1/streams/{name}` | Lets anyone read and tail the stream without a token, or stops that. |
| [Narrow a key](https://tonbo.dev/docs/streams/access.md#narrow) | `POST /v1/api-keys` | Issues a key that reaches only the streams it names or the prefixes it lists, read-only if asked. |
| [Usage](https://tonbo.dev/docs/streams/pricing.md#usage) | `GET /v1/usage/streams` | Each stream’s writes and storage this month, at list price. |
| [Delete](https://tonbo.dev/docs/streams/manage.md#delete) | `DELETE /v1/streams/{name}` | Deletes the stream and everything in it; expiry does the same on its own. |
| [Not at the URL](https://tonbo.dev/docs/streams/manage.md#lifecycle) | `PUT {url}, DELETE {url}` | Refused with 403 STREAM_LIFECYCLE: streams are created and deleted only through the Management API. |
