API
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. 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.
Note
Monitoring tools send alerts into On-Call with an integration key, not an API key. See the Alert ingest API reference and Generic webhook.
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.
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
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
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
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
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.
Hold back paging during planned work
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
- Declare it:
POST /api/v1/incidentswith atitleand aseverity(none,minor,majororcritical). - Keep a timeline:
POST /api/v1/incidents/{id}/timelinewith amessage. - Tell customers:
POST /api/v1/incidents/{id}/publishwith a status page'spage_id. From then on, timeline entries and status changes are posted to the status page as well. - Mark it identified and resolved:
POST /api/v1/incidents/{id}/acknowledge, then/resolve. - 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.
PUTon an incident, a schedule, an escalation policy or an integration, andPATCHon a layer or a maintenance window, keep a field you leave out. An escalation policy keeps its steps unless you sendsteps, which replaces them all. A postmortem is replaced whole. - Personal endpoints. Notification methods, the notification schedule and
my-on-callbelong to the caller. With an organization key, the key itself is the caller. - Streams.
/api/v1/alerts/sseand/api/v1/incidents/{id}/sseare Server-Sent Events streams of changes as they happen. Events are not replayed; read the list again after reconnecting.
Related
Was this page helpful?
