# List alerts, or the episodes they were folded into

Canonical page: https://docs.ovok.com/signals/standalone/api/alerts/list-alerts-or-the-episodes-they-were-folded-into

{/* Generated from the API Explorer document by scripts/generate-signals-api-pages.mjs. Edit ovok-core, not this page. */}


# List alerts, or the episodes they were folded into [#list-alerts-or-the-episodes-they-were-folded-into]

| Method | Path |
| --- | --- |
| `GET` | `/v1/signals/api/alert` |

<Availability route="GET /v1/signals/api/alert" />

The dashboard view.

By default this is one row per breach, in v1's alert shape plus every nest alert field, inside v1's paginate envelope (`items`, `totalItems`, `page`, `totalPages`, …) with nest's `nextCursor` beside it. Page with v1's `page` and `limit` (a page may start at most 10000 rows in), or walk with `cursor`: pass `nextCursor` back verbatim. `sort` is v1's `time-desc` (the default) or `time-asc`; `ids` narrows to those patients. It works whether or not the tenant has `episodicAlerts`. Without `project` it is tenant-wide: a per-facility view must send `project`, which keeps only patients stamped with it.

`?episodes=true` answers with episodes instead, as `{items, nextCursor}`: one row per clinical event, which opens on the first breaching reading, absorbs the rest, and closes on recovery, on going stale, or by hand. That grain REQUIRES `project`. It defaults to the tenant's `feedCodes` (`PATCH /api/tenant`), every code when it lists none; alerts have no code default.

`codes`, `since` and `acknowledged` filter either grain. `until`, `page` and `ids` are alerts only: sending one with `episodes=true` is a 422, not a filter that silently did nothing. `status` reads ACTIVE/RESOLVED for alerts and OPEN/CLOSED for episodes.

Episodes are newest first by `sort`: `openedAt`, the default, or `lastFiringAt`, the newest firing reading (the opening, for an episode that has none). `since` and the cursor use the same time. `openedAt` never changes, so walking every page lists each episode once. On `lastFiringAt` an episode that fires mid-walk moves above the cursor: it is never listed twice, but that walk misses it. A `sort` value from the other grain is a 422.

### Through ovok [#through-ovok]

- **Who can call it:** Manager apps, and users whose access policy grants the capabilities.
- **Capabilities, all required:** `signals_alerts:read`. Project admins have every capability; client applications get no admin bypass.
- ovok sets `project` to your project, so you can leave it out.
- If your access covers only some patients (anyone but project admins, manager or submitter apps, and anyone whose Patient access has no criteria), name them with `patientId` or `ids`, each one you can read, at most 100. Signals then pages over just those patients, so pages and totals stay true. A patient is named by its Signals id, or by its Medplum Patient id where Signals takes a `refId`; ovok asks Signals which patient a Signals id is.

## Request [#request]

### Query parameters [#query-parameters]

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `episodes` | boolean | No | Return episodes rather than the individual breaches they were folded from. An episode is one continuous clinical event for a (patient, code) pair: it opens on the first breaching reading, absorbs the rest, and closes on recovery, on going stale, or by hand. The default answers one row per breach, which is the duplication episodes exist to collapse. Requires `project`, and changes which of the filters below are accepted. |
| `patientId` | string | No | — |
| `ids` | array of string | No | v1's patient filter: only these patients' alerts, by Signals id. Repeat the parameter or separate with commas. Alerts only. |
| `status` | `ACTIVE`, `RESOLVED`, `OPEN`, `CLOSED` | No | ACTIVE or RESOLVED for alerts; OPEN or CLOSED with `episodes=true`. |
| `codes` | array of string | No | Restrict to these LOINC codes. On episodes it defaults to the tenant's `feedCodes`, every code when it lists none. Alerts have no default: absent, every alert, including those that carry no code. |
| `since` | string | No | Alerts raised, or episodes whose `sort` time is, at or after this instant: opened by default, last fired with `sort=lastFiringAt`. |
| `until` | string | No | Alerts raised before this instant. Alerts only. |
| `acknowledged` | boolean | No | Filter on whether the episode, or the alert, has been acknowledged. |
| `sort` | `time-desc`, `time-asc`, `openedAt`, `lastFiringAt` | No | On alerts, v1's order: `time-desc` (the default) or `time-asc`. On episodes, which time they are listed by, newest first; `since` and `cursor` use it too. `openedAt` (the default) never changes, so a walk of every page sees each episode once. `lastFiringAt` is the newest firing reading, or the opening for an episode that has none; an episode that fires mid-walk moves above the cursor. |
| `page` | number | No | v1's 1-based page of `limit` alerts. A page may start at most 10000 rows in; walk further with `cursor`. Alerts only. |
| `limit` | number | No | — |
| `cursor` | string | No | — |
| `tags[key]` | string | No | v1's tag filter: only patients whose `tags.key` equals one of the comma-separated values, or holds one in an array. Repeat with other keys to require them all. Keys are alphanumeric; `tags.key=` is accepted too. |

## Responses [#responses]

| Status | Meaning |
| --- | --- |
| `200` | A page of alerts, or of episodes, plus the cursor for the next one. |
| `400` | The query carries a raw `#`, or more than 200 parameters. |
| `401` | Your ovok access token, or your client id and secret, are missing or invalid. |
| `403` | ovok refused the call: you lack a capability this route needs, or your session has no project, or `project` names another project, or your access covers only some patients and the call names none. From Signals: Authenticated, but the client's role does not permit this, or it is not attached to the patient. Or: `episodicAlerts` is not enabled for this tenant, and episodes were requested. |
| `404` | A patient the call names is not one you can read. |
| `409` | Your project has no Signals tenant of its own (`SIGNALS_TENANT_NOT_OWN`), or it is moving to another one. |
| `422` | A patient id is not 1 to 64 letters, digits, `.`, `_`, `~` or `-`. More than 100 patients are named. From Signals: An alert filter was sent with `episodes=true`, `episodes=true` arrived without `project`, or the page starts too deep. |
| `429` | Too many requests. Retry after the seconds in `Retry-After`. |
| `500` | ovok hit an unexpected fault, such as your project having no Signals submitter. |
| `502` | Signals answered with something ovok couldn't use, or refused ovok's own credential. |
| `503` | Signals is unavailable. Retry after the seconds in `Retry-After`. |
| `504` | Signals did not answer in time. |

## Example [#example]

```bash
curl --request GET 'https://api.sandbox.ovok.com/v1/signals/api/alert' \
  --user "${OVOK_CLIENT_ID}:${OVOK_CLIENT_SECRET}"
```
