content array, or a text value over 20,000 characters — rejects the whole
request with 400 validation_error. Nothing is truncated, and the error message
names the failing field and limit. See
Text content block.
A user.message starts a new turn, and a session runs one turn at a time: by
default a prompt sent while a turn is running is rejected with 409. Set the
request-level delivery field to "when_idle" to queue the prompt instead — see
Queue a message while a turn is running.
Send a message
metadata is optional turn context for the agent. It is persisted on the
user.message event payload and returned by list/stream APIs, but it is not part
of the visible content text your UI renders as the user’s message. Metadata
values must be strings, numbers, booleans, or null.
Send a message with attachments
user.message accepts up to 10 turn-scoped file attachments. Attachments are
sent as base64 data_url sources. The accepted event, including each
source.dataUrl, is retained in session event history.
analysisMode: "visual" on a PDF attachment
only when you want page-image analysis.
Limits: images, CSV, TXT, Markdown, and DOCX are capped at 25 MB per attachment;
PDFs are capped at 50 MB.
Queue a message while a turn is running
By default, sending a prompt-starting event while a turn is already running fails with409 invalid_state (“A turn is already in progress”), and your application
owns the retry. When your caller means “deliver this whenever the agent can take
it” — for example a background job posting a completion notification into a
session — set the request-level delivery field to "when_idle":
With
"when_idle":
- If the session is idle, the prompt starts a turn immediately — exactly like an immediate send.
- Queued prompts start oldest-first, one per turn end, and each runs as its own turn.
- The
202response echoes the persisted events;data[].status === "queued"tells you the prompt was parked rather than started. The status moves toreceivedwhen its turn starts, thenprocessedlike any other prompt. - Queued prompts remain durable until they are delivered once the session is idle again.
when_idle request must contain only prompt-starting user.message events.
Control and result events (user.steer, user.approval_response, and so on)
target the currently running turn and are never queued for a later one, so a
when_idle request that includes them is rejected with 400 validation_error —
send them in a separate request with the default delivery.
Rate-limit counting
The agent’s message limit defaults to 100 accepted inbounduser.* events per
stable subject (subjectId) per fixed 60-second window. Every event in a request
consumes one point from this allowance.
- Immediate events count when they are accepted for persistence.
- A
delivery: "when_idle"prompt counts when it is accepted into the durable queue. It is not counted again when the queue drains. - Validation, not-found, archived-session, and prompt-conflict failures rejected before persistence do not count. A control event that is persisted but cannot reach a live turn does count.
user.steer,user.interrupt,user.approval_response,user.clarify_result, anduser.custom_tool_resulteach count.
RateLimit-Limit,
RateLimit-Remaining, and RateLimit-Reset. See
Rate limits and
Errors.
Supported inbound events
See the Events Reference for the
complete schema for each event.
Action responses
When the stream emitssession.status_idle with
payload.stop_reason.type: "requires_action", the event_ids array contains the
IDs your application needs to answer.
Confirm a tool request
result is allow or deny. scope is optional and can be once, session,
or always; omit it to allow once.
Answer a clarify request
answer to skip the question and let the agent continue with its
own default.
Return a custom tool result
Custom tools are executed by your application, not by the managed agent. When the stream emitsagent.custom_tool_use, execute the named tool and return the
result with user.custom_tool_result.
is_error: true when your application could not complete the tool. The text is still sent back to
the model as tool output, so include a concise, model-readable error message.
For long-running workflows, return a kickoff result within approximately five
minutes:
tool_use_id:
session.tool_updated, and starts a new agent turn with the final
text. It cannot use delivery: "when_idle"; wait for
session.status_idle before posting it. See
Long-running custom tools for the complete
flow, UI reconciliation, and retry constraints.
Response
The endpoint returns the events persisted by the request. Additional agent events can be retrieved with List Session Events or streamed with Stream Events. A message parked bydelivery: "when_idle" is returned with
status: "queued" instead of received.

