Every webhook delivery is signed with HMAC-SHA256 over a string built from a timestamp, nonce, and the raw body. Always verify the signature AND reject stale or replayed requests before processing events.Documentation Index
Fetch the complete documentation index at: https://docs.xquik.com/llms.txt
Use this file to discover all available pages before exploring further.
Headers sent with every delivery
Read these headers from each webhookPOST before parsing the JSON body. The
signature is the trust boundary; use Content-Type and User-Agent only for
handler routing and logs.
Timestamp
X-Xquik-Timestamp is Unix epoch milliseconds. Reject requests outside the
5-minute tolerance window.Nonce
X-Xquik-Nonce is 16 random bytes in hex. Store recent values for 5
minutes and reject repeats.Signature
X-Xquik-Signature is sha256=<hex> over
<timestamp>.<nonce>.<rawBody> keyed with the endpoint secret.Raw JSON body
Content-Type is always application/json. Verify the raw body bytes
before parsing or re-serializing JSON.Sender logs
User-Agent is xquik-webhooks/1.0 (+https://xquik.com). Log it for
diagnostics, but never trust it instead of the signature.How it works
- Xquik computes the signing string
<timestamp>.<nonce>.<rawBody>. - Xquik computes
sha256=+ HMAC-SHA256(webhook secret, signing string). - Your server recomputes the signature with the same secret over the raw body.
- Reject the request if the signature does not match in constant time.
- Reject the request if the timestamp is older than 5 minutes (clock-skew tolerant).
- Reject the request if the nonce was already seen in the last 5 minutes (replay protection).
Implementation
Security checklist
Always verify before processing
Always verify before processing
Never process webhook payloads without verifying the signature first. An unverified payload could be a spoofed request.
Use constant-time comparison
Use constant-time comparison
Use
timingSafeEqual (Node.js), hmac.compare_digest (Python), or hmac.Equal (Go). String equality (===) is vulnerable to timing attacks.Use the raw request body
Use the raw request body
Compute the HMAC over the raw request body bytes, not a re-serialized JSON object. Re-serialization can alter whitespace or key ordering.
Respond quickly
Respond quickly
We recommend responding within 10 seconds. Process events asynchronously if your handler is slow.
Idempotency
Webhook deliveries can be retried on failure, so your endpoint may receive the same event multiple times. UsedeliveryId as the webhook delivery idempotency key. Use streamEventId when your system should process one monitor event only once across webhook retries or endpoint changes. Do not hash the raw request body when deliveryId is available.