Payments

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.

Başlamadan önce
  • 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.

Sıkça sorulanlar

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.

Okumaya devam et

Bakiye yükle, anahtarını al, yayına çık.

Self servis. Kripto ya da kartla öde. Krediyle ölçümlenir — ağır ilkel yapılar daha pahalı, basitler ucuz.

API anahtarı al