Webhook signature verification failed. No signatures found matching the expected signature for payload

Stripe webhook fails signature check? Usually the wrong whsec_ secret or your framework changed the raw request body. Here's the fix.

Reviewed October 14, 2026

What it means in plain English

Stripe signs every webhook so your app can be sure it's genuine. This error means the check failed: one of the three ingredients (raw body, signature header, signing secret) is wrong.

Likely causes

  • Wrong signing secret: Stripe says this is the most common cause. The CLI (stripe listen) secret differs from the Dashboard endpoint secret.
  • Using a test-mode secret on a live-mode endpoint (or vice versa).
  • Your framework parsed the body as JSON before verification (e.g. Express express.json() before the webhook route, Next.js Pages Router body parser).
  • The env var holding the secret is missing in production.

How to fix it, step by step

  1. Stripe Dashboard → Workbench → Webhooks → open your production endpoint → Reveal secret. It starts whsec_.
  2. Put it in your host's env vars (e.g. STRIPE_WEBHOOK_SECRET) for Production, then redeploy.
  3. Make sure the code verifies the raw body:
    • Next.js App Router: read await req.text() and pass that string to stripe.webhooks.constructEvent.
    • Next.js Pages Router: disable bodyParser for that route and use the raw buffer.
    • Express: register the webhook route with express.raw({type: 'application/json'}) before app.use(express.json()).
  4. Read the signature from the Stripe-Signature header (should look like t=…,v1=…).
  5. Ask your AI tool: "Verify the Stripe webhook using the raw request body and STRIPE_WEBHOOK_SECRET; don't parse JSON first."

How to check it worked

  • In Workbench → your endpoint → Event deliveries, resend a recent event; it should show 200.
  • Check your server logs for the signature error disappearing.

Sources

Can't fix it? Get help.

If the steps didn't clear the error, send what the screen says. A person can take a look. This is a request for a paid fix, not an instant chat.

Request a fix