Alert Escalation Policies¶
Availability: Maintenant Pro
Escalation policies automatically route unacknowledged alerts through a chain of up to 5 notification levels, each with a configurable delay and a distinct set of channels.
Pattern: reserved-escalation channel. Since channels are silent by default (they only receive alerts when wired through an Alert Trigger), you can create a channel that exists only for an escalation level. A manager's email referenced in Level 3 of a policy, with no trigger using it, will only be notified after 1 hour of unacknowledged escalation, never at the initial dispatch. This is the cleanest way to model "last-resort" destinations without duplicate notifications. Such a channel gets the escalation, acknowledgment and exhaustion notices, but no notice when the alert resolves.
Concept¶
When an alert fires, every active escalation policy whose filters match it starts an escalation run. The run tracks which notification level is due next and sends the notifications of that level when its delay has passed. The chain stops as soon as the alert is acknowledged or resolved.
A level's delay_seconds is counted from the start of the run (the moment the alert fires), not from the previous level. A level with a delay of 900 fires 15 minutes after the alert, whatever the level before it had. Runs are evaluated once a minute, so a level can fire up to a minute after its delay.
Alert fires (T+0)
│
├─ Level 1 (delay 300) → T+5 min, if still unacknowledged → Notify #slack-oncall
│
├─ Level 2 (delay 900) → T+15 min, if still unacknowledged → Call the pager webhook
│
└─ Level 3 (delay 3600) → T+1 hour, if still unacknowledged → Email management
A run keeps the policy as it was when the run started. Editing a policy changes the alerts raised afterwards, not the runs already in progress. Deactivating or deleting a policy stops its runs (stopped_by_policy_disabled, stopped_by_policy_deletion).
Policies only see alerts that are active. An alert raised while a matching silence rule or maintenance window is in force is silenced and starts no run. If an alert becomes more severe, policies that match its new severity start a run too; runs already started continue untouched. An alert that is already acknowledged starts no new run when its severity rises, and a run still going when the alert is acknowledged stops at its next evaluation. Each time a level is sent, the alert's escalated_at is set to that time.
Examples¶
Single-level policy¶
Notify the on-call Slack channel 5 minutes after an alert fires.
{
"name": "Critical pager: Level 1 only",
"active": true,
"filters": { "severities": ["critical"] },
"levels": [
{ "delay_seconds": 300, "channel_ids": ["0195f3c8-5e2a-7b14-9a30-7d1c4f2e8a66"] }
]
}
Multi-level policy¶
Escalate progressively over an hour: the levels fire 5 minutes, 15 minutes and 1 hour after the alert.
{
"name": "Full on-call chain",
"active": true,
"filters": { "severities": ["critical", "warning"] },
"levels": [
{ "delay_seconds": 300, "channel_ids": ["0195f3c8-5e2a-7b14-9a30-7d1c4f2e8a66"] },
{ "delay_seconds": 900, "channel_ids": ["0195f3c9-0b71-7e52-8d04-3a9f6c1b2d40"] },
{ "delay_seconds": 3600, "channel_ids": ["0195f3c9-44d8-7a3c-b6e1-92f0d5a7c318"] }
]
}
Filter by entity¶
Only escalate alerts about one endpoint. A scope names an alert's entity: kind is the entity_type of the alerts to match, from the Entity column of the alert sources (container, endpoint, heartbeat, certificate, agent, swarm_service, workload and so on), and ref_id is the entity_id those alerts carry (a UUID for a container, endpoint, heartbeat, certificate or agent). Neither is checked when the policy is saved: a scope that names nothing matches no alert.
{
"name": "Checkout endpoint chain",
"active": true,
"filters": {
"severities": ["critical"],
"scopes": [{ "kind": "endpoint", "ref_id": "0195f3c4-11aa-7f00-8c55-2b9d0e3a4c18" }]
},
"levels": [
{ "delay_seconds": 300, "channel_ids": ["0195f3c8-5e2a-7b14-9a30-7d1c4f2e8a66"] }
]
}
An empty severities or scopes matches everything. An alert must satisfy both filters to match. The policy editor of the Escalation page edits the name, the activation, the severities (warning, critical) and the levels, up to 5; it shows the scopes of a policy read-only and keeps them when you save. Scopes are set through the API. The API also accepts info as a severity.
Validation¶
| Field | Rule |
|---|---|
name |
Required, at most 120 characters |
levels |
At least one, at most 5 |
levels[].delay_seconds |
Between 60 and 86400 |
| Consecutive levels | Each level is at least 60 seconds after the previous one, so delays must increase |
levels[].channel_ids |
At least one channel ID per level |
A request that breaks a rule returns 400 validation_failed with the field in the message. The channel IDs are not checked against existing channels when the policy is saved: a level that points at a deleted channel skips it when it fires.
Interactions¶
Acknowledgment stops escalation¶
When an alert is acknowledged, any active escalation run is immediately stopped with status stopped_by_ack. Every channel that received a notification of the run (a delivery that is sent or still pending) gets one acknowledgment notice, once, even if it appeared in several levels. The notice reuses the recovery format of the channel, and its message is:
When no name was recorded, the text is Acknowledged at <time>: <original alert message>. A run that has not reached its first level has notified nobody, so it sends no notice.
Resolution stops escalation¶
When an alert resolves (automatically or manually), any active run is stopped with status stopped_by_resolution. No notification is sent on resolution: channels reached by the alert's triggers receive the usual recovery notice, but a channel that only appears in escalation levels does not.
Maintenance windows suspend escalation¶
A run is checked whenever a level comes due. If a maintenance window covers the monitored entity at that moment, the run is paused (paused_by_maintenance) rather than stopped, and checked again about every minute. The first evaluation after the window ends resumes the run and the next one sends the level that was due; the following levels keep the spacing you configured between them, counted from the resume. The pause therefore pushes back every remaining level by the time the run waited, and no level is skipped.
Chain exhausted¶
If all levels fire without an acknowledgment or resolution, the run ends with status exhausted at the next evaluation. A final notice is sent on the last level's channels:
Escalation exhausted after <N> level(s) without acknowledgment, human action required: <original alert message>
Disabled or failing channels¶
A delivery to a disabled channel is recorded as failed with the error channel disabled, and the run goes on with the next level. A delivery to an enabled channel makes up to three attempts, at once, after 1 second and after 5 seconds, like any notification, and is recorded as failed with the last error if all three fail.
API¶
All endpoints require Pro edition. Below Pro they return 403 EDITION_REQUIRED (with feature: alert_escalation and required_edition: pro).
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/escalation-policies |
Create a policy |
GET |
/api/v1/escalation-policies |
List all policies (?active=true for active ones only), as {"policies": […], "limits": {…}} |
GET |
/api/v1/escalation-policies/{id} |
Get a policy |
PUT |
/api/v1/escalation-policies/{id} |
Update a policy |
PATCH |
/api/v1/escalation-policies/{id}/active |
Activate / deactivate, body {"active": true}. Deactivating stops the active runs of the policy |
DELETE |
/api/v1/escalation-policies/{id} |
Delete a policy and stop its active runs |
POST |
/api/v1/escalation-policies/overlap-probe |
Detect overlapping policies |
GET |
/api/v1/alerts/{id}/escalation-runs |
List runs for an alert |
GET |
/api/v1/escalation-runs/{id} |
Get run detail + deliveries |
GET |
/api/v1/escalation-policies/{id}/runs |
List recent runs for a policy (limit up to 200, default 50, and cursor) |
- A policy is
{id, name, active, filters: {severities, scopes}, levels: [{order, delay_seconds, channel_ids}], created_at, updated_at}.PUTreplaces the name, the activation, the filters and the levels, so send them all. limitsis{"max_active": -1, "max_levels": 5, "current_active": n}: the number of active policies is not capped (-1), and a policy holds at most 5 levels.- The overlap probe answers
{"overlapping": […]}, each entry holding thepolicy_id,policy_name,shared_channelsandfilter_intersectionof a policy that overlaps. - The run lists answer
{"runs": […]}, newest first.cursoris theidof the last run received. A run holds itsstatus,last_executed_level_index,started_at,ended_atandnext_action_at, and the run detail adds itsdeliveries. - An unknown policy or run answers
404 policy_not_foundor404 run_not_found.
The MCP server offers list_escalation_policies, get_escalation_policy, create_escalation_policy, update_escalation_policy, set_escalation_policy_active, delete_escalation_policy, list_alert_escalation_runs and get_escalation_run. They need Pro, like the API.
FAQ¶
Can I have multiple policies matching the same alert? Yes. Each matching active policy starts its own independent run. The overlap-probe endpoint helps you detect potential conflicts before saving a policy: it takes a policy body and lists the existing policies whose filters can match the same alerts and that share at least one channel.
What happens if a channel fails to deliver?
The delivery is recorded with status=failed and the error message, after three attempts. The run continues to the next level: a single channel failure does not stop the chain. A delivery left pending for more than 2 minutes (the server stopped before it finished, for instance) is retried while the alert is still active, and marked abandoned otherwise.
What happens to runs when I downgrade from Pro?
Going from Pro to Personal or Community deactivates all active policies and stops all active runs with stopped_by_edition_downgrade. When you upgrade back to Pro, policies are automatically restored to their previous active state.
What is the audit trail?
Every notification attempt is recorded with its status (pending, sent, failed, abandoned), the channel, the level index, and timestamps. Acknowledgment and exhaustion notices are recorded in the same list, with level index -1 and -3. Use GET /api/v1/escalation-runs/{id} to retrieve the full delivery history for any run. A run is active or paused_by_maintenance while it lasts, and ends with one of these statuses: stopped_by_ack, stopped_by_resolution, stopped_by_policy_deletion, stopped_by_policy_disabled, stopped_by_edition_downgrade or exhausted.
When are old runs purged?
Runs and their deliveries are purged nightly at 03:00 local time if their ended_at is older than 90 days. Active runs are never purged.