The Signature Header
Every webhook request Zolt sends includes two security-related HTTP headers:
The value of
X-Zolt-Signature is always formatted as sha256=<hex_digest>, where <hex_digest> is the lowercase hexadecimal HMAC-SHA256 of the raw request body bytes using your webhook’s signing secret as the key.
Verifying the Signature
Compute the expected HMAC-SHA256 signature from the raw, unparsed request body and your signing secret, then compare it to the value inX-Zolt-Signature using a timing-safe function. Do not parse the JSON before computing the HMAC — any whitespace normalization will produce a different digest.
Your Webhook Secret
Each webhook endpoint you register has its own unique signing secret. Zolt generates this secret automatically and reveals it exactly once — either in the dashboard dialog immediately after you click Save, or in thesecret field of the API response when you create the endpoint programmatically.
POST /v1/webhooks response (secret shown once)
- Store it immediately. Zolt does not display or return the secret again after the initial response. If you lose it, you must rotate to a new secret.
- Keep it in a secrets manager. Use an environment variable or a dedicated secrets store (such as AWS Secrets Manager, HashiCorp Vault, or your platform’s equivalent) — never hard-code it in source files.
- Rotate it if compromised. If you suspect your secret has been exposed, go to Settings → Developer → Webhooks, select the affected endpoint, and click Rotate Secret. Zolt will generate a new secret and immediately start signing deliveries with it. Update your handler with the new value before the rotation takes effect to avoid downtime.
Different endpoints have different secrets. If you register multiple webhook endpoints (for example, one for a production environment and one for staging), each endpoint has its own independent secret. Store and use the correct secret per endpoint.
Replay Attack Prevention
A replay attack occurs when an attacker captures a legitimate webhook delivery and re-sends it to your endpoint later to trigger your handler a second time. Even if the signature is valid, processing a weeks-old event as if it just happened can corrupt your data or trigger unintended side effects. Zolt includes aX-Zolt-Timestamp header with every request, set to the Unix timestamp (in seconds) at which Zolt generated the delivery. To defend against replay attacks, check that this timestamp is within an acceptable window of your server’s current time — a threshold of 5 minutes is recommended:
Replay attack check (Node.js)
Ensure your server’s system clock is synchronized with NTP. Clock drift can cause legitimate deliveries to fail the timestamp check if your server time is significantly out of sync with Zolt’s servers.