Server-Sent Events stream of run output

Returns a long-lived `text/event-stream` connection.

GET /api/v1/runs/{runId}/stream

Returns a long-lived text/event-stream connection.

Lifecycle events

  • status{ "status": "running"|"sleep", "claudeStatus": string|null }. Sent once, on connect, reflecting state at that moment.
  • claude_status{ "status": "working"|"idle"|"waiting"|"error" }.
  • finished{ "sessionId": string, "reason"?: string, "exitCode"?: number } — stream then closes. reason is no_upstream when the container never started, or already_ended when the run was over before you connected.
  • filetree[{ name, path, type, children? }] — workdir snapshot.

Content events

Every run publishes its content twice, in two independent forms. Read whichever suits you and ignore the other.

Rendered — one event type, always a string:

  • output{ "data": string }. On connect, the first output replays the buffered log so far, so a late subscriber sees the whole run.

Structured — the Claude CLI’s stream-json events, forwarded verbatim. These carry tool names and inputs, tool results, token usage and cost, none of which survive into output:

  • system{ "subtype": "init", ... }. Session setup: model, tools, MCP servers, working directory.
  • assistant{ "message": { "content": [...] } }. Content blocks are text, tool_use (with name and input), or tool_result.
  • user — same shape; carries tool results fed back to the model.
  • result{ "is_error": bool, "result": string, "total_cost_usd": number, "usage": {...} }. Terminal for the turn.
  • stream{ ... }. A structured event whose own type collided with a name this endpoint defines. Rare; the payload is unchanged.
  • stream_event — token-level deltas, only when the run or session was created with partialMessages: true. Anthropic’s streaming shapes: content_block_delta carrying a text_delta or thinking_delta, bracketed by message_start / message_stop. Thinking streams too, so a long reasoning pass is visible rather than silent.

Chat sessions

A session opened with POST /flows/{flowId}/sessions streams from this same endpoint — a session is an instance, so it has a stream like any run. Two further events apply:

  • session_ready{ "sessionId": string }. Setup is finished and the session will accept a message. Sent once, when the container comes up. You do not have to wait for it — a message sent during setup queues rather than failing — but it is the signal to show a ready state.

  • chat_output{ "text": string }. Reply prose as it is produced.

  • turn_end{ "exitCode": number, "sessionId": string }. End of one turn, not of the stream.

  • replay_truncated{ "instanceId": string }. You reconnected to a session whose replay buffer had already dropped frames, so the catch-up that follows has a hole in it. Backfill with GET /runs/{runId}/logs?format=structured&channel=chat rather than trusting what arrives after it.

Reconnecting

Drop the connection and reopen it and you are caught up: conversational frames are buffered per session and replayed in order, so you receive the reply text produced while you were away and any turn_end that fired during the gap. The turn itself never stopped — it is not tied to your connection.

The buffer is bounded, so a very long answer can outrun it. That is what replay_truncated is for; it arrives before the partial replay, never after.

turn_end does not close the connection. A session outlives its turns: keep reading and the next message’s output arrives here. Only finished means the session itself is over.

Unknown event names are forward-compatible additions — skip them rather than failing.

A : ping comment is sent every 15 s to keep proxies from closing the connection.

Browser EventSource clients can authenticate via ?api_key=....

event: system
data: {"type":"system","subtype":"init","model":"claude-opus-5"}

event: assistant
data: {"type":"assistant","message":{"content":[{"type":"tool_use","name":"Bash","input":{"command":"pnpm test"}}]}}

event: output
data: {"data":"[tool: Bash]\r\n"}

event: result
data: {"type":"result","is_error":false,"total_cost_usd":0.0412,"usage":{"input_tokens":18432,"output_tokens":901}}

event: finished
data: {"sessionId":"3f2b…","exitCode":0}

Authentication

Requires a project API key — see Authentication.

Parameters

NameInTypeRequiredDescription
runIdpathstringrequiredUUID of the run.

Responses

StatusDescription
200Event stream.
404Resource not found or not accessible to this project.

Tag: Streaming