List events
Response:
Stream events
after with the last
durable numeric sequence already loaded from event history to avoid replaying
older events on the initial connection.
event name and the event
envelope as JSON data.
Reconnect and resume
Treat the SSEid as an opaque transport cursor, not as the event’s numeric
sequence. Browsers automatically send it back as Last-Event-ID when an
EventSource reconnects to the same URL.
Some replayed history frames may not include an SSE id. The live stream is
therefore not the source of truth for complete history. On every new connection
or reconnect:
- Open the SSE stream and buffer incoming frames.
- List durable events using
GET /events?after={lastSequence}. - Merge the history response and buffered frames by event
id, then advance your numeric sequence cursor. - Continue consuming the live stream.
- Let the SSE client preserve
Last-Event-ID; do not parse or synthesize it.
after query parameter and event sequence belong to durable history. The
SSE id and Last-Event-ID belong to live transport resume.
Event envelope
List and stream responses wrap every payload in the same event envelope:
For inbound
user.message events, payload is the accepted event. If the event
included metadata, it is returned as payload.metadata. Metadata is persisted
turn context and is not part of the visible payload.content text. If the event
included attachments, the attachment metadata and dataUrl source are included
in that payload so the event is auditable.
Usage snapshots
When available, terminal turn events include ausage object with the usage for
that completed turn. This is the right object to forward to observability systems
such as Langfuse for per-generation token and cost reporting. Session responses
also expose an aggregate usage object for lifetime session totals.
cost_usd is omitted when pricing is unavailable; cost_status explains whether
the cost is estimated, included, or unknown. last_turn_latency_ms measures
the wall-clock time for that completed turn. context_* fields describe the
current context window at the end of the turn; they are not billable deltas.
Event categories
See the Events Reference for schemas and examples.
Required actions
When asession.status_idle event has payload.stop_reason.type set to
requires_action, the turn is paused until your application sends the matching
user event.
Clarify requests
When the agent uses theclarify tool, the stream emits an agent.clarify_request followed by a session.status_idle with stop_reason.type: "requires_action". The turn is paused until you answer.
payload.choices is a list of multiple-choice options, or null for an open-ended question. Answer by sending a user.clarify_result event with the request_id and the user’s answer (an empty answer skips the question, letting the agent proceed with its own default). The paused turn then resumes and continues streaming.
Custom tool requests
When the model calls one of your custom tools, the stream emitsagent.custom_tool_use, then session.status_idle with requires_action. Your
application should execute the tool and send user.custom_tool_result.
session.tool_updated is emitted and how clients reconcile the ephemeral
patch with durable event history.
Automatic title updates
When you create a session without atitle, the agent generates a short, descriptive one from the first exchange (see Sessions). When the title is ready, the stream emits session.title_updated; update your UI from payload.title:
GET /events
and replayed on reconnect. It also updates the session’s title field. Manual
titles are authoritative: if you create or update a session with an explicit title,
the automatic title is not applied. To read the current title at any time, call
Get a session.
Send events
UsePOST /v1/sessions/{sessionId}/events to send user input and control events. See Send Session Events.

