Skip to main content
Verify each webhook in two steps: read the raw body, then call unwrap with the request headers.

Before you start

  • Save signing_secret from the subscription’s create response as RELAY_WEBHOOK_SECRET.
  • Read the raw body before any JSON middleware touches it; changed whitespace changes the signed bytes.

Verify with the SDK

unwrap checks the three webhook headers against the raw body and returns the parsed event. It throws when a header is missing, the signature does not match, or the body is not JSON. Configure the secret once on the client, or pass key per call when one receiver serves several subscriptions:
TypeScript SDK

Read the signature format

Relay signs requests with Standard Webhooks, so any Standard Webhooks library verifies them too. The signing input joins the ID and the timestamp with periods and appends the raw body. Relay strips the whsec_ prefix, base64-decodes the key, and computes HMAC-SHA256 over that input:
A retry reuses the event ID and body under a new timestamp, so deduplicate by event_id, never by the signature.

When it fails

Reject the request with 401 before you store anything when a header is missing or the signature does not match; delivery policy treats that as terminal. Reject a body that passes the signature but does not parse the same way. If your secret is missing, restore it from your secret store; the receiver example returns 401 for every case.

Next steps