# List workflow runs (/api/runs/list-runs)

`GET /api/runs`

Filtered workflow-run listing (sling runs list): branch / status / conclusion / trigger / workflow_path / runner-label / time-window filters over the CI facts store, keyset-paginated via an opaque cursor. Authenticated; scoped to the caller's orgs by membership.

Base URL: `https://runners.starsling.dev`

## Authentication

Requires a bearer token (`Authorization: Bearer`).

## Parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `org` | query | string | yes | GitHub organization login. Required — a run listing is always org-scoped. e.g. `acme` |
| `repo` | query | string | no | Bare repository name, without the org prefix. Narrows to one repo. e.g. `api` |
| `branch` | query | string | no | Only runs on this branch. e.g. `main` |
| `status` | query | array<string> | no | Lifecycle state. Repeatable: ?status=queued&status=completed. |
| `conclusion` | query | array<string> | no | Terminal outcome. Repeatable, and absent until a run completes. |
| `trigger` | query | string | no | The GitHub event that started the run. e.g. `push` |
| `workflow_path` | query | string | no | Workflow file path, as committed in the repository. e.g. `.github/workflows/ci.yml` |
| `label` | query | string | no | Runner label a job in the run requested. e.g. `self-hosted` |
| `window` | query | string | no | Relative lookback, e.g. 30d. Mutually exclusive with from/to and month. e.g. `30d` |
| `from` | query | string | no | Start of the range, inclusive. Required with `to`. e.g. `2026-06-01` |
| `to` | query | string | no | End of the range, exclusive. Required with `from`. e.g. `2026-07-01` |
| `month` | query | string | no | A whole calendar month, YYYY-MM. e.g. `2026-06` |
| `limit` | query | string \| integer | no | Rows per page. Page with `cursor`. 1–100; e.g. `30` |
| `cursor` | query | string | no | Opaque keyset cursor from a prior page's `next_cursor`. |

## Responses

| Status | Description |
| --- | --- |
| `200` | One page of workflow runs, newest first. Page with `next_cursor`. |
| `400` | The window flags conflict or don't parse, or the cursor is stale. |
| `401` | No credential, or a GitHub grant too old to read org membership — re-run `sling login`. |
| `403` | You are not a member of the org named in `?org=`. |
| `422` | A path or query parameter failed schema validation. `details` names each offending field. |
| `500` | The control plane failed, or the CI facts store is not configured for this deployment. |

### `200` body

- `runs` — array<object>, required
  - array of object
    - `run_id` — string, required
    - `run_url` — string, required
    - `workflow_path` — string, required
    - `branch` — string
    - `trigger` — string, required
    - `status` — string, required
    - `conclusion` — string
    - `created_at` — string, required
    - `duration_ms` — string | integer
    - `jobs_total` — string | integer, required
    - `jobs_failed` — string | integer, required
- `has_more` — boolean, required
- `next_cursor` — string

### Example

```json
{
  "runs": [
    {
      "run_id": "28961231706",
      "run_url": "https://github.com/acme/api/actions/runs/28961231706",
      "workflow_path": ".github/workflows/ci.yml",
      "branch": "main",
      "trigger": "push",
      "status": "completed",
      "conclusion": "failure",
      "created_at": "2026-07-22T09:14:03.000Z",
      "duration_ms": 412000,
      "jobs_total": 12,
      "jobs_failed": 1
    }
  ],
  "has_more": false
}
```