X-Kibble-Signature header. The value is an HMAC-SHA256 digest of the raw request body, computed using the webhook_secret that was returned when you created the invoice. Verifying this signature ensures the request came from Kibble and that the payload was not tampered with in transit.
How verification works
- Read the raw bytes of the incoming request body — before any JSON parsing.
- Compute
HMAC-SHA256(raw_body, webhook_secret)and encode the result as a lowercase hex string. - Prepend
sha256=to form the expected signature. - Compare it to the value in the
X-Kibble-Signatureheader using a constant-time comparison.
401.
Code examples
Storing the secret
Store thewebhook_secret as an environment variable alongside your other credentials. Never hard-code it in source files or commit it to version control.
webhook_secret. Store them mapped to their invoice_id — for example, in your database next to the invoice record — so you can look up the correct secret when a webhook arrives.
Reading the raw body
Most web frameworks parse the request body automatically, which loses the original bytes needed for verification. You must access the raw, unparsed body to compute the correct digest.- Next.js (App Router)
- Express
- Fastify
If your signature comparison fails unexpectedly, confirm you are reading the raw body as a string (UTF-8). JSON re-serialization changes whitespace and key ordering, producing a different digest.