Skip to main content
/api/v2/ is the surface external developers are meant to call. Where /api/v1/ exposes the platform’s own resources — leads, widgets, knowledge cards — v2 exposes executions: you ask an agent for something, and you get a run with an id, a status, a cost and a trace.
It is additive. /api/v1/ is unchanged and is not deprecated by anything here.

Four products, one contract

Runtime

/responses, /conversations, /agents/{id}/runs. Stateless replies, durable transcripts, and non-conversational agent runs. All three take the same options and stream with the same events.

Documents

/documents. Upload a file, parse it once, read the parsed representation, hand out expiring download links.

Intelligence

/extractions and /reports. A document plus a JSON Schema becomes validated fields with evidence; an agent plus a task becomes a report.

Operations

/jobs, /logs, /webhooks. Poll long work, read what an execution actually did, and get told when something finishes.
Knowledge sits across the line: /knowledge/ingestions is the one place a stored document becomes something an agent can retrieve.

One shape, everywhere

Learn these four things once and every endpoint on the surface behaves the same way. Two conventions that surprise people, stated here so they surprise nobody:
Both are 404, byte for byte. There is no 403 that confirms existence, because a 403 turns id-guessing into an inventory.The one place this reads oddly is preview: a caller without the agent:preview scope asking for a draft gets 404, not 403. Confirming that a draft exists but may not be run is exactly the confirmation the rule exists to withhold.
A workspace out of credits has not had a model failure — nothing went wrong upstream, the platform declined to spend. usage_blocked (402) and rate_limited (429) both end a run as blocked. Every other error code ends it as failed.Filing the two together is what makes an error-rate dashboard useless.

What the caller does not control

The runtime chooses the model, the provider, the sampling parameters and the prompt. A request that tries to set one of them is a 400 that names the field and says why — not a silently ignored key:
The complete list of what a caller may set is seven fields — stream, response_format, tool_policy, memory_policy, knowledge_policy, timeout_ms, preview — and the three policy fields can only ever subtract. There is no value meaning “retrieve more than this agent is configured for”.
Identity is never in the body. Who you are comes from the credential. The runtime input refuses about thirty reserved keys — tenant_id, scopes, billed_to, principal, and the rest — by name rather than dropping them quietly, so a caller who believed one of them worked finds out immediately.

Why the endpoint reference can be believed

The endpoint reference under Endpoint reference in this tab is not written by hand. It is generated from the running code by manage.py openapi and gated in CI by manage.py openapi --check, which regenerates the document in memory and refuses a build where the checked-in file and the code disagree. Nothing non-trivial in it is typed by a person: --check also refuses a document that documents a scope no key could ever be issued, that describes a route that is not wired, or that leaves a routed scoped operation undescribed.

What it is honest about not being finished

A generated document is only worth the gaps it admits to. Two are worth knowing before you write a client.
There are four mechanisms, and each operation documents the one it actually takes:
  • /logs returns next.
  • /documents, /extractions, /reports and /knowledge/ingestions return next_cursor and read it back as cursor.
  • /conversations/{id}/messages returns next_cursor, reads it back as after, and its cursor is a message id rather than an encoded pair.
  • /jobs pages by offset and returns no cursor at all.
Cursors are opaque base64url. Do not build one: a raw ISO timestamp is not a cursor, because +00:00 decodes to a space in a query string and silently breaks every second page.
/responses, /conversations and /agents/{id}/runs set Idempotency-Replayed. /jobs, /extractions, /reports and /knowledge/ingestions set Idempotent-Replay. POST /documents sets neither and signals a replay by answering 200 where a create answers 201.Read each operation rather than assuming one name. A client checking for the wrong header reads every replay as a fresh execution — which for a create is the one conclusion idempotency exists to prevent.
Some Phase 4 request bodies list the field names their handler reads and pin no types. That is a stated gap, not licence to send anything: the endpoint answers 400 with a message naming the problem.

Where to start

1

Get a scoped key

Authentication — and grant the minimum scopes the caller needs, because that is what decides how bad an exposure is.
2

Make one call

Quickstart — a single response, then the same call streamed.
3

Read the endpoint you need

The generated reference in this tab has a request playground for every one of the 52 operations.