Runs API
Runs record each occurrence of a job and every attempt to deliver it. Use these endpoints to build dashboards, export history, or debug failures.
The run object
{
"id": "run_01J9ZM1A…",
"job_id": "job_01J9ZK3Q…",
"scheduled_at": "2026-11-10T03:30:00Z",
"trigger": "schedule",
"status": "succeeded",
"attempts": 2,
"claimed_at": "2026-11-10T03:30:00.004Z",
"started_at": "2026-11-10T03:30:00.006Z",
"finished_at": "2026-11-10T03:30:21.410Z",
"next_attempt_at": null,
"start_lag_ms": 6,
"e2e_ms": 21410,
"sla_breached": false,
"last_error": null
}
| Field | Values |
|---|---|
trigger | schedule, manual, retry_manual |
status | running, deferred, succeeded, failed, skipped, cancelled |
See Jobs, runs and attempts for what each state and timestamp means.
List runs of a job
GET /api/v1/jobs/{id}/runs?status=failed&from=2026-11-01T00:00:00Z&to=2026-11-10T00:00:00Z&limit=50
Newest first, with run ID breaking ties at the same scheduled time. Pass next_cursor as cursor to continue a page (default 50, maximum 200). Filter by status, trigger, sla_breached=true, and a from/to range on scheduled_at.
List runs across the workspace
GET /api/v1/runs with the same filters plus job_id and tag.
Get a run
GET /api/v1/runs/{id} returns the run plus its attempts:
{
"id": "run_01J9ZM1A…",
"status": "succeeded",
"attempts": [
{
"n": 0,
"started_at": "2026-11-10T03:30:00.006Z",
"finished_at": "2026-11-10T03:30:01.010Z",
"duration_ms": 1004,
"outcome": "retryable",
"status_code": 503,
"error": "HTTP 503",
"request_summary": "POST https://api.example.com/reports (231 bytes)",
"response_body": "upstream unavailable"
},
{
"n": 1,
"started_at": "2026-11-10T03:30:11.300Z",
"finished_at": "2026-11-10T03:30:21.410Z",
"duration_ms": 110,
"outcome": "success",
"status_code": 200,
"error": null,
"request_summary": "POST https://api.example.com/reports (231 bytes)",
"response_body": null
}
]
}
response_body is null when it wasn’t stored (successful attempts by default) or has aged out. See Data retention.
Retry a failed run
POST /api/v1/runs/{id}/retry → 202 with the new run. Only runs with status failed can be retried; the new run has trigger = retry_manual, the same scheduled_at, and a fresh set of attempts. Repeated requests for the same occurrence coalesce into one manual retry; an exhausted manual retry returns 409 conflict.