Skip to main content
Every webhook request includes a signature so you can verify it was sent by Formable and wasn’t tampered with in transit. Always verify the signature before acting on a webhook.

How HMAC validation works

Anyone who learns your webhook URL could send a fake POST to it. HMAC Signature verification stops that: Formable and your server share a secret that only the two of you know. On every delivery, Formable uses that secret to stamp the request body, and you check the stamp before trusting the event. Think of it like a wax seal on a letter:
  1. Formable takes the exact request body and your signing secret, and runs them through a one-way function (HMAC-SHA256). The result is a short fingerprint.
  2. That fingerprint is sent in the Content-Sha256 header.
  3. Your server repeats the same calculation with the same secret and the raw body you received.
  4. If your fingerprint matches the header, the body came from Formable and wasn’t altered. If it doesn’t match, reject the request.
An attacker without the secret can’t forge a matching fingerprint. Changing even one character of the body produces a different fingerprint, so tampering is caught too. Use the signing secret Formable showed once when you registered the webhook. Store it as an environment secret and use that same value to verify every request.
Your signing secret is provided as a base64-encoded string. Decode it to raw bytes and use those bytes as the HMAC key.
If you misplaced the secret or don’t remember it, Formable cannot show it again. Rotate it from Settings → Webhooks → Rotate secret, copy the new secret when it’s shown, and update your environment. The previous secret stops working immediately. To verify a request:
1

Read the raw body

Capture the request body exactly as received, before any JSON parsing or re-serialization. Re-serializing can change whitespace or key order and break verification.
2

Compute the expected signature

HMAC-SHA256 the raw body using the base64-decoded secret as the key, then base64-encode the digest.
3

Compare

Compare your computed value with the Content-Sha256 header using a constant-time comparison. If they match, the request is authentic.

Examples

Common pitfalls

Frameworks that auto-parse JSON discard the original bytes. Re-serializing the parsed object almost always produces a slightly different string (whitespace, key order), so the HMAC won’t match. Always sign over the raw request body.
The secret is a base64 string. Use its decoded bytes as the HMAC key — don’t pass the base64 string directly.
Compare signatures with a constant-time function (crypto.timingSafeEqual, hmac.compare_digest, hash_equals) to avoid timing attacks.
Keep your signing secret confidential. If it is exposed, misplaced, or forgotten, rotate it from Settings → Webhooks → Rotate secret and update your verifier right away.