Create stream

bucketpathstringrequired

Bucket ID. The Durable Streams Protocol specifies [a-z0-9_-]{4,64}. Ursula does not currently enforce this regex but client-side conformance is recommended.

streampathstringrequired

Stream 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-Typeheaderstring

Content type of the initial payload (e.g. application/json). Becomes the stream's content type.

Stream-Closedheaderstring

Set to true to close the stream immediately after creation.

Stream-TTLheaderstring

Time-to-live in seconds. The stream will expire after this duration.

Stream-Expires-Atheaderstring

Absolute expiration timestamp (RFC 3339). Mutually exclusive with Stream-TTL.

Stream-Seqheaderstring

Client-supplied monotonic sequence token. Rejects creates whose Stream-Seq is not lexicographically greater than the previous value seen for this stream.

Stream-Attrsheaderstring

JSON 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-Idheaderstring

Producer identity for exactly-once writes.

Producer-Epochheaderstring

Producer epoch (must accompany Producer-Id).

Producer-Seqheaderstring

Producer sequence number (must accompany Producer-Id).

Stream-Forked-Fromheaderstring

Parent 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-Offsetheaderstring

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

bodybodybinary

Optional 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

StatusMeaning
201Stream created.
200Stream already exists (idempotent).
400Invalid stream ID, invalid headers, or bad JSON payload.
409Stream 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/hello
curl -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.