Skip to main content
Both POST /api/v1/responses (with stream: true) and GET /api/v1/runs/{runId}/stream open a Server-Sent Events (SSE) connection. SSE is a plain HTTP response with Content-Type: text/event-stream — every event is a data: line followed by a blank line.
The connection closes after data: [DONE]. If it drops earlier, you can resume with GET /runs/{runId}/stream using the same run_id.

Event types

Every event is a JSON object with a type field. Events fall into three groups: lifecycle, output, and terminal.

Lifecycle

event
Sent immediately after POST /responses connects. Use its response.id and response.run_id to correlate downstream events or resume later.
event
Sent immediately after GET /runs/{runId}/stream connects. Includes the current status so you know whether you’re attaching mid-run or to something already terminal.

Output

event
Progress event indicating that the response stream opened an output item. This is not the final itemized workflow output shape; read GET /api/v1/runs/{runId} after completion for Result fields, output items, and parts.
event
Progress event indicating that the streamed output item closed. Same shape as added.

Terminal

event
Run finished successfully. Followed by data: [DONE] and connection close.
To read the actual output, call GET /api/v1/runs/{runId} and read the output object. Streaming delivers progress events; the final structured output lives on the run record.
event
Run failed. Followed by data: [DONE] and connection close.

Keepalive

The server emits SSE comment lines (: keepalive) every 15 seconds to prevent proxies and CDNs from closing idle connections during long-running steps. Ignore them — any line starting with : is a comment.

Consuming the stream

Browser

Node / Python

Both have solid SSE libraries — eventsource for Node, httpx + sseclient for Python. The semantics are the same: parse each data: line as JSON and branch on type.

Resuming a dropped stream

If your connection drops mid-run, don’t re-POST — that starts a new run (and bills you again). Instead, reconnect with the run_id from response.created:
The first event will be response.resumed. If the run already finished while you were disconnected, you’ll get the terminal event and [DONE] on the next poll tick (~1 second).