Skip to main content
When you receive a webhook from Exa, you should verify that it came from us to ensure the integrity and authenticity of the data. Exa signs all webhook payloads with a secret key that’s unique to your webhook endpoint.

How Webhook Signatures Work

Exa uses HMAC SHA256 to sign webhook payloads. The signature is included in the Exa-Signature header, which contains:
  • A timestamp (t=) indicating when the webhook was sent
  • One or more signatures (v1=) computed using the timestamp and payload
The signature format looks like this:

Verification Process

To verify a webhook signature:
  1. Extract the timestamp and signatures from the Exa-Signature header
  2. Create the signed payload by concatenating the timestamp, a period, and the raw request body
  3. Compute the expected signature using HMAC SHA256 with your webhook secret
  4. Compare your computed signature with the provided signatures


Security Best Practices

Following these practices will help ensure your webhook implementation is secure and robust:
  • Always Verify Signatures - Never process webhook data without first verifying the signature. This prevents attackers from sending fake webhooks to your endpoint.
  • Use Timing-Safe Comparison - When comparing signatures, use functions like hmac.compare_digest() in Python or crypto.timingSafeEqual() in Node.js to prevent timing attacks.
  • Check Timestamp Freshness - Consider rejecting webhooks with timestamps that are too old (e.g., older than 5 minutes) to prevent replay attacks.
  • Store Secrets Securely - Store your webhook secrets in environment variables or a secure secret management system. Never hardcode them in your application. Important: The webhook secret is only returned when you create a webhook - make sure to save it securely as it cannot be retrieved later.
  • Use HTTPS - Always use HTTPS endpoints for your webhooks to ensure the data is encrypted in transit.
  • Register the Final URL - Webhook deliveries do not follow HTTP redirects (3xx responses). If your endpoint redirects, the delivery will be treated as a failure. Always register the URL that directly handles the payload.


Troubleshooting

Invalid Signature Errors

If you’re getting signature verification failures:
  1. Check the raw payload: Make sure you’re using the raw request body, not a parsed JSON object
  2. Verify the secret: Ensure you’re using the correct webhook secret from when the webhook was created
  3. Check header parsing: Make sure you’re correctly extracting the timestamp and signatures from the header
  4. Encoding issues: Ensure consistent UTF-8 encoding throughout the verification process

Testing Signatures Locally

You can test your signature verification logic using the webhook secret and a sample payload:
Python


What’s Next?