An outbound webhook is a URL you own that Status Bee sends a POST to whenever something happens in a workspace: an incident opens, a maintenance window starts, a monitor goes down, a certificate is about to expire. Use it to page your on-call, mirror status into your own app, or drive a chat bot.
Webhooks are per workspace. A workspace can have as many as you like, each with its own URL, its own secret and its own list of events.
Create a webhook
In the dashboard, open Settings, then Webhooks, and add the URL. Pick the events you want, or leave the list empty to receive all of them. The signing secret is shown once, when the webhook is created. Store it with your other secrets; you will need it to verify deliveries.
The same thing through the API:
curl -X POST "https://api.statusbee.co/user/webhooks" \
-H "Authorization: Bearer sb_live_…" \
-H "Content-Type: application/json" \
-d '{
"workspace_id": 5,
"url": "https://ops.example.com/hooks/statusbee",
"events": ["incident.created", "incident.updated", "incident.resolved", "monitor.down", "monitor.up"]
}'{
"statusCode": 200,
"error": false,
"message": null,
"data": {
"id": 12,
"workspace_id": 5,
"org_id": 5,
"url": "https://ops.example.com/hooks/statusbee",
"events": ["incident.created", "incident.updated", "incident.resolved", "monitor.down", "monitor.up"],
"failure_count": 0,
"disabled_at": null,
"created_at": "2026-09-14T09:02:11.000Z",
"secret": "whsec_9f2c…"
}
}https://. Plain HTTP endpoints are rejected at creation.What a delivery looks like
Every delivery is a POST with a JSON body in this envelope. The data object is specific to the event type; see the event reference.
{
"id": "48213",
"type": "incident.created",
"created_at": "2026-09-14T02:14:36.418Z",
"workspace_id": 5,
"data": {
"incident_id": 91,
"title": "Checkout errors",
"status": "investigating",
"impact": "major",
"update_id": 240,
"body_md": "We are seeing elevated error rates on checkout and are investigating."
}
}Headers
Content-Typeheader- Always
application/json. X-Eventheader- The event type, the same value as
typein the body. Useful for routing before you parse anything. X-Delivery-Idheader{webhook_id}:{event_id}. Stable across retries of the same delivery, so you can drop duplicates.X-Signatureheadersha256=followed by the hex HMAC-SHA256 of the raw body, keyed with your webhook's secret. See Verify signatures.
Responding
Return any 2xx status within 10 seconds. The body is ignored. Do the work after you have acknowledged: a handler that takes longer than the timeout is treated as a failure and retried, and you will process the same event twice.
Redirects are not followed. Point the webhook at its final URL.
Which events go where
Webhooks receive the full event stream. Subscribers on your status page only hear about incidents and maintenance. The monitor events, component.status_changed, subscriber.created and page.published are for your systems, never for the public.
| Event | Webhooks | Status page subscribers |
|---|---|---|
| incident.created / updated / resolved | Yes | Yes, when the update has notifications on |
| maintenance.scheduled / reminder / started / completed | Yes | Yes |
| component.status_changed | Yes | No |
| monitor.down / up / ssl_expiring | Yes | No |
| subscriber.created, page.published | Yes | No |
Ordering and duplicates
Events are delivered in the order they happened for a given incident or window, one batch at a time. Across unrelated resources there is no ordering guarantee. Retries mean the same delivery can arrive more than once; use X-Delivery-Id to make your handler idempotent.