Submit your first run
This page assumes an agent already exists in a workspace — see Agents if it does not — and that you have a service key for that workspace.
Throughout, https://your-deployment.example.com stands in for your deployment’s own host.
The path carries no version segment. Breaking changes are not made, only additive ones: a
field is retired with a Deprecation header and a sunset date at least 180 days out, never by
disappearing.
1. Check you can reach it
Section titled “1. Check you can reach it”curl https://your-deployment.example.com/system/health/system/health is liveness and touches no database, so it answers even when the platform is
having a bad day. /system/ready is the one that is allowed to fail — it checks that the
database schema is at the head this build expects.
2. Submit a run
Section titled “2. Submit a run”curl -X POST https://your-deployment.example.com/runs \ -H "X-Api-Key: $COBRE_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: order-4417-triage" \ -d '{ "agent_slug": "triage", "input": {"text": "the package arrived open"} }'Name the agent with either agent_slug or agent_id. input is an open object; what
belongs in it is decided by the agent’s own input schema, and an input that does not fit is a
422 naming the field.
You get 202 Accepted and a run in queued:
{ "id": "0190a2f4-…", "status": "queued", "agent_id": "…", "agent_revision_id": "…", "attempt_count": 0, "queued_at": "2026-08-15T12:00:00Z", "output": null}The response is the full RunView — the fields above are the ones you need first. Note
agent_revision_id: the run is pinned to the exact revision that produced it, which is what
makes a six-month-old run still explainable.
3. Collect the result
Section titled “3. Collect the result”Three ways, and they suit different callers.
curl https://your-deployment.example.com/runs/0190a2f4-… \ -H "X-Api-Key: $COBRE_KEY"Read status until it is terminal — succeeded, failed, timed_out or cancelled — and
then read output. Simple, works everywhere, and costs you a request per poll.
Wait for it inline
Section titled “Wait for it inline”Add response_mode: "sync" and a wait_seconds to the submission, and the call holds until
the run settles:
curl -X POST https://your-deployment.example.com/runs \ -H "X-Api-Key: $COBRE_KEY" \ -H "Content-Type: application/json" \ -d '{ "agent_slug": "triage", "input": {"text": "the package arrived open"}, "response_mode": "sync", "wait_seconds": 30 }'You get 200 instead of 202, with the settled run.
Two things this mode does that people get wrong:
- A synchronous wait also ends when the run suspends. A caller waiting on a human approval is told so, rather than left to time out.
- A wait that expires is a
504, and the run keeps running. The response carries the run id. Poll it or stream it — do not treat the504as a failed run.
Stream it
Section titled “Stream it”curl -N https://your-deployment.example.com/runs/0190a2f4-…/stream?after_seq=0 \ -H "X-Api-Key: $COBRE_KEY"Server-sent events, one frame per thing that happened, run.end last. Accumulate output text
from text.delta and nothing else. There is a WebSocket on the same path when you need one.
The guarantees, the resumption rules and the frame catalogue are on
Streaming a run.
4. Handle the refusals
Section titled “4. Handle the refusals”Four failures are worth handling by name before you ship:
| What it means | What to do | |
|---|---|---|
402 budget_exceeded | The workspace hit its ceiling. No run was created. | Stop. Retrying cannot succeed until a limit is raised. |
429 rate_limited | Too many submissions. | Back off. A Retry-After header is sent when the platform can say how long; it is advisory and may be absent. |
409 idempotency_in_flight | Your first attempt with this key is still running. | Wait a second and retry the same key. |
504 on a sync wait | The wait expired. The run did not. | Poll or stream the run id you were given. |
Every failure carries the same envelope and a code from a closed catalogue. Branch on the code, never on the message — see Errors.
The order things are checked in
Section titled “The order things are checked in”Which error you see is decided by a fixed gating order, and knowing it saves an afternoon:
- schema →
422 - agent visible →
404 - revision →
422 - persona →
422 - input schema →
422 - idempotency →
200/409/422 - budget →
402 - limits →
429 - insert
The budget check happens before any row is written, which is why a 402 leaves nothing
behind to look at.
Where to next
Section titled “Where to next”- Authentication — the other credential kinds, and what a role floor does.
- Conventions — pagination, partial updates, optimistic concurrency.
- SDKs — if you would rather not write this by hand.