# Summarize a range of runs

**GET** `/api/runs/range`

Summarizes the runs in a range: causes of failure, days, triggers and the busiest workflows.

Needs [an API token](https://docs.gorunner.io/api/authentication#scopes) with the **Read** permission for runs (`run:read`).

## Parameters

### Query

- `workflowId` · Optional · UUID: One workflow’s runs.
- `environment` · Optional · string: `production` (the default), `test` or `all`.
- `window` · Optional · string: `24h`, `7d`, `30d`, `90d` or `all` (the default). Not with `from` or `to`.
- `tz` · Optional · string: A time zone name, such as `Europe/Berlin`, for “today” and the days. Unknown or left out: UTC.

**What are the rarely used parameters?**

- `triggerType` · Optional · string: How it began: `manual`, `webhook`, `cron`, `poll`, `error`, `run_finished`, `event`, `api`, `mcp` or `subflow`.
- `tag` · Optional · string: Runs with exactly this tag, added by the Tags app.
- `from` · Optional · time: Runs started at or after this time (RFC 3339).
- `to` · Optional · time: Runs started before this time. After `from`.
- `q` · Optional · string: Up to 200 characters. Finds runs whose ID starts with it, or whose workflow name or error has it, ignoring case.
- `reason` · Optional · string: Up to 200 characters. Runs whose error has it, ignoring case.
- `group` · Optional · string: A failure group’s `key`, from Group failed runs.

## Read it

`byCause` holds the 5 biggest failure groups (see [Group failed runs](https://docs.gorunner.io/api/stats/list-run-failure-groups)), `byWorkflow` the 10 busiest workflows. `byDay` uses the days of `tz`.

`slowerThanUsual` counts finished runs that took at least `slowerFactor` times (3) their workflow’s usual time.

## Responses

- 200 OK

  The summary.

- 400 `VALIDATION_ERROR`

  A filter has a value it doesn’t take. The message names it.

- 403 `FORBIDDEN`

  The token lacks the **Read** permission for runs.

- 500 `INTERNAL_ERROR`

  The summary couldn’t be read. Try again.

Any call can also answer: [`401 UNAUTHORIZED`](https://docs.gorunner.io/errors#UNAUTHORIZED) · [`401 TOKEN_ENDED`](https://docs.gorunner.io/errors#TOKEN_ENDED) · [`403 TOKEN_SURFACE_OFF`](https://docs.gorunner.io/errors#TOKEN_SURFACE_OFF) · [`403 FEATURE_OFF`](https://docs.gorunner.io/errors#FEATURE_OFF) · [`403 EMBED_NOT_ALLOWED`](https://docs.gorunner.io/errors#EMBED_NOT_ALLOWED) · [`403 EMBED_NOT_AVAILABLE`](https://docs.gorunner.io/errors#EMBED_NOT_AVAILABLE) · [`403 ACCOUNT_SUSPENDED`](https://docs.gorunner.io/errors#ACCOUNT_SUSPENDED) · [`429 RATE_LIMITED`](https://docs.gorunner.io/errors#RATE_LIMITED) · [`503 BUSY`](https://docs.gorunner.io/errors#BUSY) · [`503 PAUSED`](https://docs.gorunner.io/errors#PAUSED) · [`503 SERVICE_UNAVAILABLE`](https://docs.gorunner.io/errors#SERVICE_UNAVAILABLE). See [Errors](https://docs.gorunner.io/api/errors#by-status).

Request

**curl**

```bash
GORUNNER="https://api.gorunner.io"
GORUNNER_TOKEN="grt_…"  # needs Read for runs

URL="$GORUNNER/api/runs/range?window=7d&tz=Europe/"
URL="${URL}Berlin"
curl "$URL" \
  -H "Authorization: Bearer $GORUNNER_TOKEN"
```

**JavaScript**

```js
const GORUNNER = "https://api.gorunner.io";
const TOKEN = process.env.GORUNNER_TOKEN;

const res = await fetch(
  `${GORUNNER}/api/runs/` +
    `range?window=7d&tz=Europe/Berlin`,
  {
    headers: { Authorization: `Bearer ${TOKEN}` },
  },
);
const { data } = await res.json();
```

**Python**

```python
import os, requests

GORUNNER = "https://api.gorunner.io"
TOKEN = os.environ["GORUNNER_TOKEN"]

res = requests.get(
    f"{GORUNNER}/api/runs/range",
    params={
      "window": "7d",
      "tz": "Europe/Berlin",
    },
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]
```

Response · 200 OK, shortened

```json
{
  "data": {
    "runs": 120,
    "failed": 10,
    "failedWorkedOnRetry": 4,
    "slowerThanUsual": 2,
    "slowerFactor": 3,
    "byCause": [
      {
        "key": "gAAAAB…",
        "workflowId": "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
        "workflowName": "Order intake",
        "step": "Forward to fulfilment",
        "reason": "the service answered 503",
        "count": 10
      }
    ],
    "byDay": [
      {
        "day": "2026-10-25",
        "from": "2026-10-25T00:00:00+02:00",
        "runs": 15,
        "failed": 1
      },
      "…"
    ],
    "byTrigger": [
      {
        "triggerType": "webhook",
        "runs": 98,
        "failed": 10
      }
    ],
    "byWorkflow": [
      {
        "workflowId": "3b1e5c2a-7d4f-4e8b-a1c6-5f2d9b0e7a31",
        "workflowName": "Order intake",
        "runs": 64,
        "failed": 10
      }
    ]
  }
}
```

**Every field**

It takes no body.

### Response · 200 OK

- `data` · object
  - `runs` · integer
  - `failed` · integer
  - `failedWorkedOnRetry` · integer
  - `slowerThanUsual` · integer
  - `slowerFactor` · integer
  - `byCause` · array of objects: The biggest failure groups (at most 5), biggest first.
    - `key` · string: The failure group’s `key` (`GET /api/runs?group={key}`).
    - `workflowId` · UUID
    - `workflowName` · string
    - `step` · string: The failed step’s display name; absent when the messages name no step.
    - `reason` · string
    - `count` · integer
  - `byDay` · array of objects: Each local day in `tz` with runs in the range.
    - `day` · string
    - `from` · time: The day’s own start.
    - `runs` · integer
    - `failed` · integer
  - `byTrigger` · array of objects: Runs and failures by the run’s own trigger type (as `GET /api/runs?triggerType`).
    - `triggerType` · string
    - `runs` · integer
    - `failed` · integer
  - `byWorkflow` · array of objects: The 10 busiest workflows.
    - `workflowId` · UUID
    - `workflowName` · string
    - `runs` · integer
    - `failed` · integer

Related: [Count runs by state](https://docs.gorunner.io/api/stats/count-runs) · [Usual run times](https://docs.gorunner.io/api/stats/get-usual-run-times)

Source: https://docs.gorunner.io/api/stats/summarize-run-range
