GET /v3/organizations/{orgId}/sessions/{sessionId}/events returns a Session’s activity in pages. It is a poll, not a stream: each call returns the events after a cursor, and with wait_ms it waits for the next one.
What you will have
- A loop that reads every event exactly once in transcript order.
- A rule for handling the same event coming back on a later page.
Prerequisites
Create or open a Session, and have an API key withsessions:read. See Build a chat UI on the API.
The cursor
Start withafter_seq=0. Each response returns:
items: the events after the cursor, in ascendingseq.next_seq: the last item’sseq, or the same cursor whenitemsis empty.session: the current status (running,exit,errororsuspended) andoutcome.
next_seq as the next after_seq. Stop when a page’s items is empty and session.status is no longer running. Add wait_ms (for example 20000) so an empty page waits for the next event instead of returning at once.
The same event can come back
A streamed event (a reply, reasoning, or a tool’s live output) keeps itsid. Each time its content grows, it returns with a higher seq. So a poller can receive one id on more than one page.
Keep the copy of each id with the highest seq. That copy has the most complete content.
Order by position, not seq
seq is a delivery cursor. It is not the order things happened in. Sort by position to get the transcript:
positionis theseqan event first appeared at.- It never changes for an event, and no two events in a Session share one.
seq than an event that happened after it. Sorting by seq would put it in the wrong place.
Numbers are not counts
seq and position jump by about 4.29 billion (2^32) when a follow-up, a retry, or a machine change starts a new attempt. They also have gaps where an event is hidden. Compare them and sort with them. Do not count with them or show them to a person.
Event types
Each event has atype:
Without
sessions:debug, data carries a fixed set of fields (for example tool, input, content, is_error, duration_ms). An owner or admin with sessions:debug gets the full diagnostic projection.
To read only the conversation, add view=conversation. It returns only assistant, reasoning, tool_use and tool_result events, and it does not move the cursor.
Working code
The chat UI sample implements this: aMap keyed by id that keeps the highest seq, a cursor loop with wait_ms, and a sort by position.

