Skip to main content
A session is one directly-controlled run of an agent. You create it, send input, stream events, interrupt it, and cancel it. Sessions are durable — they can run for a long time and sit idle at storage cost only.

The session object

string
Unique id (e.g. ses_01H...).
string
The agent this session runs.
integer
The pinned agent version.
string | null
The deployment that created this session, if any.
string | null
The persona this session acts as, or null when the create call named none.
string | null
The computer this session provisioned for its filesystem and shell tools, or null when its toolset needs none. It is a real computer — it lists under GET /v1/computers as session {id} and takes exec, snapshot and fs/* — but it belongs to the session: DELETE on it is refused while the session can still run, and it is destroyed when the session ends.
string
Lifecycle state — see below.
string | null
Why the last turn yielded control — see below. Read it whenever the session is not running; do not treat idle as success.
string
Effective completion window for this session.
integer
Per-session cap, in micro-USD. Always set: it falls back to the agent’s budget.max_task_micro_usd.
integer
Cumulative spend on this session so far, in micro-USD.
object
Cumulative token counts across five billed tiers.
object[]
What the session is parked on. One array, two kinds of row, distinguished by kind — which defaults to "tool", so a row without it is a held tool call.A kind: "tool" row is resolved with tool confirmations and accompanies stop_reason: "awaiting_approval". A kind: "question" row is resolved with answers and accompanies awaiting_answer. A session parked on both reports awaiting_approval and carries both.
object | null
JSON Schema the final result must satisfy, inherited from the agent unless overridden at create.
object | null
The typed result, populated when the session goes idle satisfying output_schema. See Structured outputs.
integer
Highest event seq emitted so far. See Events.
object
Arbitrary key/value pairs.
string | null
When the session first started running.
string | null
When the session reached a terminal state (completed, failed, cancelled).
string
Creation timestamp.

Lifecycle

A session moves through these status values: Whenever a turn yields control, stop_reason is set to one of:
idle is resumable and completed is terminal — both are non-running. Always branch on stop_reason rather than treating idle as success. Anything worth keeping is written to Files; scratch work stays in the sandbox.

Create a session

POST /v1/sessions201 Created. Creates and starts the session. Inherits the agent’s configuration; you may override the window, set a per-session budget, and provide an initial message.
string
required
The agent to run.
integer
Pin a specific version. Defaults to the agent’s current_version.
string
required
Initial input. Starts the first turn immediately.
string
Override the completion window (immediate | priority | loose).
integer
Per-session cap in micro-USD. Work pauses at the cap.
string
Attribute this session to a deployment, so its spend shows under that schedule in the ledger. Defaults to null.
string
The persona this session acts as — an idn_ id or the persona’s name. The agent must hold a grant to it. Defaults to null.
object
JSON Schema the final result must satisfy. Overrides the agent default. See Structured outputs.
boolean
When true, a session that cannot produce a conforming object goes idle with stop_reason: "error". Overrides the agent default; requires an output_schema on the session or the agent.
object
Arbitrary metadata.

Retrieve a session

GET /v1/sessions/{id}200 OK with the current status, stop_reason, and usage.
Response

List sessions

GET /v1/sessions200 OK, cursor-paginated. Filter with ?agent_id=, ?deployment_id=, and ?status=. See Pagination.

Send input

POST /v1/sessions/{id}/messages202 Accepted. Sends input to a session and produces events. The reply is the acceptance, not a session snapshot: the turn has not run yet.
string
required
The message text to send.
boolean
When true, steer a running session in one call: the current turn stops at its next commit boundary and the new message is applied. This is the common case. Defaults to false.
string
Accepted and ignored. De-duplicate a retried send with the Idempotency-Key header — see Idempotency; this body field does nothing.
Without interrupt, sending to a running session returns 409 with code session_running — interrupt first, or set interrupt: true.
Response
accepted_seq is the session’s event high-water mark at the moment the send was accepted: every event this turn produces has seq > accepted_seq. That is what to wait on — poll GET /v1/sessions/{id}/events?after_seq=143, or wait for the session’s last_seq to pass it. Do not wait on status alone: the send returns before the first event is committed, so a status read taken immediately after can still describe the previous turn.

Interrupt a session

POST /v1/sessions/{id}/interrupt200 OK. Stops the current turn at its next commit boundary, preserving history and the sandbox, and returns the session idle with stop_reason: "interrupted". An optional message is applied as the next input. Unlike cancel, the session stays resumable.
string
Optional input to apply after interrupting.
Response

Respond to a tool confirmation

When a tool with permission: "ask" runs, the session goes idle with stop_reason: "awaiting_approval" and the blocking calls appear in pending_actions. Resolve each with: POST /v1/sessions/{id}/tool_confirmations202 Accepted, carrying the full session object with the resolved call removed from pending_actions. Like a send, the reply is the acceptance: the tool has not run yet.
string
required
The id from pending_actions[].tool_call_id (also carried on the tool.confirm event).
string
required
allow to run the tool, or deny to reject it.
string
On deny, fed back to the model as the tool result.
Response

Answer a question

An agent that needs something from a person parks the turn: the session goes idle with stop_reason: "awaiting_answer" and the question appears in pending_actions as a row with kind: "question", carrying a prompt and one to three fields. Answer it with: POST /v1/sessions/{id}/answers202 Accepted, carrying the full session object with the answered question removed from pending_actions. Scope sessions:write.
string
required
The id from pending_actions[].tool_call_id on the row you are answering.
object
required
One entry per field, keyed by fields[].key. A string, or an array of strings for a choice field with multiple: true. Every field must be answered.
This is a separate route from tool_confirmations, not a variant of it. A held tool call is answered with a verb and no payload; a question is answered with a payload and no verb. Posting an answer for a kind: "tool" row is rejected with validation_failed (400) naming tool_call_id, and points you at the other route. A choice field accepts anything the person types unless it sets other: false, in which case only its listed options are accepted. The values are read back by the model as words, so send the option text and not an index.
Response

Raise the budget

PATCH /v1/sessions/{id}/budget200 OK. Scope sessions:write. A session that hit its cap stops with stop_reason: "budget_paused". Raise the cap and it becomes resumable.
integer
required
The new per-session cap, in micro-USD.
Raise only. A cap at or below what the session has already consumed is rejected with validation_failed (400) — lowering it would be retroactive, charging a limit against spend that already happened.
Returns the full session object with the new budget_micro_usd. Errorsvalidation_failed (400) for a cap that is not a raise; not_found (404); insufficient_credits (402) when the organization cannot cover the new cap.

Cancel a session

POST /v1/sessions/{id}/cancel200 OK. Terminally stops the session and moves it to cancelled. Any in-flight turn is stopped. Use interrupt instead if you want to keep the session resumable.
Response

Stream events

List and stream a session’s events, resumable by seq.