Escalation policy reference
Escalation policy
Section titled “Escalation policy”| Field | Type | Default | Description |
|---|---|---|---|
name | string | required | Human label, shown in dashboards and per-incident views. |
repeat_count | int | 0 | How many more times to run through the levels after the first pass, from 0 to 20. See repeat cycles. |
on_exhausted | string | notify_owners | What happens when nobody acknowledges: notify_owners, stop or escalate_to_policy. See when nobody acknowledges. |
escalate_to_policy_id | uuid | null | The policy escalate_to_policy runs once. Required with escalate_to_policy and refused (400) with anything else. Must be another policy of this account (404 otherwise); a policy naming itself is a 400. |
On PUT /escalation_policy/{policy_id}, fields you leave out stay as they are. Switching on_exhausted away from escalate_to_policy clears escalate_to_policy_id; sending only escalate_to_policy_id changes the fallback of a policy that already escalates.
{ "on_exhausted": "escalate_to_policy", "escalate_to_policy_id": "<backup-policy>" }Deleting a policy needs an admin or an API key; other roles get 403. A policy that another policy falls back to cannot be deleted: the 409 has data.conflict policy_is_a_fallback and lists them in data.policies (id, name).
Escalation level
Section titled “Escalation level”| Field | Type | Default | Description |
|---|---|---|---|
level_number | int | last | Position within the policy, from 1. Lower runs first. Omit it to add the level last. A position inside the list inserts the level there and moves the levels at and below it down one. A position past the end (more than N + 1 for N levels) or below 1 is a 400. |
timeout_minutes | int | required | How long to wait for any responder ack at this level before advancing, counted from when the level starts. Whole minutes, from 1 to 1440 (one day). |
target_user_ids | uuid[] | [] | Page these specific users. Each user’s notification rules + contact methods determine the actual delivery. |
target_schedule_ids | uuid[] | [] | Page whoever is on-call in these on-call schedules at firing time. |
A level that reaches nobody when it starts is skipped at once with an escalation_unreachable event, and the next level starts.
Levels are positions
Section titled “Levels are positions”A policy’s levels are always numbered 1 to N with no gaps and no duplicates. Every change keeps it that way:
- Adding a level puts it at its
level_number(last by default) and moves the levels at and below it down one. - Deleting a level moves every level below it up one.
- Reordering rewrites every number in one go. See the reorder endpoint.
An open incident follows its level, not the number. After a reorder it keeps waiting on the same level and moves on from that level’s place in the new order.
Deleting the level an open incident is waiting on pages nobody straight away. When that level’s timeout ends, the escalation continues at the level that took its place, and the incident records an escalation_level_removed event. If the deleted level was the last one, its timeout ends the pass: the next repeat starts at level 1, or the policy runs out and on_exhausted applies when no repeats remain.
Step types: practical recipes
Section titled “Step types: practical recipes”Page the on-call rotation
Section titled “Page the on-call rotation”{ "timeout_minutes": 5, "target_schedule_ids": ["<primary>"] }The most common first level.
Page a specific person
Section titled “Page a specific person”{ "timeout_minutes": 10, "target_user_ids": ["<eng-manager>"] }For fixed targets, such as the engineering manager at level 2.
Page on-call + a backup person
Section titled “Page on-call + a backup person”{ "timeout_minutes": 5, "target_schedule_ids": ["<primary>"], "target_user_ids": ["<sre-lead>"]}Both fire in parallel. First ack from anyone wins.
Page on-call + secondary on-call
Section titled “Page on-call + secondary on-call”{ "timeout_minutes": 10, "target_schedule_ids": ["<primary>", "<secondary>"]}Both schedules’ current responders get paged.
Final-level “page everyone”
Section titled “Final-level “page everyone””{ "timeout_minutes": 30, "target_user_ids": ["<eng-mgr>", "<vp-eng>", "<cto>"] }Reorder endpoint
Section titled “Reorder endpoint”PUT /escalation_policy/{policy_id}/level/reorder accepts a level_ids array in the order you want and rewrites every level’s level_number to match, in one transaction.
{ "level_ids": ["<id-1>", "<id-2>", "<id-3>"] }The array must name every level of the policy exactly once. A missing level, an extra or unknown id, or a repeated id is a 400 and changes nothing, so a list built before someone else added or deleted a level is refused rather than applied. Fetch the levels again and resend. A policy in another account is a 404.
How targets are paged
Section titled “How targets are paged”A level’s targets are resolved and de-duplicated, then each user is paged through their own notification rules for the incident’s urgency.
| Incident severity | Urgency used |
|---|---|
critical | high |
major | high |
minor | low |
This mapping is fixed and cannot be overridden per policy. Every user starts with a high and a low rule on their sign-in email.
Contact methods are email, SMS and Slack DM; there are no phone calls. A rule is skipped when its method cannot page: an SMS number that is not verified, an email address that bounced permanently or reported spam, or SMS when the account has none left. Each skip is recorded on the incident as a page_skipped event with its reason. A user no rule can reach is paged at their sign-in email, recorded as escalation_fallback_email. See readiness for the full definition.
Readiness endpoint
Section titled “Readiness endpoint”GET /escalation_policy/{policy_id}/readiness reports, for each level and each urgency, whether the level reaches someone before it times out. POST /escalation_policy/readiness does the same for levels that are not saved yet. Both only read. See check that a policy reaches someone.
Incident events
Section titled “Incident events”The escalation writes these to the incident timeline. They carry ids and reasons, never an address.
| Event | When |
|---|---|
escalation_unreachable | A level reached nobody and was skipped. Lists each target’s status and any schedule with nobody on call. |
escalation_fallback_email | A user no rule could reach was paged at their sign-in email. |
page_skipped | A rule, or an owner’s email, could not be sent, with the reason. |
escalation_level_removed | The level an open incident was waiting on was deleted. |
escalation_policy_handoff | The policy ran out and handed over to its escalate_to_policy_id. |
escalation_exhausted | The policy ran out: the reason (repeats_used, nobody_reachable, no_levels), the on_exhausted applied, and who was emailed. |
Escalation state values
Section titled “Escalation state values”The incident API does not return this state. An incident’s detail response has unassigned_after_exhaustion, true while the state is exhausted and nobody has acknowledged.
| Value | Meaning |
|---|---|
active | Cycling through levels. |
acknowledged | Acked or resolved. Paging stopped and pending schedules deleted. |
exhausted | The policy ran out and on_exhausted applied. Level cycling stopped, but a per-user delayed page that was already scheduled can still fire. |
See also
Section titled “See also”- Escalation overview: concept and lifecycle.
- Readiness: whether each level reaches someone.
- On-call schedules: what
target_schedule_idsresolves to. - API Reference: wire-level request/response shapes.