Stripe webhook signature verification
Stripe signs each webhook delivery in the Stripe-Signature header. Verification must use the exact raw request body and the endpoint signing secret for the destination that received the event.
Most Stripe signature failures are caused by body parsing, an incorrect whsec_ secret, or a timestamp outside the allowed tolerance.
Requirements
- Read the Stripe-Signature header from the incoming request.
- Preserve the request body exactly as received before JSON parsing or re-serialization.
- Use the endpoint signing secret, which begins with whsec_, rather than a Stripe API key.
- Use the official Stripe SDK verification helper where one is available for your language.
Node.js example
javascript
import express from 'express';
import Stripe from 'stripe';
const app = express();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = stripe.webhooks.constructEvent(
req.body,
req.headers['stripe-signature'],
process.env.STRIPE_WEBHOOK_SECRET
);
res.status(200).json({ received: true, type: event.type });
} catch (error) {
res.status(400).send('Invalid Stripe signature');
}
});Why verification fails
| Error pattern | What to check |
|---|---|
| No matching signature | Confirm the raw body, endpoint secret, and Stripe-Signature header. |
| Timestamp outside tolerance | Check server time and use a newly delivered event. |
| Missing header | Confirm the request came from Stripe and that proxies preserve the header. |
| Works locally but not in production | Compare middleware order, body decoding, and environment-specific secrets. |
Diagnose with captured evidence
- Open the captured request and confirm the Stripe-Signature header is present.
- Compare the endpoint environment in Stripe with the whsec_ secret loaded by the application.
- Check whether the framework exposed bytes, a string, or an already parsed object to the verifier.
- Use the reconstruction result to identify whether extraction, digest comparison, or timestamp validation diverged.
- Send a new Stripe test event after changing middleware or secrets.
Verify the fix
Verification is fixed when a new Stripe delivery passes signature validation using the raw body, the handler returns 2xx, and the same event ID is not processed twice.