# Runs API

> Create, retrieve, list and cancel runs over HTTPS. The same operations the SDKs and the CLI use.

Source: https://galley.themes.dev/docs/reference/runs-api/

A run is one execution of a job or workflow. Use these endpoints when you enqueue work from a language without an SDK, or from a script. All requests go to `https://api.runnel.example/v1` with an API key in the `Authorization` header; the key decides the environment. Bodies and responses are JSON, and times are RFC 3339 in UTC.

> **Note** Errors return a non-2xx status with `{ "error": { "type": "…", "message": "…" } }`. Each key may make 600 requests a minute; the `Runnel-RateLimit-Remaining` header shows what is left.

## Create a run

Queues a run of a job or workflow that has been deployed to the key's environment. Send an idempotency key to make retries of the request safe: a second request with the same key within 24 hours returns the original run with status `200` instead of creating another.

`POST /v1/runs`

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job` | string | Yes | Name of the job or workflow, such as `send-invoice`. |
| `payload` | object | No | JSON passed to the job. Up to 256 KB. Defaults to `{}`. |
| `delay` | string | No | Wait before the run is eligible, such as `5m` or `2h`. At most `30d`. |
| `idempotency_key` | string | No | Up to 128 characters, unique per job and environment for 24 hours. |

```bash
curl https://api.runnel.example/v1/runs \
  -H "Authorization: Bearer $RUNNEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job":"send-invoice","payload":{"invoiceId":"inv_8812","accountId":"acc_42"},"delay":"5m","idempotency_key":"inv_8812"}'
```

```json
{
  "id": "run_01JB7X2K9Q4MZ8",
  "object": "run",
  "job": "send-invoice",
  "status": "queued",
  "attempt": 0,
  "max_attempts": 5,
  "payload": { "invoiceId": "inv_8812", "accountId": "acc_42" },
  "environment": "production",
  "idempotency_key": "inv_8812",
  "created_at": "2026-10-28T09:14:02Z",
  "scheduled_for": "2026-10-28T09:19:02Z"
}
```

## Retrieve a run

Returns one run with its current status, output or error, and for workflows the steps it has reached so far.

`GET /v1/runs/{id}`

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `id` | string | Yes | The run id, in the path. |

```bash
curl https://api.runnel.example/v1/runs/run_01JB7X2K9Q4MZ8 \
  -H "Authorization: Bearer $RUNNEL_API_KEY"
```

```json
{
  "id": "run_01JB7X2K9Q4MZ8",
  "object": "run",
  "job": "onboard-customer",
  "status": "failed",
  "attempt": 3,
  "max_attempts": 3,
  "output": null,
  "error": { "message": "Mail provider returned 503", "step": "send-welcome" },
  "started_at": "2026-10-28T09:19:04Z",
  "finished_at": "2026-10-28T09:31:40Z",
  "steps": [
    { "name": "create-account", "status": "succeeded", "finished_at": "2026-10-28T09:19:05Z" },
    { "name": "send-welcome", "status": "failed", "finished_at": "2026-10-28T09:31:40Z" }
  ]
}
```

## List runs

Lists runs in the key's environment, newest first, a page at a time. Pass `next_cursor` from one response as `cursor` to get the next page.

`GET /v1/runs`

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job` | string | No | Only runs of this job or workflow. |
| `status` | string | No | One of `queued`, `running`, `retrying`, `succeeded`, `failed`, `cancelled`. |
| `limit` | integer | No | Page size, 1 to 100. Defaults to 20. |
| `cursor` | string | No | Cursor from the previous page. |

```bash
curl "https://api.runnel.example/v1/runs?job=send-invoice&status=failed&limit=2" \
  -H "Authorization: Bearer $RUNNEL_API_KEY"
```

```json
{
  "data": [
    { "id": "run_01JB7X2K9Q4MZ8", "object": "run", "job": "send-invoice", "status": "failed" },
    { "id": "run_01JB7W8D2T6PQ1", "object": "run", "job": "send-invoice", "status": "failed" }
  ],
  "has_more": true,
  "next_cursor": "cur_9fK2mQ"
}
```

## Cancel a run

Cancels a run that is queued, running or waiting to retry. A running attempt is signalled through `ctx.signal` and gets 30 seconds to stop. Cancelling a run that already finished returns `409` with the error type `run_finished`.

`POST /v1/runs/{id}/cancel`

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `id` | string | Yes | The run id, in the path. |
| `reason` | string | No | Up to 200 characters, shown in the dashboard and the run's logs. |

```bash
curl -X POST https://api.runnel.example/v1/runs/run_01JB7X2K9Q4MZ8/cancel \
  -H "Authorization: Bearer $RUNNEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"reason":"Customer closed the account"}'
```

```json
{
  "id": "run_01JB7X2K9Q4MZ8",
  "object": "run",
  "job": "send-invoice",
  "status": "cancelled",
  "finished_at": "2026-10-28T09:16:11Z"
}
```

To retry a failed run, or replay a workflow from one step, use [`runnel runs retry`](/docs/reference/cli/) or the dashboard.
