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.

はじめる前に
  • 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.

よくある質問

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.

続けて読む

チャージして、キーを取得し、リリース。

セルフサーブ。暗号資産またはカードで支払い。クレジットで従量課金——重いプリミティブは高く、単純なものは安価。

APIキーを取得