ReferenceHTTP APIEvents

Durable event replay and live stream (SSE)

GET
/v1/sessions/{id}/events

Streams the session's events as Server-Sent Events: first the stored events after Last-Event-ID (all of them without it), then new ones as they are written. Each frame's id is its cursor, event its kind (system, assistant, tool_use, tool_result, question, result, status, error), and data a versioned envelope naming the session, turn and attempt. Frames arrive in id order, the order to rely on; a new event's occurred_at is no earlier than the one before it. An event the engine emits after its turn's terminal belongs to no turn (turn_id null). question events announce pending requests; status events report the session's status and, after a pause, resume, terminate or recovery decision, its admission_state. system events with a platform subtype are the control plane's own: session_closed when a close commits, and input_wait with stage (parked when a turn parks on its unanswered requests, expired when a parked turn's requests expire, lost when the worker holding them went away unanswered) and the request_ids it covers. The stream does not end with a turn or the session: it stays open until the client disconnects, the credential is revoked, or the session's share stops covering the caller (the reconnect then answers 404). Reading changes nothing.

Reconnect after backoff with the last complete event id in Last-Event-ID; replay resumes strictly after that event. The stream sends a comment keepalive every 15 seconds. 410 CURSOR_EXPIRED means the cursor fell outside retained history and the client must resynchronize from resource state; alpha does not trim events, so this response is reserved. A result event is engine output, not durable completion: confirm the turn with GET /v1/sessions/{id}/turns/{turn_id} and treat only completed, failed, interrupted, cancelled, or outcome_unknown as terminal.

Scope: sessions:read (API key or cookie session).

Authorization

headerAuthorizationBearer <token>

For servers and scripts: an API key sent as an HTTP bearer token, Bearer <key>. It holds exactly the scopes it was issued with; a key issued before scopes existed holds none. It never needs the CSRF header, and it cannot manage agents, members, teams or API keys. Issue one in the web console under Settings → API keys; each operation names the scope it needs.

Scope: sessions:read

Path Parameters

id*string

The session's id.

Match^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
Formatuuid

Header Parameters

Last-Event-ID?string

The id of the last complete event received. Replay resumes strictly after it; omit it (or send it empty) to replay from the start. A malformed value answers 400 BAD_REQUEST.

Length1 <= length

Response Body

text/event-stream: one frame per event, each an id:, an event: and a data: line, with the envelope as JSON on the data: line.

text/event-stream
  1. response
id*string
Length1 <= length
event*string
data*
Example Request
curl -X GET 'https://example.com/v1/sessions/497f6eca-6276-4993-bfeb-53cbbbba6f08/events'
Example Response
{  "id": "ev_2s",  "event": "status",  "data": {    "schema_version": 1,    "session_id": "0f8b6a52-3d1e-4c7a-9b2f-5e6d7c8a9b01",    "turn_id": "2",    "attempt_id": "att_01",    "occurred_at": "2026-10-11T08:14:02Z",    "data": {      "phase": "running"    }  }}