Browse the docs

How webhooks work

One HTTPS endpoint per workspace, thirteen event types, a signature on every delivery.

On this page
  1. Create a webhook
  2. What a delivery looks like
  3. Headers
  4. Responding
  5. Which events go where
  6. Ordering and duplicates

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:

Request
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"]
  }'
Response
{
  "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…"
  }
}
The URL must be 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.

Body
{
  "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 type in 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-Signatureheader
sha256= 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.

EventWebhooksStatus page subscribers
incident.created / updated / resolvedYesYes, when the update has notifications on
maintenance.scheduled / reminder / started / completedYesYes
component.status_changedYesNo
monitor.down / up / ssl_expiringYesNo
subscriber.created, page.publishedYesNo

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.