You manage webhooks from the developer dashboard. Open your workspace’s Webhooks page (Admin role
or higher) to add an endpoint, copy its signing secret, send a test event, read the delivery log, replay a delivery
that failed, and rotate the secret. The secret is shown once, when the endpoint is created or rotated — copy it
then. Outside Production, only test-mode endpoints on a Sandbox-plan workspace are ever called; a live endpoint is
never called outside production.
The headers
Each delivery carries three headers:What gets signed
The signature covers the exact bytes of the id, the timestamp, and the raw request body, joined by periods:Computing the signature
Your endpoint’s signing secret looks likewhsec_ followed by 48 lowercase hex characters. Decode the hex characters
to their raw bytes first — the secret is not used as a literal string.
signed_content using key_bytes, base64-encode the result, and prefix it with v1,.
Compare it against each value in webhook-signature (there may be more than one during a secret rotation — see
below) using a constant-time comparison, never a plain ===/==.
Also check the timestamp
Reject a delivery whosewebhook-timestamp is too far in the past (a replayed request) or the future (a clock
skew you can’t explain) — five minutes either way is a reasonable window. This is a separate check from the
signature itself; a valid signature on an old, replayed request is still a replay.
Secret rotation — why you may see two signatures
Rotating an endpoint’s secret does not invalidate deliveries in flight. For the rotation’s overlap window (24 hours by default),webhook-signature carries two v1,... values, one for the outgoing secret and one for the new
one, space-separated in the single header. Verify against a signature that matches either — never require both.
See also
- Handling retries and duplicates
- Permissions — what a webhook’s event type requires