---
title: "List routes for a check"
method: GET
path: "/api/v1/checks/{id}/routes"
tags: ["Routes"]
---

# List routes for a check

`GET /api/v1/checks/{id}/routes`

## Request

- Base URL: `https://app.lastping.dev`
- URL: `https://app.lastping.dev/api/v1/checks/{id}/routes`
- Auth: API key in header `X-Api-Key`

Returns all routing rules for the check.  Each rule maps an event type
(`down`, `recovery`, `fail`, `every-run`, `success`, `started`,
`blocked`, `note`) to a list of channel UUIDs. Always returns a JSON
array (never null).

## Response `200`

Array of routes (may be empty).

- Route[]
  - `event_type` 'down' | 'recovery' | 'fail' | 'every-run' | 'success' | 'started' | 'blocked' | 'note': The check event that triggers this route. `down`, `recovery` and `fail` fire on a state change. `every-run`, `success` and `started` are informational: `every-run` fires once per completed run (success or failure), `success` fires only on a successful run, and `started` fires when a run begins. All three are bounded only by how often the monitor runs (not by state changes), and they share one per-channel rate budget (default 60/hr) separate from down/fail/recovery — a chatty monitor routed to any combination of the three can starve its own notifications once that shared budget is exhausted. `blocked` fires when the agent reports it is blocked (waiting on a human) via a `blocked` ping and is still blocked 10 minutes later: the notification is held 10 minutes, a note, step, success, fail or cancel for the same run inside that time cancels it (a title does not), and a run sends it at most once per blocked stretch (until one of those ends the stretch). A `blocked` ping sent without a run id belongs to no run, so any non-blocked ping on the monitor ends its stretch instead: a start, log, note, success, fail or cancel of any run, or a step of the monitor's current run (any step when no run is current). It is agent-reported rather than a system-derived state change, but it draws on the down/recovery/fail alert budget rather than the info one, because a blocked run needs a human and must not be starved by chatty info traffic. It is distinct from the `blocked`-CAUSE incident: if the block outlasts `blocked_timeout_s`, a separate `down` event fires with cause `blocked` (routable via the bare `down` route or a `down/blocked` per-cause override), not another `blocked`-event-type notification. `note` is an agent-reported, informational free-text signal (no state change) and shares the every-run/success/started info budget.
  - `channel_ids` string[]: Ordered list of channel UUIDs to notify (never null; may be empty).

## Other responses

- `401`: Missing or invalid API key.
- `404`: Check not found in this project.
- `429`: Too many requests. The per-principal fixed-window rate limit has been exceeded. Retry after the number of seconds indicated by the `Retry-After` response header. The problem body's `code` is `RATE_LIMITED`. It names this limiter specifically, so a client can tell it apart from the application-level throttles that also answer 429 with their own codes and their own, much longer, `Retry-After` values (`TEST_PING_RATE_LIMITED`, `TOO_MANY_ATTEMPTS`). Back off globally on `RATE_LIMITED`; back off on the one operation for the others. The principal is the API key for a key-authenticated request and the USER for a browser session, so every tab one person has open shares one budget.

---

[API](https://skmtc.dev/lastping/apis/lastping-management-api.md) · [All operations](https://skmtc.dev/lastping/apis/lastping-management-api/llms.txt) · [OpenAPI document](https://skmtc.dev/lastping/apis/lastping-management-api/revisions/bbc6eda91c46?raw)
