Verify Stripe Webhook Signatures
Stripe signs every webhook with an HMAC-SHA256 over a timestamped payload and sends it in the Stripe-Signature header (e.g. t=1614265330,v1=…). Verifying it prevents spoofed events and replay attacks. Paste the raw request body, your endpoint signing secret and the header below.
Everything runs in your browser — the payload and secret never leave this page. Want to verify a different provider? See the webhook signature verifier hub or the generic HMAC generator.
How Stripe signs webhooks
- Read the
t(timestamp) andv1(signature) values from theStripe-Signatureheader. - Build the signed payload string: the timestamp, a literal
., then the raw request body. - Compute HMAC-SHA256 of that string using your endpoint signing secret (
whsec_…) as the key, hex-encoded. - Compare it to
v1with a constant-time check, and reject events whose timestamp is too old.
Reference: Stripe signature documentation.
Verify Stripe signatures in code
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
// req.body must be the RAW body (Buffer/string), not parsed JSON.
const sig = req.headers['stripe-signature'];
try {
const event = stripe.webhooks.constructEvent(
req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
// event is verified — handle it
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}import stripe
sig_header = request.headers['Stripe-Signature']
try:
event = stripe.Webhook.construct_event(
request.data, sig_header, endpoint_secret)
# event is verified — handle it
except stripe.error.SignatureVerificationError:
return '', 400Frequently asked questions
What is the Stripe-Signature header?
It is the header Stripe adds to every webhook, formatted like t=1614265330,v1=5257a8…. t is the unix timestamp and v1 is the HMAC-SHA256 signature you verify.
Why does verification fail even with the right secret?
Almost always because the body was re-serialized. Stripe signs the exact raw bytes it sent, so you must verify against the unparsed request body — not JSON.stringify(req.body).
Which secret do I use?
The endpoint signing secret that starts with whsec_, shown in the Stripe Dashboard under Developers → Webhooks for that specific endpoint. It is not your API key.
Verify other providers
Receiving Stripe webhooks on a server behind a firewall or on localhost? Webhook Relay can forward them to your internal service and even verify or transform them before delivery.
