Skip to main content
Everything that happens in a session is recorded as an ordered event: your messages, the agent’s replies, tool calls, status changes, and grader verdicts. This page covers sending events, reading them, streaming them live, and recovering a dropped stream. The TypeScript samples assume the rl client from Client setup.

Before you begin

  • You need the organization developer or admin role to send messages. 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.
  • You need a session id. See Sessions.

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 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 user.message with neither text nor content is dropped without an error. The request fails with 400 only when every entry is dropped. Compare events_accepted with the number of events you sent. 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.

Hand a browser step back

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.

What the response means

The response confirms that your turns were stored. It does not include the agent’s reply; read that from the events or the stream. 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.

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.
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. Pass it as after_event_id for the next page. An empty token means you have read everything that exists right now. 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.

Event fields

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. It has no SDK method; call it with fetch or cURL. The URI must come from an event in the same session tree.
Open the session. 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.

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.

Frames

Each event is sent as event: <type>, id: <event_id>, and data: <json>. The 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.

Stream errors

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. The TypeScript helper accepts records up to 8 MiB and throws on larger ones. If that happens, 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.

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. Take one snapshot, draw it, then keep it current with the gestalt stream. Use it instead of polling listSessions or opening one event stream per session.
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. 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. It has no SDK method.
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. The gestalt stream never closes on its own otherwise, so close it when your dashboard is done.

What can go wrong

Every error uses the same body: code, message, and details with field, requestId, and retryable. See Errors.

Limits

  • Referenced sessions: 10 per message.
  • Event pages: about 8 MiB each.
  • Stream keep-alive: a ping every 15 seconds.
  • Gestalt: 5,000 sessions per snapshot, 30-day window (400 days with agent_id).
See Limits for the rest.

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.