Streaming
Some responses arrive over time rather than all at once: a token stream from a model, a log tail, a long export. A streaming method hands the caller each event as it arrives, in whatever form is natural for their language.
An operation whose success response declares text/event-stream streams automatically. For the other formats, configure it per endpoint.
What callers write
These are from generated SDKs, for an operation GET /events/stream tagged events.
for await (const event of client.events.stream()) {
console.log(event.id);
}Returns an AsyncIterable.
Formats
| Format | Wire shape | Use it when |
|---|---|---|
| Server-sent events | text/. Each event prefixed data: and ended by a blank line | Model output and live feeds. It's the most common choice |
| NDJSON | One complete JSON object per line, such as application/ | Exports and logs, with no event framing to parse |
| Chunked | Raw bytes or text | The response has no structure of its own |
For server-sent events, the client handles the framing for you: it joins multi-line data: fields, ignores keep-alive comments, and treats [DONE] as the end of the stream.
Setting it up
In SDK Studio, select the endpoint and open its streaming settings. Each is saved on that endpoint, under streaming.
Transport formatchoiceThe wire format your endpoint uses.
| Value | Studio label | Meaning |
|---|---|---|
sse | SSE | Server-sent events: text/, one event per message |
ndjson | NDJSON | Newline-delimited JSON: one JSON object per line |
chunked | Chunked | Raw chunked transfer, surfacing bytes as they arrive |
streaming.format
Event fieldfieldThe field surfaced from each chunk.
streaming.eventField
For events shaped like this, leave Event field as data, and each iteration yields the parsed object:
data: {"id": "evt_1", "type": "user.created"}
data: {"id": "evt_2", "type": "user.updated"}Stream key
Some endpoints answer with plain JSON or a stream, depending on a field in the request body. The SDK generates two methods for these: a normal one and a stream one. The stream method sets the field for the caller and leaves it out of its arguments.
Stream key is set to Automatic by default, which looks for a boolean field named stream, event, streaming or eventMode. If your API uses another name, such as sse, pick that field from the list.
If the field is text rather than a boolean, also set Stream value. For a response_mode field that takes streaming or blocking, the stream key is response_mode and the stream value is streaming. Callers of the normal method can still pass blocking.
Declaring it in your spec
Declaring the media type is usually all you need:
responses:
"200":
description: A stream of events
content:
text/event-stream:
schema:
$ref: "#/components/schemas/Event"Give the schema a $ref to your event, so callers get typed events rather than untyped data.
An operation can also offer both forms. If it declares JSON and text/event-stream, callers get an ordinary method and a separate streaming companion.
Stopping early
Stop iterating as soon as you don't need more events, so the connection can close promptly. For cancellation from elsewhere, pass a signal:
const controller = new AbortController();
for await (const event of client.events.stream({ signal: controller.signal })) {
if (event.type === "done") break;
}Streaming methods take fewer options than ordinary ones. In TypeScript they accept headers and signal, not per-call retry or timeout settings.
Failures
Retries apply to establishing the request. Once events have reached the caller, replaying the request would duplicate them, so a stream that breaks surfaces its error instead.
Put an offset, a sequence number or a cursor in each event, and let the endpoint accept it. Otherwise a dropped connection means starting again from the beginning.
A record that looks like JSON but doesn't parse raises SdkStreamParseError, or that language's equivalent.
Timeouts
Don't set a short timeout on a streamed endpoint. Give it its own timeout that fits the stream, rather than inheriting one meant for ordinary calls.
Don't stream everything
Streaming costs the caller a loop and gives up a plain return value. Use it when the first byte matters, or when the response has no natural end. A 40 ms JSON response should stay a JSON response.