Skip to main content
Every webhook POST that Off the Hook sends to your endpoint includes a fixed set of HTTP headers. Three of these — webhook-id, webhook-timestamp, and webhook-signature — are defined by the Standard Webhooks specification and are what the Svix verification libraries expect. The remaining headers are either standard HTTP conventions or Off the Hook extensions.

Headers

Signature format

The webhook-signature header contains one or more space-separated signature tokens, each prefixed with the version string v1,:
During a secret rotation grace period, both the new and old secrets are active simultaneously. Off the Hook signs the payload with both secrets and includes both signatures in a single header value, new secret first:
Your verification code should accept a delivery if any of the provided signatures matches your current secret. The Svix library handles this automatically. The signature covers the string ${webhook-id}.${webhook-timestamp}.${body} — the event ID, timestamp, and raw request body concatenated with literal periods and HMAC-SHA256 signed with your subscription secret.

Deduplication

Off the Hook retries deliveries when your endpoint returns 5xx, 408, 429, or the connection fails entirely. Every retry of the same event uses the same webhook-id value. Store the IDs you have already successfully processed and skip any delivery that arrives with a duplicate ID, returning 2xx so the retry stops.

Timestamp validation

Reject any delivery where the webhook-timestamp is more than 5 minutes older than the current time. This defends against replay attacks where a valid captured request is re-sent to your endpoint later. The Svix verification library enforces this window automatically when you call wh.Verify().
For full signature verification examples in TypeScript, Go, Python, and other languages, see Verify Webhook Signatures.