Create stream
bucketpathstringrequiredBucket ID. The Durable Streams Protocol specifies [a-z0-9_-]{4,64}. Ursula does not currently enforce this regex but client-side conformance is recommended.
streampathstringrequiredStream ID within the bucket. Cannot contain \0 and segments cannot equal ... Note: Ursula does not currently enforce the Durable Streams Protocol's 122-byte stream-ID ceiling - clients should still respect it for conformance.
Content-TypeheaderstringContent type of the initial payload (e.g. application/json). Becomes the stream's content type.
Stream-ClosedheaderstringSet to true to close the stream immediately after creation.
Stream-TTLheaderstringTime-to-live in seconds. The stream will expire after this duration.
Stream-Expires-AtheaderstringAbsolute expiration timestamp (RFC 3339). Mutually exclusive with Stream-TTL.
Stream-SeqheaderstringClient-supplied monotonic sequence token. Rejects creates whose Stream-Seq is not lexicographically greater than the previous value seen for this stream.
Stream-AttrsheaderstringJSON stream attributes. See stream attributes. If the stream already exists, the submitted attributes must match the stored attributes for the create request to be idempotent.
Producer-IdheaderstringProducer identity for exactly-once writes.
Producer-EpochheaderstringProducer epoch (must accompany Producer-Id).
Producer-SeqheaderstringProducer sequence number (must accompany Producer-Id).
Stream-Forked-FromheaderstringParent stream path (e.g. {bucket}/{stream}). When set, the new stream is created as a fork of the parent: the server copies the parent's data up to Stream-Fork-Offset (or the parent's current tail if omitted) into the new stream's initial payload. The new stream is independent after creation — subsequent appends and reads do not touch the parent.
Stream-Fork-OffsetheaderstringOffset into the parent stream up to which data is copied. Must be <= the parent's current tail offset. Defaults to the parent's tail offset when omitted. A value of 0 creates an empty fork that inherits metadata but copies no data.
bodybodybinaryOptional initial payload. If provided, becomes the first entry in the stream. Ignored when Stream-Forked-From is set (the forked prefix becomes the initial payload instead).
Response
| Status | Meaning |
|---|---|
201 | Stream created. |
200 | Stream already exists (idempotent). |
400 | Invalid stream ID, invalid headers, or bad JSON payload. |
409 | Stream already exists with different content type, or sequence conflict. |
Response headers include Location, Content-Type, Stream-Next-Offset, and lifetime headers (Stream-TTL / Stream-Expires-At) when set. Stream-Closed: true is set if the create request also closed the stream. ETag is set on reads only.
curl -X PUT http://127.0.0.1:4437/demo/hellocurl -X PUT http://127.0.0.1:4437/demo/hello \
-H 'Content-Type: application/json' \
--data-binary '{"msg": "first entry"}'curl -X PUT http://127.0.0.1:4437/demo/ephemeral \
-H 'Stream-TTL: 3600'curl -X PUT http://127.0.0.1:4437/demo/child \
-H 'Stream-Forked-From: demo/hello'curl -X PUT http://127.0.0.1:4437/demo/session-1 \
-H 'Stream-Attrs: {"title":"Support session","metadata":{"purpose":"customer-support"}}'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, retention, fork source, or stream attributes, the response is 409 Conflict.
When forking, the child inherits the parent's content_type (unless explicitly overridden) and TTL / expiration policy (unless explicitly set). The parent stream is protected from hard deletion by a reference count until all of its forks are deleted.