Every webhook POST that Off the Hook sends to your endpoint includes a fixed set of HTTP headers. Three of these —Documentation Index
Fetch the complete documentation index at: https://docs.offthehook.dev/llms.txt
Use this file to discover all available pages before exploring further.
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
| Header | Example value | Description |
|---|---|---|
content-type | application/json | Always application/json — the body is always a JSON object |
webhook-id | evt_8xN9kP2QbA... | Unique event ID; stays the same across every retry of the same event — use it for deduplication |
webhook-timestamp | 1730000000 | Unix timestamp in seconds when the webhook was created |
webhook-signature | v1,<base64> | HMAC-SHA256 signature; multiple space-separated values appear during secret rotation |
x-oth-subscription-id | sub_2QkP9aB7xN... | The subscription that triggered this delivery — useful for routing in a shared endpoint |
user-agent | OffTheHook/0.1 | Identifies Off the Hook as the sender |
Signature format
Thewebhook-signature header contains one or more space-separated signature tokens, each prefixed with the version string v1,:
${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 returns5xx, 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 thewebhook-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().