# On-Call API

The On-Call API lets scripts and CI jobs do what the On-Call console does: read and answer alerts, raise one from a deploy pipeline, see who is on call, put someone on cover, hold back paging during planned work, and run incidents. Every endpoint, with its parameters, schemas, errors and an example request, is in the [On-Call API reference](https://docs-dev.evohub.io/oncall.md). This page shows the common tasks and the rules that apply to all of them.

Paths below are relative to `https://evohub.io`. Requests need an API key, sent as described in [API overview](https://docs-dev.evohub.io/api-overview.md#authentication).

> [!NOTE]
> Monitoring tools send alerts *into* On-Call with an integration key, not an API key. See the [Alert ingest API reference](https://docs-dev.evohub.io/alert-ingest.md) and [Generic webhook](https://docs-dev.evohub.io/generic-webhook.md).

## Scopes

Each endpoint needs one scope. Give a key only the ones its job needs.

| To | Scope |
| --- | --- |
| List and read alerts, their timelines and analytics | `oncall:alert:read` |
| Acknowledge, resolve, suppress, assign, take over and add notes to alerts | `oncall:alert:respond` |
| Raise an alert, redirect one to another policy, resolve by fingerprint | `oncall:alert:write` |
| Read incidents, their timelines and analytics | `oncall:incident:read` |
| Declare and edit incidents, write their timelines, publish them to a status page | `oncall:incident:write` |
| Read schedules, overrides and who is on call | `oncall:schedule:read` |
| Change schedules, layers, rotations and overrides | `oncall:schedule:write` |
| Read escalation policies, and the Slack and Teams connections | `oncall:escalation:read` |
| Change escalation policies | `oncall:escalation:write` |
| Read integrations (including their ingest keys) | `oncall:integration:read` |
| Create, change and delete integrations and their signing secrets | `oncall:integration:write` |
| Read maintenance windows | `oncall:maintenance:read` |
| Schedule, change and end maintenance windows | `oncall:maintenance:write` |
| Read postmortems | `oncall:postmortem:read` |
| Write postmortems | `oncall:postmortem:write` |
| Organization settings: message templates, Slack and Teams, importing from Opsgenie or PagerDuty | `oncall:settings:write` |
| Read the On-Call audit log | `oncall:audit:read` |

A key without the scope gets **403**, never 401. See [Errors](https://docs-dev.evohub.io/errors.md#401-versus-403).

> [!WARNING]
> An integration's record includes its ingest key. A key with `oncall:integration:read` can read every ingest key it can see, so treat it like a credential.

## List open alerts

```bash
curl "https://evohub.io/api/v1/alerts?status=open&severity=critical&limit=20" \
  -H "Authorization: Bearer $EVOHUB_API_KEY"
```

`status=open` means triggered or acknowledged. The list is paged with `limit` (50 by default) and `offset`, and `meta.total` says how many alerts match. Filter by `assignee=me`, `integration_id`, `escalation_policy_id`, `team_id`, a creation range (`created_from`, `created_to`) or free text (`q`), and sort with `sort` and `dir`.

## Acknowledge or resolve an alert

```bash
curl -X POST https://evohub.io/api/v1/alerts/$ALERT_ID/acknowledge \
  -H "Authorization: Bearer $EVOHUB_API_KEY"

curl -X POST https://evohub.io/api/v1/alerts/$ALERT_ID/resolve \
  -H "Authorization: Bearer $EVOHUB_API_KEY"
```

Both answer with the alert. Doing it twice is harmless: acknowledging an acknowledged alert or resolving a resolved one changes nothing. A resolved alert cannot be acknowledged (**409** `ALERT_RESOLVED`). To answer many at once, send their ids to `/api/v1/alerts/acknowledge-bulk`, `/resolve-bulk` or `/takeover-bulk`; the answer lists which succeeded and which failed.

## Raise an alert from a pipeline

```bash
curl -X POST https://evohub.io/api/v1/alerts \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "title": "Checkout error budget exhausted",
        "severity": "high",
        "fingerprint": "checkout-error-budget",
        "escalation_policy_id": "'"$POLICY_ID"'"
      }'
```

This pages people exactly like an alert from an integration, and the notifications count toward usage. While an alert with the same `fingerprint` is open, sending it again does not open a second one. Resolve it later with `POST /api/v1/alerts/resolve-by-fingerprint` and `{"fingerprint": "checkout-error-budget"}`. Both need `oncall:alert:write`.

For a monitoring tool that should keep sending alerts, create an integration instead: it gets its own URL and key, and needs no API key.

## Who is on call

- `GET /api/v1/on-call-now` — who is on call right now on every schedule.
- `GET /api/v1/schedules/{id}/on-call-now` — the same for one schedule, with when the shift ends.
- `GET /api/v1/schedules/my-on-call` — for the person the key belongs to: their current shifts and their next one.

## Put someone on cover

```bash
curl -X POST https://evohub.io/api/v1/schedules/$SCHEDULE_ID/overrides \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "override_user_id": "'"$USER_ID"'",
        "start_time": "2026-10-12T18:00:00Z",
        "end_time": "2026-10-13T09:00:00Z",
        "reason": "Covering a trip"
      }'
```

The person must be a member of the organization who can respond to alerts, or the request is refused with **422** `CANNOT_RESPOND`. The same rule applies to anyone you add to a rotation, an escalation step or an alert. See [Overrides and takeover](https://docs-dev.evohub.io/overrides-and-takeover.md).

## Hold back paging during planned work

```bash
curl -X POST https://evohub.io/api/v1/maintenance-windows \
  -H "Authorization: Bearer $EVOHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "title": "Database upgrade",
        "starts_at": "2026-10-12T22:00:00Z",
        "ends_at": "2026-10-13T00:00:00Z"
      }'
```

While the window runs, alerts are still recorded but nobody is paged. A window lasts at most 30 days. It can also publish a scheduled maintenance on a status page (`status_page_id`) and silence uptime monitors (`uptime_monitor_ids`). End it early with `POST /api/v1/maintenance-windows/{id}/complete`; deleting it removes it and what it published.

## Run an incident

1. Declare it: `POST /api/v1/incidents` with a `title` and a `severity` (`none`, `minor`, `major` or `critical`).
2. Keep a timeline: `POST /api/v1/incidents/{id}/timeline` with a `message`.
3. Tell customers: `POST /api/v1/incidents/{id}/publish` with a status page's `page_id`. From then on, timeline entries and status changes are posted to the status page as well.
4. Mark it identified and resolved: `POST /api/v1/incidents/{id}/acknowledge`, then `/resolve`.
5. Write the postmortem: `PUT /api/v1/incidents/{id}/postmortem`.

To record an incident that is already over, send `started_at` and `resolved_at` when you declare it.

## Rules that apply everywhere

- **Teams.** Schedules, escalation policies and integrations can belong to a team. A personal key sees what you see: the organization-wide ones and those of your teams. An organization key sees the organization-wide ones and, when it is scoped to a team, that team's. Anything else answers **404**, as if it did not exist.
- **Updates.** `PUT` on an incident, a schedule, an escalation policy or an integration, and `PATCH` on a layer or a maintenance window, keep a field you leave out. An escalation policy keeps its steps unless you send `steps`, which replaces them all. A postmortem is replaced whole.
- **Personal endpoints.** Notification methods, the notification schedule and `my-on-call` belong to the caller. With an organization key, the key itself is the caller.
- **Streams.** `/api/v1/alerts/sse` and `/api/v1/incidents/{id}/sse` are Server-Sent Events streams of changes as they happen. Events are not replayed; read the list again after reconnecting.

## Related

- [On-Call API reference](https://docs-dev.evohub.io/oncall.md)
- [Alert ingest API reference](https://docs-dev.evohub.io/alert-ingest.md)
- [API keys and scopes](https://docs-dev.evohub.io/api-keys-and-scopes.md)
- [Errors](https://docs-dev.evohub.io/errors.md)
- [On-Call overview](https://docs-dev.evohub.io/on-call-overview.md)
