> ## Documentation Index
> Fetch the complete documentation index at: https://docs.snakream.tonbo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Create stream

> Create a new append-only stream within a bucket.

<ParamField path="bucket" type="string" required>
  Bucket ID. Must match `[a-z0-9_-]{4,64}`.
</ParamField>

<ParamField path="stream" type="string" required>
  Stream ID within the bucket.
</ParamField>

<ParamField header="Content-Type" type="string">
  Content type of the initial payload (e.g. `application/json`). Becomes the stream's content type.
</ParamField>

<ParamField header="Stream-Closed" type="string">
  Set to `true` to close the stream immediately after creation.
</ParamField>

<ParamField header="Stream-TTL" type="string">
  Time-to-live in seconds. The stream will expire after this duration.
</ParamField>

<ParamField header="Stream-Expires-At" type="string">
  Absolute expiration timestamp (RFC 3339). Mutually exclusive with `Stream-TTL`.
</ParamField>

<ParamField header="If-Match" type="string">
  Conditional create: only succeed if the stream's ETag matches.
</ParamField>

<ParamField header="Stream-Seq" type="string">
  Client-supplied sequence token for conflict detection.
</ParamField>

<ParamField header="Producer-Id" type="string">
  Producer identity for [exactly-once writes](/concepts/exactly-once-writes).
</ParamField>

<ParamField header="Producer-Epoch" type="string">
  Producer epoch (must accompany `Producer-Id`).
</ParamField>

<ParamField header="Producer-Seq" type="string">
  Producer sequence number (must accompany `Producer-Id`).
</ParamField>

<ParamField body="body" type="binary">
  Optional initial payload. If provided, becomes the first entry in the stream.
</ParamField>

## Response

| Status | Meaning                                                                   |
| ------ | ------------------------------------------------------------------------- |
| `201`  | Stream created.                                                           |
| `200`  | Stream already exists with identical configuration (idempotent).          |
| `400`  | Invalid stream ID, invalid headers, or bad JSON payload.                  |
| `404`  | Bucket not found.                                                         |
| `409`  | Stream already exists with different configuration, or sequence conflict. |
| `412`  | `If-Match` precondition failed.                                           |

Response headers include `Location`, `Content-Type`, `Stream-Next-Offset`, and `ETag`.

<RequestExample>
  ```bash Create empty stream theme={null}
  curl -X PUT https://stream.tonbo.dev/ds/demo/hello
  ```

  ```bash Create with initial payload theme={null}
  curl -X PUT https://stream.tonbo.dev/ds/demo/hello \
    -H 'Content-Type: application/json' \
    --data-binary '{"msg": "first entry"}'
  ```

  ```bash Create with TTL theme={null}
  curl -X PUT https://stream.tonbo.dev/ds/demo/ephemeral \
    -H 'Stream-TTL: 3600'
  ```
</RequestExample>

<Note>
  If a stream with the same ID already exists and has identical configuration, the response is `200 OK` (idempotent). If the existing stream differs in content type, closed state, or retention, the response is `409 Conflict`.
</Note>
