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.
- Console
- cURL
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.
events_accepted with the number of events you sent.
Event fields and send rules
Event fields and send rules
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.Retry a send safely
Retry a send safely
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.Hand a browser step back
Hand a browser step back
When a session is A
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.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.
- Console
- cURL
Open the session. The transcript streams live.
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.
Stream parameters
Stream parameters
Every frame type
Every frame type
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:: connectedis the first line.: pingfollows every 15 seconds. They keep the connection alive; ignore them.- When you connect to a running session, a
session.status_runningframe tells you the current state. - When the session reaches a terminal status, the stream sends one last
session.status_idle(completed) orsession.status_terminated(failed or cancelled), withstop_reasonand, on failure,error. Then it closes.
Stream errors and record size
Stream errors and record size
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.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.
- Console
- cURL
Open the session. The transcript shows every event, and the Events tab lists them with their raw fields.
next_page_token as after_event_id. An empty token means you have read everything that exists right now.
List parameters and paging
List parameters and paging
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.Event fields
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. 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.
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 pollinglistSessions 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.
Snapshot fields
Snapshot fields
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
OpenstreamSessionGestalt with the same since and agent_id, and after set to the snapshot’s as_of.
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.
Gestalt frames and reconnecting
Gestalt frames and reconnecting
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_acceptedis lower than the events you sent. Some entries were dropped. Check each entry’stypeand 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 events error
Every events error
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.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.