Concepts

Last updated 29 October 2026

View .md

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

A stream, a database and a Machine

A streamA databaseA Machine (Not open yet)
Question it answersHow 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 itHTTPS requests to its URL, from any languageSQL on a local copy, opened by nameHTTPS requests to its name
Who writesAny number of producers, each retried append onceOne process at a time: the last one to open itYour program, writing its own database
Durable whenThe append answers 200synced() resolvesIn 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.

OperationRequestWhat it does
CreatePOST /v1/streamsCreates a stream with its name, region, content type and an optional expiry.
ListGET /v1/streamsLists the account’s streams, by name, with a prefix and pages.
ShowGET /v1/streams/{name}Reads one stream: its URL, state, content type and expiry.
Exchange a keyPOST https://tonbo.dev/api/iam/tokenExchanges an API key for a short-lived access token, or a narrower token for a web page.
AppendPOST {url}Appends the body, exactly once with producer headers.
ClosePOST {url} with Stream-Closed: trueEnds the stream for good: it stays readable and refuses appends.
ReadGET {url}?offset=…Reads from an offset to the end.
Long-pollGET {url}?offset=…&live=long-pollWaits at the end for the next append.
SSE tailGET {url}?offset=…&live=sseStays open and pushes every new append as a Server-Sent Event.
HEADHEAD {url}Reads the end, closure, retention and latest snapshot, without the contents.
Immutable chunkGET {url}/incarnation/{token}/chunk/{offset}Reads up to 4 MiB of history at a URL whose answer never changes.
Immutable snapshotGET {url}/incarnation/{token}/snapshot/{offset}Reads the latest snapshot at a URL whose answer never changes.
Publish a snapshotPUT {url}/snapshot/{offset}Publishes a summary of the stream up to an offset; larger ones go up in parts.
Read a snapshotGET {url}/snapshot/{offset}Reads the latest snapshot.
Advance retentionPUT {url}/retention/{offset}Drops the history before a snapshot; reads before it then answer 410.
BootstrapGET {url}/bootstrapReads the latest snapshot and every message after it in one answer.
Public or privatePATCH /v1/streams/{name}Lets anyone read and tail the stream without a token, or stops that.
Narrow a keyPOST /v1/api-keysIssues a key that reaches only the streams it names or the prefixes it lists, read-only if asked.
UsageGET /v1/usage/streamsEach stream’s writes and storage this month, at list price.
DeleteDELETE /v1/streams/{name}Deletes the stream and everything in it; expiry does the same on its own.
Not at the URLPUT {url}, DELETE {url}Refused with 403 STREAM_LIFECYCLE: streams are created and deleted only through the Management API.