Automation hooks (Zapier, Make, n8n)
Automation hooks connect CompleteStatus to workflow platforms like Zapier, Make and n8n. They implement the REST-hook pattern those platforms speak natively: the platform subscribes a target URL to the events it wants, and CompleteStatus POSTs a JSON event to that URL the moment an incident opens or resolves — no polling.
Hooks are organization-wide (they fire for incidents on any monitor in any of your projects), unlike alert channels, which belong to a project and are routed per monitor. Because they're driven by the REST API, using them requires an API key — and API keys require the Business plan or above (see /docs/rest-api).
Events
| Event | Fires when |
|---|---|
incident.opened |
A monitor is confirmed down and an incident opens |
incident.resolved |
The monitor recovers and the incident resolves |
If a maintenance window covers the monitor, hook deliveries are suppressed along with all other alerting — see /docs/maintenance-windows.
Subscribing (the REST-hook API)
Hooks are managed through the REST API with an API key carrying the hooks:manage scope (create one at /settings/api-keys — available on the Business plan or above, like all API keys).
Subscribe:
curl -X POST https://completestatus.com/api/v1/hooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/", "events": ["incident.opened", "incident.resolved"]}'
{
"data": {
"id": 7,
"url": "https://hooks.zapier.com/hooks/catch/123456/abcdef/",
"events": ["incident.opened", "incident.resolved"],
"active": true,
"consecutive_failures": 0,
"last_delivered_at": null,
"expired_at": null,
"created_at": "2026-07-08T09:00:00+00:00"
}
}
List subscriptions with GET /api/v1/hooks, and unsubscribe with DELETE /api/v1/hooks/{id} (returns 204). Zapier's "unsubscribe" step should call the DELETE endpoint with the id returned at subscribe time.
Your active subscriptions are also listed — with revoke buttons — at the bottom of /settings/channels.
Warning: The target URL must be publicly reachable. CompleteStatus validates it when you subscribe and again at every delivery (resolving, pinning the public IP and refusing redirects), so private and internal addresses are rejected in both places.
Delivery payload
Every delivery is an HTTP POST with a JSON body and two headers:
X-CompleteStatus-Event— the event name (incident.openedorincident.resolved).X-CompleteStatus-Hook-Id— the subscription id the delivery belongs to.
Body schema (identical shape for both events):
{
"event": "incident.opened",
"severity": "critical",
"title": "Monitor DOWN: API",
"message": "API (https://api.example.com) is DOWN — HTTP 502 after 1.9s at TTFB. Since Wed, Jul 8, 2026 9:00 AM.",
"timestamp": "2026-07-08T09:00:00+00:00",
"timestamp_unix": 1783587600,
"monitor": {
"id": 12,
"name": "API",
"target": "https://api.example.com",
"type": "uptime"
},
"incident": {
"id": 42,
"cause": "HTTP 502",
"diagnosis": "HTTP 502 after 1.9s at TTFB",
"opened_at": "2026-07-08T09:00:00+00:00",
"resolved_at": null,
"url": "https://completestatus.com/incidents/42"
}
}
Field notes:
event—incident.openedorincident.resolved; the same value as theX-CompleteStatus-Eventheader.severity—criticalforincident.opened,okforincident.resolved.title/message— human-readable one-liners, ready to drop into a Slack step or an email body.timestamp/timestamp_unix— when the incident opened (forincident.opened) or resolved (forincident.resolved), ISO 8601 and Unix seconds.monitor.type— the monitor type (uptime,keyword,port,heartbeat, …).incident.diagnosis— the one-line failure diagnosis derived from incident forensics;nullwhen no forensics exist (fall back toincident.cause).incident.resolved_at—nullwhile the incident is open; set onincident.resolved.incident.url— deep link to the incident in CompleteStatus.
A 2xx response marks the delivery successful. Anything else — including redirects — counts as a failure.
Retries and auto-expiry
Deliveries follow the house retry conventions:
- Failed deliveries are retried automatically with increasing backoff (10 seconds, 1 minute, 5 minutes).
- Deliveries are deduplicated per (hook, incident, event) — a retry never re-POSTs an event a hook already received, so your workflow will not double-fire.
- Every failed attempt increments the hook's
consecutive_failurescounter; any success resets it to 0. - After 12 consecutive failed attempts (three incidents' worth of exhausted retries against a dead endpoint) the hook is auto-expired:
expired_atis set,activebecomesfalse, and deliveries stop. Re-subscribe (or have your Zap re-subscribe) to resume.
Hooks or the webhook channel?
- Use an automation hook when a platform manages the subscription itself (Zapier/Make/n8n REST-hook triggers) or when you want org-wide incident events without per-monitor routing.
- Use the webhook alert channel when you want per-monitor routing, cooldowns, and an HMAC-signed request to an endpoint you wrote yourself.
Related guides
- /docs/rest-api — API keys, authentication and the rest of the v1 surface.
- /docs/alert-channels — the 21 notification channel types.
- /docs/incidents-and-escalation — when incidents open and resolve.