Skip to main content
Three endpoints execute an agent, and they share one request shape, one option set, one error envelope and one stream contract.

POST /responses — stateless

No conversation is named and none comes back. Internally a conversation is opened on the api channel because a turn needs somewhere to live, and no messages are written to it — so the request leaves a record that it happened and what it cost, and no copy of what was said.

POST /agents/{id}/runs — a payload and a task

For work that is not a conversation: an object to reason over plus a line saying what to do with it.
The structured payload reaches the model in the user message — fenced and labelled — and never in the system prompt. That is one code path for every entry point on the surface, so a payload cannot become an instruction. Read a run back with GET /agents/{id}/runs/{run_id}, which needs agents:read. Reading a run is a different authority from starting one.

The input

  • channel decides both rendering and which ledger line the turn bills to. "" means “not stated” and falls through to the conversation’s own channel — it is not a synonym for api. Values: api, web, website, whatsapp, phone, voice.
  • attachments carry a ref to something already stored. Never bytes.
  • request_context is caller-supplied context. The one key the runtime acts on is resource_id, which narrows the execution context to that resource — and raises rather than narrowing to nothing when the caller could not reach it. That refusal is invalid_context, a 403.
The input carries no identity field of any kind. Who you are comes from the credential.About thirty reserved keys are refused by name inside request_contexttenant_id, company_id, scopes, permissions, entitlements, billed_to, principal, role, token, usage_category and the rest. They are refused rather than dropped silently, so a caller who believed one of them worked finds out on the first call instead of in production.

The options

Send them flat in the body or nested under options; both are read and the nested value wins. An unrecognised key inside options is a 400.
The three policy fields can only ever subtract. There is no value meaning “retrieve more than this agent is configured for”, or “use a tool this agent does not have”.
timeout_ms out of range is refused, not clamped. A caller who asked for ten minutes and silently got sixty seconds reads the resulting timeout as a platform fault.

What you may not set

These are refused with a 400 that names the field and gives the reason, because each is one a caller reasonably expects to work and the answer is a decision rather than an omission.

The response

status is one of six: queued, running, completed, failed, cancelled, blocked. Four of those are terminal — completed, failed, cancelled, blocked. Anything else is still in flight and a caller polling it may see it change. id is the public run id (run_…) and is the same id the stored run carries, so a caller quoting it in a ticket lands on one row. Database primary keys are never exposed.

Cancelling

Needs responses:create. Any run you may read can be cancelled here, not only ones from POST /responses — the ids are one namespace. Two success statuses, and the difference is information rather than success:
  • 202 — the run was in flight and will stop at its next checkpoint.
  • 200 — there was nothing left to stop.
Cancellation is cooperative, so 202 is the honest code for “accepted” rather than 204. It is idempotent: a second call answers the same way as the first, and a call for a finished run answers 200, because “it already stopped” is the outcome you wanted. A run that reached a terminal status is left exactly as it is — a cancel that lost the race does not reopen it. A cancelled run returns no output. You asked for it to stop; handing you a partial answer as though it were the answer is how a cancelled report ends up quoted in a board pack.

Preview and drafts

"preview": true runs the agent’s unpublished configuration. Asking is free; being allowed is not.
Preview needs the agent:preview scope, which is issued on its own and is implied by nothing — a key that may edit an assistant does not thereby preview its drafts.
Without permission the answer is 404, not 403. Confirming that a draft exists but may not be run is exactly the confirmation the not-found rule exists to withhold.
Statuses a preview run may execute: active, draft, paused, preview. Without preview, only active — asking for anything else is agent_not_available, a 409.