Signature headers
Each request includes three headers:| Header | Description |
|---|---|
webhook-id | Unique identifier for this delivery |
webhook-timestamp | Unix timestamp (seconds) of when the request was sent |
webhook-signature | HMAC-SHA256 signature of the request |
Verification steps
Extract the headers
Read the
webhook-id, webhook-timestamp, and webhook-signature headers from the incoming request.Construct the signature base string
Concatenate the webhook ID, timestamp, and raw request body, separated by periods:Use the raw request body as received — do not parse and re-serialize the JSON.
Compute the expected signature
Sign the base string using HMAC-SHA256 with your webhook signing secret (the
whsec_ prefixed value from your webhook settings, with the prefix stripped before use as the key).Base64-encode the resulting hash.Compare signatures
The Extract the signature after
webhook-signature header contains the signature in the format:v1, and compare it to your computed value using a constant-time comparison to prevent timing attacks.Example implementations
Troubleshooting
Signature verification fails on every request
Signature verification fails on every request
- Confirm you’re using the correct signing secret from your webhook settings
- Make sure you’re stripping the
whsec_prefix before using the secret as a key - Verify you’re using the raw request body, not a parsed/re-serialized version
- Check that your base string format is exactly
{webhook-id}.{timestamp}.{body}with period separators
Requests rejected for timestamp
Requests rejected for timestamp
- Ensure your server clock is synchronized (use NTP)
- The tolerance window is 5 minutes — requests outside this window are considered invalid
Test ping works but production events fail
Test ping works but production events fail
- Confirm your endpoint returns a
2xxstatus within 10 seconds - Check that your endpoint handles the larger payloads of production events
- Review delivery logs in the Outhire admin UI for specific error details