Webhook Verification Using Secrets
processing steps read the raw request body (before json parsing) read the signature header compute hmac sha256 and compare examples value source where it comes from your webhook secret you (dashboard) integration information → webhook secret should also be stored securely in your system raw webhook request body detected (inbound post) exact http body — do not re parse or re serialize json signature header from webhook detected (inbound post) http header name is "signature" (capital s) value is 64 char lowercase hex const crypto = require('crypto'); // webhooksecret > your secret from dashboard (webhook secret field) // rawbody > received raw http body from detected post // signatureheader > received value of header "signature" (capital s) function verifydetectedwebhook(rawbody, webhooksecret, signatureheader) { const expected = crypto createhmac('sha256', webhooksecret) update(rawbody, 'utf8') digest('hex'); const a = buffer from(expected, 'utf8'); const b = buffer from(signatureheader trim(), 'utf8'); if (a length !== b length) return false; return crypto timingsafeequal(a, b); } // webhooksecret = process env webhook secret (same as dashboard) // signatureheader = req headers\['signature'] || req headers\['signature']import hashlib import hmac \# webhook secret > your secret from dashboard (webhook secret field) \# raw body > received raw http body from detected post \# signature header > received value of header "signature" (capital s) def verify detected webhook(raw body, webhook secret, signature header) expected = hmac new( webhook secret encode('utf 8'), raw body encode('utf 8'), hashlib sha256, ) hexdigest() return hmac compare digest(expected, signature header strip()) \# webhook secret = os environ\['webhook secret'] \# raw body = request get data(as text=true) \# signature header = request headers get('signature', '') common mistakes mistake result sha256(body + secret) plain hash verification fails — use hmac sha256 re serialize json after parsing verification fails — use raw body base64 encode the digest verification fails — use lowercase hex wrong secret (different webhook type) verification fails