Skip to main content
A visitor can connect a webhook from a status page’s subscribe form (see Subscribe to a status page). This page describes what that endpoint receives.
Subscriber webhooks vs. operator webhooksSubscriber webhooks are created by visitors on the public page and only carry incident and maintenance updates for that page. Operator webhooks are created on the Alerts page as a Generic webhook integration, carry more event types, and use a different body. See the webhook payload reference for those. Both use the same signature scheme.

Request

Every delivery is an HTTPS POST with a JSON body.
Every subscriber webhook has a signing secret, so the signature headers are always present.

Events

There is no separate event when a maintenance window starts: maintenance.starting_soon covers it. Incident edits that are not a posted update, deletions, and anything on a draft send nothing. When an update closes an incident (a Resolved update), only incident.resolved (or maintenance.completed) is sent for it, not an additional incident.message_added. The subscriber notification events reference explains which subscribers receive each event.

Payloads

Updates

Every incident and maintenance event uses the same shape.
incident.published
incident.message_added
maintenance.scheduled
incident.resolved, maintenance.starting_soon, maintenance.completed, and maintenance.canceled have the same fields; only event, headline, and the content differ.

Test message

Sent when the webhook is connected. The subscription is created only if your endpoint answers this request with a 2xx status.
subscription.connected
It carries no event_id or incident_id. It is signed like every other delivery.

Verify the signature

The signing secret is shown once, in the subscribe form, when the webhook is connected. It starts with whsec_. Use the whole string, prefix included, as the HMAC key. To verify a delivery:
  1. Read X-Observer-Timestamp. Reject the delivery if it is more than five minutes from your server’s clock. This bounds replay of a captured request.
  2. Compute HMAC-SHA256 with the secret as the key over ${timestamp}.${rawBody}: the timestamp header value, a period, and the request body exactly as received. Hex-encode the digest and prepend sha256=.
  3. Compare the result with X-Observer-Signature using a constant-time comparison. Reject the delivery if they differ.
Hash the raw request bytes. Parsing the JSON and serializing it again can change whitespace or key order and break the signature.
server.js

Delivery behaviour

  • Timeout: your endpoint must answer within 10 seconds.
  • Success: any 2xx status. The response body is ignored.
  • Failure: any other status, a timeout, a network error, or a redirect. Redirects are never followed; configure the final URL.
  • No retries: each event is sent once per subscription. A failed delivery is recorded and is not retried, and the subscription stays connected for the next event. If you cannot afford to miss an update, poll the page’s feed or JSON status as a backstop.
  • Duplicates: rare, but possible if processing is interrupted after a delivery. Use event_id to discard repeats.
  • Address checks: the URL must resolve to a public address on every delivery. A URL that later resolves to a private address is refused.

Rotate the secret or disconnect

Open the subscription’s manage_url (also linked as Manage subscription after connecting) and click Disconnect Webhook. Disconnecting stops all deliveries and deletes the stored URL and signing secret. There is no in-place secret rotation. To get a new secret, disconnect the subscription, then connect the same URL again from the status page’s subscribe form. The new subscription has a new secret and a new manage_url. Submitting a URL that is still connected does not issue a new secret; it only sends another subscription.connected test message.