whsec_… secret. Verify the signature before you trust the payload.
With the SDK
The SDK checks the signature and the timestamp, then returns the parsed event. It throwsWebhookVerificationError if either check fails.
Without the SDK
- Build the signed content:
{webhook-id}.{webhook-timestamp}.{raw body}. - Strip
whsec_from the secret and base64-decode the rest to get the key. - Compute HMAC-SHA256 of the signed content and base64-encode it.
- Compare
v1,<result>with each space-separated value inwebhook-signature, in constant time. - Reject the request if
webhook-timestampis more than 5 minutes from your clock.
Test locally
Send a correctly signed sample event to your handler with the CLI. Anywhsec_ plus base64 value works as a test secret.
Respond and retry
- Return any
2xxwithin 10 seconds. Do slow work after you respond. - Anything else is a failure:
3xx(redirects aren’t followed),4xx,5xx, a timeout, or a URL that now resolves to a private address. - Deliveries can repeat. Deduplicate on the
webhook-idheader, which stays the same across retries. - Order isn’t guaranteed. Use the event’s
created_at, or fetch the invoice.
After the sixth retry fails, the delivery is dropped.
Deliveries currently go out once a day at 03:00 UTC, so in practice each retry happens on the next daily run, about a day apart.
"active": false and a disabled_at time, and stops receiving events. Any successful delivery resets the count. To start again, delete the endpoint and register it again.