Skip to main content
Everything that happens in a session is recorded as an ordered event: your messages, the agent’s replies, tool calls, and status changes. Send events to steer a session, and stream or list them to follow it.
You need a session id; see Sessions. Sending messages needs the organization developer or admin role. The organization user role can read and stream events. The billing role cannot see sessions. See Organizations and roles. For API calls, create a key under API keys; see API keys.

Send messages

sendSessionEvents adds turns to a session. Send message for one plain-text turn, or events for typed turns. If you send both, events wins and message and the top-level actor are ignored.
Open the session, type in Message the agent…, and click Send. While the agent is working the button reads Queue, and Interrupt & send appears beside it.
The response confirms that your turns were stored. It does not include the agent’s reply; read that from the stream or the event list. Compare events_accepted with the number of events you sent.
A user.message with neither text nor content is dropped without an error. If every entry is dropped, the request also fails with 400.The top-level referenced_session_ids grants the session read access to up to 10 earlier sessions from this turn on. If you cannot read one of them, the whole request fails with 404 and no message is delivered. See Referenced sessions.A top-level image or document block can name a file from your library instead of carrying bytes. See Show a file to the agent in a message.A message to a session that is still being cancelled returns a retryable 409 conflict. A message to a subagent session in a terminal status also returns 409 conflict, because only root sessions resume.
To retry a send after an ambiguous network failure without adding the turn twice, send one stable Idempotency-Key header and resend the same request. See Idempotent mutations.
When a session is awaiting_human, the agent is waiting for a person to handle a step in its browser display, such as a sign-in. Its active_handoff names the request. Send a handoff_resolved event with that handoff_id to let the agent continue, with an optional note of up to 2,000 characters telling it what you did. It must be the only event in the request.
A handoff_id that doesn’t match the active hand-off, or a session with none, returns 409 conflict. Without this event, the agent resumes on its own when the hand-off deadline passes.

Stream events

streamSessionEvents is a server-sent events (SSE) stream of a session’s events as they are recorded. It replays everything after your cursor first, then stays open for new events. The stream closes on its own only when the session reaches a terminal status: completed, failed, or cancelled. An interrupted or sleeping session keeps it open.
Open the session. The transcript streams live.
Each event is sent as event: <type>, id: <event_id>, and data: <json>. Save the id of each frame you handle: it is your position if the connection drops. See Recover from a dropped stream.
The frame’s JSON has type, id, session_id, session_thread_id, processed_at, content, stop_reason, usage, error, anchor_event_id, and raw_event, which holds the full stored event.The stream also sends frames without an id. These are not stored events and do not move your position:
  • : connected is the first line. : ping follows every 15 seconds. They keep the connection alive; ignore them.
  • When you connect to a running session, a session.status_running frame tells you the current state.
  • When the session reaches a terminal status, the stream sends one last session.status_idle (completed) or session.status_terminated (failed or cancelled), with stop_reason and, on failure, error. Then it closes.
The Content-Type of the response is text/event-stream; charset=utf-8; max-record-bytes=<N>, where <N> is the largest record the server may send. Size your SSE parser’s buffer to that value. If a record is larger than your client accepts, list events after your last id with payloads=refs, then resume the stream after the event you fetched.

Recover from a dropped stream

Networks drop connections. The stream is designed so you can reconnect without losing events.
1

Track the last event you finished processing

Save a frame’s id only after you have handled it. Frames without an id never change your position.
2

Reconnect from that id

Reconnect with Last-Event-ID: <id>, or with after_event_id=<id> in the URL. The server replays every event after it. If you use after_event_id, update it on every reconnect; reusing the original URL replays from the original position. A malformed id returns 400. A well-formed id from another session does not fail; it is treated as a position.
3

Back off between attempts

Retry with exponential backoff and jitter. A 503 means the server is at its stream capacity; retry after a short wait.
4

Deduplicate by event id

Replays can repeat an event you already saw, so keep a set of handled event_id values and skip repeats.
5

Reconcile when the session ends

When several agents write at once, an event can be recorded slightly after a later-sorting event was already sent to you, and a cursor reader can miss it. After the stream closes at a terminal status, page through listSessionEvents from the start and add any event id you have not seen.
If your process restarts and loses its place, list events with listSessionEvents to rebuild state, then open the stream with after_event_id set to the last id you listed.

List events

listSessionEvents returns events oldest first, in pages. Any session id in a tree returns the combined timeline of the whole tree, including subagents.
Open the session. The transcript shows every event, and the Events tab lists them with their raw fields.
To read the next page, pass next_page_token as after_event_id. An empty token means you have read everything that exists right now.
Any other value for hydrate, image_urls, or payloads returns 400.Pagination. next_page_token is always present and equals the id of the last event on the page. A short page with a non-empty token does not mean the end. events can be null on the last page.Event ids. Event ids sort in the order events were created, so an id works as a position. An after_event_id that is well formed but not in this session is not an error: you get the events that sort after it.Oversized events. An event too large for a page is returned alone, with content_hydration_status: oversized. Fetch its full content with Get full event content.

Get full event content

getSessionEventContent returns the full content of one event. Use it for oversized events or payload references. The event must belong to the session. The response carries an ETag.

Get an image

Image blocks in events carry an image URI. getSessionImage returns the image bytes for it, with the image’s media type. Call it with an HTTP client or cURL. The URI must come from an event in the same session tree. In the console, images show inline in the transcript.
To skip this call, list events with image_urls=signed and download from each block’s short-lived url.

Watch many sessions with the gestalt

The gestalt is a live, compact summary of every root session in a time window: its status, execution state, and last activity. It is built for dashboards and alerting. Use it instead of polling listSessions or opening one event stream per session. Take one snapshot, draw it, then keep it current with the gestalt stream.
since is required, in RFC 3339 format. It can be at most 30 days ago, or 400 days ago when you also pass agent_id. Keep the snapshot’s as_of for the stream.
Sessions are ordered newest first by creation time. A row has failed: true when the session ended in a failure. truncated: true means only the newest 5,000 were returned; narrow the window or add agent_id. Both fields are left out when false.

Keep the snapshot current

Open streamSessionGestalt with the same since and agent_id, and after set to the snapshot’s as_of.
On each gestalt.change frame, replace each row by session_id and remove rows with deleted: true. The gestalt stream never closes on its own otherwise, so close it when your dashboard is done.
To reconnect, send the last frame id as after or as the Last-Event-ID header. One of them is required. A stream position older than 30 days is rejected; take a new snapshot.

What can go wrong

The most common problems:
  • The reply never arrives after delivery_state: queued. The agent is still on its current turn. Wait, or interrupt the session.
  • events_accepted is lower than the events you sent. Some entries were dropped. Check each entry’s type and content.
  • The stream replays the same events after every reconnect. The URL still has the original after_event_id. Update or remove it on reconnect.
  • The stream stays open after the agent stopped. The session is interrupted or sleeping, not terminal. Close the stream yourself, or cancel the session.
Every error has required code and message fields plus optional details. When present, details can include field, requestId, retryable, and code-specific context. Use the generated Endpoints reference for exact alternatives and Errors for recovery guidance.
Limits on referenced sessions, event pages, stream keep-alive, and the gestalt are in Limits.

Next steps

Sessions

Start, interrupt, cancel, and delete sessions.

Session operations

Pending inputs, compute usage, the analyst, and the session tree.

Multi-agent sessions

Read events across threads and subagents.

Deliverables and artifacts

Ask for deliverables and see how they’re kept.