Signature headers
Each request includes three headers:Verification steps
1
Extract the headers
Read the
webhook-id, webhook-timestamp, and webhook-signature headers from the incoming request.2
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.
3
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.4
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.5
Check the timestamp
Verify that
webhook-timestamp is within 5 minutes of the current time to prevent replay attacks. Reject requests with timestamps outside this window.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