# List runs

Source: https://docs.coderhelm.com/api/reference/runs/list-runs

`GET /api/runs`

Lists the team's runs, newest first, one page at a time. Search with `q` and filter by `status`, `source` and `repo`. Each page reads at most a few hundred runs, so a page can come back short, or empty, with `next` set: keep reading until `next` is null.

## Authentication

A team API key: `Authorization: Bearer chk_...`. The key needs the `view` scope. See [Authentication](https://docs.coderhelm.com/api/authentication).

## Parameters

### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `source` | string | no | Only runs from this source, such as `github`, `jira` or `alert`. |
| `limit` | integer | no | Runs per page, 1 to 100. Default 50. |
| `cursor` | string | no | `next` from the previous page (the last run id it covered). |
| `q` | string | no | Search words: ticket key or number, title, repo, PR number, status. |
| `status` | string | no | Comma-separated exact statuses, e.g. `failed,cancelled`. |
| `repo` | string | no | One repo, `owner/name` (exact, case-insensitive). |

## Responses

### 200

A page of runs.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `next` | string or null | no | Pass as `cursor` to read on; null when there are no older runs. |
| `runs` | array of RunSummary | yes | Runs that match, newest first. Can be short, or empty, while `next` is set: older runs are still unread. |
| `runs[].cost_usd` | number or null | no | What the run cost in model usage, in US dollars, as recorded. |
| `runs[].created_at` | string or null | no | When the run started (RFC 3339). |
| `runs[].current_pass` | string or null | no | The step the run is on or ended on, such as `triage`, `plan`, `implement`, `review` or `pr`. |
| `runs[].duration_s` | integer or null | no | How long the run took, in seconds. |
| `runs[].pr_number` | integer or null | no | That pull request's number. |
| `runs[].pr_url` | string or null | no | The pull request the run opened. |
| `runs[].repo` | string or null | no | The repository, `owner/name`. |
| `runs[].run_id` | string or null | no | The run's id, a ULID. Newer runs sort after older ones. |
| `runs[].status` | string or null | no | Where the run is: `pending`, `running`, `awaiting_ci`, `completed`, `failed`, `needs_input`, `needs_outside_change`, `cancelled`, `retried` or `closed`. Treat a value you don't know as in progress. |
| `runs[].ticket_id` | string or null | no | The ticket's key or issue number in its source. |
| `runs[].ticket_source` | string or null | no | What started it, such as `github`, `jira` or `alert`. |
| `runs[].title` | string or null | no | The ticket's title. |
| `runs[].tokens_in` | integer or null | no | Input tokens used. |
| `runs[].tokens_out` | integer or null | no | Output tokens used. |
| `scanned` | integer | yes | How many runs were read to fill this page (searches and filters skip some). |

Headers: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`.

### 401

The key is missing, malformed, revoked or expired, or the person who made it left the team.

### 403

The key lacks the scope this endpoint needs (`missing_scope`).

### 429

Over the key's rate limit (`rate_limited`), or, for endpoints that start work, over the team's monthly token limit (`token_limit_reached`).

Headers: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`, `Retry-After`.

### 500

Something failed on CoderHelm's side. Safe to retry reads.

## Example request

cURL:

```bash
curl -X GET 'https://api.coderhelm.com/api/runs' \
  -H "Authorization: Bearer $CODERHELM_API_KEY"
```

TypeScript:

```ts
const res = await fetch("https://api.coderhelm.com/api/runs", {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.CODERHELM_API_KEY}`,
  },
});
if (!res.ok) {
  const { error, code } = await res.json();
  throw new Error(`${res.status} ${code}: ${error}`);
}
const data = await res.json();
```

Python:

```python
import os
import requests

headers = {
    "Authorization": f"Bearer {os.environ['CODERHELM_API_KEY']}",
}
res = requests.request("GET", "https://api.coderhelm.com/api/runs", headers=headers)
if not res.ok:
    raise RuntimeError(f"{res.status_code}: {res.json().get('error')}")
data = res.json()
```

## Example response

```json
{
  "next": "01JB8W2Q7N4D6R8S0T2V4X6Z8A",
  "runs": [
    {
      "cost_usd": 1.42,
      "created_at": "2026-10-22T14:03:11Z",
      "current_pass": "pr",
      "duration_s": 734,
      "pr_number": 318,
      "pr_url": "https://github.com/acme/web/pull/318",
      "repo": "acme/web",
      "run_id": "01JB8X6F4M2C9QZ3T7V5W1K0HA",
      "status": "completed",
      "ticket_id": "WEB-42",
      "ticket_source": "jira",
      "title": "Add rate limiting to the login form",
      "tokens_in": 182340,
      "tokens_out": 20511
    }
  ],
  "scanned": 50
}
```
