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

# Snapshots and bootstrap

Last updated 2 November 2026

Every header and status of the requests that publish and read a stream’s snapshot, upload one in parts, advance its retention and bootstrap a reader.

These requests go to paths under the stream’s URL; the guide is [Snapshots and retention](https://tonbo.dev/docs/streams/snapshots.md). The headers every request shares, the error codes and how to tell whether a write applied are on the [overview](https://tonbo.dev/docs/reference/streams.md).

## Publish a snapshot

Stores a summary of the stream up to an offset, which new readers start from instead of the beginning. It removes nothing from the stream.

`PUT {stream}/snapshot/{snapshot_offset}` · Protocol: [extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot), [extensions 2.1](https://ursula.tonbo.io/docs/specs/extensions/#21-offset-conventions), [extensions 8](https://ursula.tonbo.io/docs/specs/extensions/#8-url-encoding)

Credential: A key or token that reaches the stream and is not read-only.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `snapshot_offset` path | offset | Required | The offset the snapshot summarizes the stream up to, excluded, URL-encoded: a `Stream-Next-Offset` an answer gave. On a JSON stream it must fall between two messages, which a `Stream-Next-Offset` always does, else `400` with `NOT_JSON_BOUNDARY`. Past the end of the stream answers `409`, before the retained offset `410`. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Content-Type` header | media type | Optional; `application/octet-stream` when omitted | The snapshot's own content type, which need not be the stream's. Reads of the snapshot answer with it. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Stream-Snapshot-Offset` header | offset | On 204 and 409 | On a `204`, the published snapshot's offset. On a `409`, the latest snapshot's, which the request did not replace. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Stream-Snapshot-Digest` header | 64 lowercase hexadecimal digits | On 204 and 409 | The snapshot's digest: the BLAKE3 hash of its content type and body. A publish sent again answers the same digest. On a `409`, the latest snapshot's. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `204` | Published, or the same snapshot published again. It replaces the stream's earlier snapshot at once. |
| `400` | The offset is malformed or, on a JSON stream, not between two messages. |
| `409` | Another snapshot is the latest: a different body at the same offset, or the latest is at a later offset; the headers name it. A `409` that names no snapshot refuses an offset past the end of the stream. |
| `410` | The offset is before the stream's retained offset. |
| `503` | `JSON_BOUNDARY_UNVERIFIED`: the boundary could not be checked just now. Nothing was published: send it again after `Retry-After`. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`402` `PAYMENT_REQUIRED`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#payment-required) | The account’s balance is zero. Appends pause; reads and tails continue. | After a top-up |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`409`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#snapshot-conflict) | Another snapshot body at the same offset, or a snapshot at an offset before the latest one. | No |
| [`413`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#too-large) | The body is over the request body limit. | No |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Safe while the snapshot is the latest: the same offset, content type and body answer `204` with the same digest.

### Example

```shell
curl -sS -i -X PUT "$STREAM/snapshot/$OFFSET" \
  -H "Authorization: Bearer $TONBO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"messages":3}'
```

## Stage a part of a snapshot

Uploads one part of a snapshot too large for one request; a [commit](#commit-parts) publishes the parts together.

`POST {stream}/snapshot/{snapshot_offset}/parts` · Protocol: [extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)

Credential: As for a publish.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `snapshot_offset` path | offset | Required | Checked as an offset and otherwise ignored: a part belongs to the stream, so a commit at another offset may use it. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Content-Length` header | integer | Recommended | The part's size, at most `Ursula-Max-Request-Bytes`, 8 MiB today. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Stream-Snapshot-Part` header | 1 to 64 visible ASCII characters | On 201 | The part's id, which the commit lists. Staging changes nothing a reader sees. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Ursula-Max-Staged-Parts` header | integer | On 429 STAGED_PARTS_LIMIT | The stream already holds this many staged parts no commit used, 8,192: commit or [discard](#discard-parts) them before staging more. Waiting does not help, so the answer has no `Retry-After`. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Ursula-Max-Staged-Bytes` header | integer | On 429 STAGED_PARTS_LIMIT | The same for their bytes, 2 GiB. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `201` | Staged. Sending it again stages another part, so keep the ids of the parts you use. |
| `429` | `STAGED_PARTS_LIMIT`, with the bound in its header: commit or discard parts first. A `429` with `Retry-After` is the account's rate instead ([Rate limited](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited)). |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`402` `PAYMENT_REQUIRED`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#payment-required) | The account’s balance is zero. Appends pause; reads and tails continue. | After a top-up |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`413`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#too-large) | The body is over the request body limit. | No |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Sending it again stages another part, which only costs space until a commit or a discard; unused parts are discarded after a day.

### Example

```shell
curl -sS -i -X POST "$STREAM/snapshot/$OFFSET/parts" \
  -H "Authorization: Bearer $TONBO_API_KEY" \
  -H "Content-Type: application/octet-stream" \
  -d '{"messages":3}'
```

Each answer's `Stream-Snapshot-Part` is a part id; keep them in order for the commit.

## Publish a snapshot from its parts

Publishes the snapshot made of staged parts, in the order the body lists them, as a [publish](#publish-snapshot) of the whole would.

`PUT {stream}/snapshot/{snapshot_offset} with Stream-Snapshot-Parts` · Protocol: [extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot), [extensions 10](https://ursula.tonbo.io/docs/specs/extensions/#10-server-metadata)

Credential: As for a publish.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `Stream-Snapshot-Parts` header | integer, 1 to 4096 | Required | How many part ids the body lists, each once. The body is the ids, each followed by one newline and nothing else. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Stream-Snapshot-Digest` header | 64 lowercase hexadecimal digits | Required | The digest of the whole snapshot, which the stream computes over the assembled parts: a mismatch answers `400` with `SNAPSHOT_DIGEST_MISMATCH` and publishes nothing. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |
| `Content-Type` header | media type | Optional; `application/octet-stream` when omitted | The snapshot's content type, as for a publish. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Ursula-Max-Snapshot-Bytes` header | integer | On 413 SNAPSHOT_TOO_LARGE | The assembled snapshot is larger than the stream accepts; the header names the limit, which `HEAD` reports too. ([extensions 10](https://ursula.tonbo.io/docs/specs/extensions/#10-server-metadata)) |
| `Retry-After` header | seconds | On 503 | A commit of this stream is still running, `SNAPSHOT_COMMIT_IN_PROGRESS`, or too many run at once: send the same commit again after it. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `204` | Published, with the headers of a publish. |
| `400` | A digest that does not match, a part that is unknown or staged for another stream, or a body that does not list exactly `Stream-Snapshot-Parts` distinct ids. |
| `409` | As for a publish: another snapshot is the latest. It comes before the retained-offset check, so a superseded commit answers `409` even below retention. |
| `413` | `SNAPSHOT_TOO_LARGE`, with `Ursula-Max-Snapshot-Bytes`. |
| `503` | The commit is running or has to wait: send it again after `Retry-After`; it answers from the first once that finished. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`402` `PAYMENT_REQUIRED`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#payment-required) | The account’s balance is zero. Appends pause; reads and tails continue. | After a top-up |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`409`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#snapshot-conflict) | Another snapshot body at the same offset, or a snapshot at an offset before the latest one. | No |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Safe: a commit sent again answers as a publish sent again does, and the parts are kept until its answer is final.

### Example

```shell
curl -sS -i -X PUT "$STREAM/snapshot/$OFFSET" \
  -H "Authorization: Bearer $TONBO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Stream-Snapshot-Parts: 2" \
  -H "Stream-Snapshot-Digest: $DIGEST" \
  -d '$PART_1
$PART_2
'
```

`DIGEST` is the digest of the whole snapshot, and `PART_1` and `PART_2` the ids the stage answers named.

## Discard staged parts

Discards every staged part of the stream, so an abandoned upload stops counting toward its bounds. It deletes neither the stream nor a published snapshot.

`DELETE {stream}/snapshot/parts` · Protocol: [extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)

Credential: As for a publish.

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Stream-Incarnation` header | token | On 204 | The stream whose parts were discarded ([Stream-Incarnation](https://tonbo.dev/docs/reference/streams.md#header-stream-incarnation-response)). ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `204` | Discarded. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Safe. While a commit of the stream runs it may answer `503` with `Retry-After`: send it again after it.

### Example

```shell
curl -sS -i -X DELETE "$STREAM/snapshot/parts" \
  -H "Authorization: Bearer $TONBO_API_KEY"
```

## Read a snapshot

Reads the latest snapshot, or a byte range of it.

`GET {stream}/snapshot/{snapshot_offset}` · Protocol: [extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)

Credential: As for a read.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `snapshot_offset` path | offset | Required | The latest snapshot's offset, which `HEAD` names in `Stream-Snapshot-Offset`. Any other answers `404`: an earlier snapshot is gone once replaced. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Range` header | `bytes=first-last`, `bytes=first-` or `bytes=-length` | Optional | One byte range of the snapshot, answered `206`. A range that starts at or past its end answers `416`. Several ranges, a range that does not parse, or `If-Range`, answer the whole snapshot. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `If-Range` header | entity tag | Ignored | With it the answer is the whole snapshot, `200`, whatever `Range` asks. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `If-None-Match` header | entity tag | Optional | The snapshot's `ETag`: `304` with the same headers, ignoring any range. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Content-Type` header | media type | On 200 and 206 | The snapshot's content type, as published. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Stream-Snapshot-Offset` header | offset | On 200, 206 and 304 | The snapshot's offset. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Stream-Snapshot-Digest` header | 64 lowercase hexadecimal digits | On 200, 206 and 304 | The digest of the whole snapshot, never of the range. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Stream-Next-Offset` header | offset | On 200, 206 and 304 | Where the messages after the snapshot start: read on from it. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Stream-Up-To-Date` header | `true` | When nothing follows the snapshot | The snapshot is at the end of the stream. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `ETag` header | entity tag | On 200, 206 and 304 | The snapshot's digest in quotes. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Accept-Ranges` header | `bytes` | On every snapshot answer | The snapshot can be read in byte ranges. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |
| `Content-Range` header | `bytes first-last/total` or `bytes */total` | On 206 and 416 | The range returned, and the snapshot's size. ([extensions 2.5](https://ursula.tonbo.io/docs/specs/extensions/#25-read-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `200` | The snapshot. |
| `206` | The requested range. |
| `304` | The snapshot is the one the `ETag` named. |
| `416` | The range starts at or past the snapshot's end. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#snapshot-not-latest) | A snapshot read names an offset that is not the latest snapshot’s. | At the latest offset |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Always safe.

### Example

```shell
curl -sS -i "$STREAM/snapshot/$OFFSET" \
  -H "Authorization: Bearer $TONBO_API_KEY"
```

## Advance retention

Stops keeping, and paying for, the stream's history before an offset at or before its latest snapshot.

`PUT {stream}/retention/{retained_offset}` · Protocol: [extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)

Credential: As for a publish.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `retained_offset` path | offset | Required | The new start of the stream, URL-encoded: at most the latest snapshot's offset and, on a JSON stream, between two messages; otherwise `400`. An offset at or before the current retained offset changes nothing. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Stream-Retained-Offset` header | offset | On success | The stream's retained offset after the request. From then on a read before it, `-1` included, answers `410`. ([extensions 2.2](https://ursula.tonbo.io/docs/specs/extensions/#22-publish-snapshot)) |

### Statuses

| Status | What it means |
| --- | --- |
| `204` | Advanced, or already at or past the offset. |
| `400` | The offset is past the latest snapshot, or not between two messages of a JSON stream. |
| `503` | On a JSON stream, the boundary could not be checked just now. Nothing changed: send it again after `Retry-After`. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Always safe: retention only moves forward.

### Example

```shell
curl -sS -i -X PUT "$STREAM/retention/$OFFSET" \
  -H "Authorization: Bearer $TONBO_API_KEY"
```

## Bootstrap

Gives a new reader the stream's current state in one answer: its latest snapshot and the messages after it.

`GET {stream}/bootstrap` · Protocol: [extensions 3.1](https://ursula.tonbo.io/docs/specs/extensions/#31-request), [extensions 3.2](https://ursula.tonbo.io/docs/specs/extensions/#32-response), [extensions 3.3](https://ursula.tonbo.io/docs/specs/extensions/#33-follow-up-live-reads), [extensions 3.4](https://ursula.tonbo.io/docs/specs/extensions/#34-compatibility)

Credential: As for a read.

### Request

| Parameter | Value | Required | What it does |
| --- | --- | --- | --- |
| `live` query | none | Not accepted | Bootstrap never tails, and takes no query parameter; `live` answers `400`. To go live, open a [tail](https://tonbo.dev/docs/reference/streams/read.md#sse) at its `Stream-Next-Offset`. ([extensions 3.3](https://ursula.tonbo.io/docs/specs/extensions/#33-follow-up-live-reads)) |

### Answer

| Field | Value | When | What it means |
| --- | --- | --- | --- |
| `Content-Type` header | `multipart/mixed; boundary=…` | On 200 | A body of parts, each with its own `Content-Type`: first the latest snapshot, or an empty `application/octet-stream` part when there is none, then the messages after it, one part per message on a JSON stream and one or more per part on any other. ([extensions 3.2](https://ursula.tonbo.io/docs/specs/extensions/#32-response)) |
| `Stream-Snapshot-Offset` header | offset | On 200 | The snapshot's offset, or `-1` without one. ([extensions 3.2](https://ursula.tonbo.io/docs/specs/extensions/#32-response)) |
| `Stream-Next-Offset` header | offset | On 200 | Where the answer ends: read or tail on from it. ([extensions 3.2](https://ursula.tonbo.io/docs/specs/extensions/#32-response)) |
| `Stream-Up-To-Date` header | `true` | When the answer reached the end | The answer holds the whole stream. Absent, it stopped short, after 8 MiB of messages or where older messages are only in object storage: read on from `Stream-Next-Offset` before treating the state as current. ([extensions 3.2](https://ursula.tonbo.io/docs/specs/extensions/#32-response)) |

### Statuses

| Status | What it means |
| --- | --- |
| `200` | The snapshot and the messages after it, complete or partial. |

| Refusal | When | Send again |
| --- | --- | --- |
| [`401`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unauthorized) | The key or token is missing, expired or revoked, or the request sent a key that acts as an Agent, which answers the code `exchange_required`. | With a valid key or a new token |
| [`403`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#forbidden) | The key is narrowed and does not reach this stream, or is read-only and the request appends. | No |
| [`404`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#not-found) | The stream does not exist yet, is still being created, or was deleted or expired; a request with a missing or expired token may answer the same. | Once it is active |
| [`412`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#incarnation) | The request carried Stream-Incarnation, and the stream was deleted and created again since. | No |
| [`429`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#rate-limited) | The account sent more requests per second, or held more tails open at once, than its region allows. | After Retry-After |
| [`503`](https://tonbo.dev/docs/streams/troubleshooting/stream.md#unavailable) | The region cannot take the request, or check an API key sent directly, for a moment. | Unchanged, after Retry-After |

Sending it again: Always safe. A reader that gets `410` from a read bootstraps to rebuild its state, then reads on from the answer's `Stream-Next-Offset`.

### Example

```shell
curl -sS -i "$STREAM/bootstrap" \
  -H "Authorization: Bearer $TONBO_API_KEY"
```
