Stripe: No signatures found matching the expected signature for payload
StripeSignatureVerificationError: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?In one sentence: Your webhook couldn't prove the event came from Stripe, usually because the body was parsed before verification or the webhook secret is wrong.
What it means
Stripe signs every webhook event. Your server has to check that signature using the exact raw bytes of the request and your webhook signing secret (it starts with `whsec_`). If even one byte differs, or the secret is wrong, verification fails.
In AI-built apps this usually happens because the framework already turned the body into JSON, or because the secret from the Stripe CLI, test mode and live mode got mixed up. Until it's fixed, paid orders and subscriptions won't be recorded.
Common causes
- The request body was parsed as JSON (`req.json()`, `express.json()`, `bodyParser`) before being passed to `constructEvent`.
- Using the wrong signing secret: the Stripe CLI secret in production, the test-mode secret for live events, or a secret from a different endpoint.
- The `STRIPE_WEBHOOK_SECRET` environment variable is missing on the host (e.g. Vercel) or wasn't redeployed after being added.
- A redirect (http to https, or `www` to non-`www`) changes the request before it reaches your handler.
How to fix it
- Pass the raw body to Stripe. In a Next.js App Router route use `await req.text()`; in Express use `express.raw({ type: 'application/json' })` on the webhook route only.
- Copy the signing secret from the exact endpoint in Stripe Dashboard → Developers → Webhooks (test and live endpoints have different secrets), and use the `stripe listen` secret only for local testing.
- Set it as an environment variable on your host and redeploy.
- Point the webhook at the final URL (the exact domain, with https) so no redirect happens, then resend a test event from the Stripe dashboard.
Before
const body = await req.json(); // parsed: signature check fails
stripe.webhooks.constructEvent(JSON.stringify(body), sig, secret);After
// app/api/stripe/webhook/route.ts
export async function POST(req: Request) {
const body = await req.text(); // raw body
const sig = req.headers.get("stripe-signature")!;
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
// ...handle event
return new Response("ok");
}Tried this and it's still broken? Paste your exact error for a free explanation of your specific case.
Prompt to paste into your AI tool
My Stripe webhook fails with 'No signatures found matching the expected signature for payload'. Make the webhook route read the raw request body (req.text() in Next.js App Router, express.raw on just this route in Express) and pass it unchanged to constructEvent, read the secret from STRIPE_WEBHOOK_SECRET, and don't change any other billing logic.Still stuck?
Paste your exact error and code. Get a plain-English explanation free, or the full fix for $5.
Hitting errors every day? Builder is $15/mo for 100 fixes per month. Compare plans
Related errors
- Next.js Image: hostname is not configured under images in next.config.js
- TypeError: Cannot read properties of undefined
- CORS error: blocked by CORS policy
- Hydration failed: server HTML didn't match the client (Next.js)
Weekly: the errors breaking vibe-coded apps and how to fix them. Free.
No spam. Unsubscribe anytime.