Verify a payment webhook signature
A payment webhook tells you an invoice settled — but only a verified one is safe to act on. Each delivery carries an X-Signature header holding an HMAC-SHA256 of the raw body. Recompute it with your signing secret and reject anything that does not match.
- Your webhook signing secret from the dashboard
- Access to the raw, unparsed request body
1Read the raw body and signature header
Compute the HMAC over the exact bytes you received. Parsing to JSON and re-serializing can reorder keys and break the digest, so capture the raw body before any middleware touches it.
> POST /webhooks/1st-node
> X-Signature: 4f1c...9ab2
> { "invoice": "in_8fK2", "status": "settled", "amount_usd": 49 }2Recompute the HMAC and compare
HMAC-SHA256 the raw body with your signing secret and compare against X-Signature in constant time. On any mismatch, return 400 and drop the event — do not credit the order.
const h = crypto.createHmac("sha256", SIGNING_SECRET)
.update(rawBody).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(h),
Buffer.from(req.header("X-Signature")))) return res.status(400).end();3Act only on verified settled events
Once the signature verifies, branch on status: pending, underpaid, overpaid or settled. Credit the order only on settled, and record the invoice id so a redelivery is a no-op.
Perguntas frequentes
Why must I use the raw body, not the parsed JSON?
Re-serializing JSON can change whitespace and key order, which changes the digest and makes a valid signature fail. Always HMAC the exact bytes received.
What happens if the signature does not match?
Reject it — return 4xx and ignore the payload. A mismatch means the body was altered or the sender lacks your secret, so it must never credit an order.
Continue lendo
Recarregue, pegue a chave e publique.
Autoatendimento. Pague em cripto ou cartão. Medido por créditos: primitivas pesadas custam mais, as simples são baratas.
Obter chave de API