Skip to main content

Notification Webhooks

A notification policy with the webhook channel sends each matching event to your HTTPS endpoint as a JSON POST. Each delivery is signed, so your endpoint can reject any request that Qumo did not send.

The signing secret

When you create a webhook policy, Qumo generates its signing secret and returns it once, in the create response (signing_secret). In the console, it appears once, right after you create the policy. No later response returns it. Store it with your receiver’s other secrets. To change the secret, delete the policy and create it again. The new policy has a new secret.
Webhook policies created before signing was introduced have no secret. Qumo still delivers to them, unsigned, so existing receivers keep working. To start verifying, delete the policy and create it again.

What a delivery carries

The signature covers the timestamp as well as the body. A captured delivery therefore cannot be replayed later with a new timestamp, and your receiver can reject an old one by checking its age.

Verifying a delivery

  1. Read the raw request body before parsing it. Re-serialized JSON is not byte-for-byte the same, so its signature will not match.
  2. Compute HMAC-SHA256 over the X-Notification-Timestamp value, a ., and the raw body, using the signing secret as the key. Hex-encode the result in lowercase.
  3. Compare it with X-Notification-Signature-256 using a constant-time comparison.
  4. Reject the delivery if the timestamp is more than a few minutes from your clock. Five minutes is a reasonable window.
A delivery with no signature headers comes from a policy created before signing was introduced. Once you have recreated the policy, reject unsigned deliveries.

Retries

A delivery that fails with a network error or a 5xx response is retried with exponential backoff for up to five minutes. Each attempt is signed again with a fresh timestamp. Use the body’s notification_id to drop duplicates. Slack and Discord policies are not signed. Those services authenticate the sender through the secret in the webhook URL itself.