Every webhook delivery includes a cryptographic signature so you can verify the request came from your Exo app, not from a third party.Documentation Index
Fetch the complete documentation index at: https://docs.exowizz.com/llms.txt
Use this file to discover all available pages before exploring further.
How signing works
When Exo sends a webhook, it:- Serializes the JSON payload
- Computes an HMAC-SHA256 hash using the subscription’s secret as the key
- Sends the hash in the
X-Exo-Signatureheader, prefixed withsha256=
User-Agent: Exo-Webhook/1.0 header.
For traceability, Exo also sends X-Exo-Event and X-Exo-Delivery headers.
Verifying in your receiver
To verify a webhook delivery, compute the same HMAC hash on your end and compare it to the signature header.- PHP
- Node.js
- Python
Important notes
- Always use a constant-time comparison function (like
hash_equalsin PHP orhmac.compare_digestin Python) to prevent timing attacks. - The signature is computed on the raw JSON body of the request, not on any parsed or reformatted version. Make sure you read the raw body before parsing.
- Each webhook subscription has its own unique secret, generated when the subscription is created. If you have multiple subscriptions, use the correct secret for each one.
Webhook request format
Every webhook delivery is an HTTP POST with these headers:| Header | Value |
|---|---|
Content-Type | application/json |
X-Exo-Signature | sha256= followed by the hex-encoded HMAC hash |
X-Exo-Event | Event UUID |
X-Exo-Delivery | Delivery UUID |
User-Agent | Exo-Webhook/1.0 |
Handling failures
If your webhook receiver returns a non-2xx status code or times out, Exo retries using configured attempt limits and backoff values (global settings inconfig/exo.php, or per Resource overrides through webhookMaxAttempts() and webhookBackoff()).