Jobs
Long-running tools run as jobs with a durable ID. They never spin forever in your HTTP request.
Starting a job
Tools of kind async_job (and tools that support async) return 202 with a job object when you execute them with "async": true:
json
{ "request_id": "…", "status": "queued", "tool": "…", "tool_version": "…", "data": null,
"billing": { "state": "reserved", "reserved_usd": "0.50", "charged_usd": null, "currency": "USD", "final": false },
"job": { "job_id": "…", "status_url": "/v1/jobs/…" } }Polling
text
GET /v1/jobs?status=&cursor=&limit= (jobs:read) → { items: JobRecord[], next_cursor }
GET /v1/jobs/{jobId} (jobs:read) → JobRecord
GET /v1/jobs/{jobId}/result (jobs:read) → artifact bytes, original content-type
POST /v1/jobs/{jobId}/cancel (jobs:write) → JobRecordJobRecord.status is one of queued, running, succeeded, failed, cancelling, cancelled. billing carries the same states as synchronous requests; the hold is captured or released when the job finishes.
Cancelling
Cancellation is best-effort: work the supplier already performed may still be billed. The final receipt on the job tells you what was charged.
Webhooks
Subscribe to job.completed and job.failed instead of polling. See Webhooks.