StripePaymentsAPI

Stripe: No signatures found matching the expected signature for payload

StripeSignatureVerificationError: No signatures found matching the expected signature for payload.

In short: Stripe signs the raw request body. Your code verified a parsed or modified body, or used the wrong signing secret.

Why it happens

Frameworks parse JSON automatically, and re-serialized JSON no longer matches Stripe's signature. The other common cause is the wrong whsec_ secret: the Stripe CLI (stripe listen) prints its own secret that differs from the dashboard endpoint's secret, and test vs. live endpoints each have their own.

How to fix it

  1. Verify with the raw body: in Next.js App Router use await req.text(); in Express use express.raw({ type: 'application/json' }) on that route only.
  2. Pass the exact stripe-signature header to stripe.webhooks.constructEvent(rawBody, sig, secret).
  3. Local testing: use the secret printed by stripe listen. Production: use the secret from that endpoint in the Dashboard (Developers → Webhooks).
  4. Check you're using test-mode secrets with test events and live with live.
  5. Return a 2xx quickly and do slow work afterwards so Stripe doesn't time out and retry.

Example

// app/api/stripe/webhook/route.ts
export async function POST(req: Request) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature")!;
  const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  // handle event.type ...
  return new Response(null, { status: 200 });
}
Don't: Don't skip signature verification. Anyone could then POST fake 'payment succeeded' events to your endpoint.

Copy-paste fix prompt

3 · The fix promptPaste into Cursor, Claude Code, Codex, Lovable, Bolt, Replit or v0
I'm getting this error in my app:

StripeSignatureVerificationError: No signatures found matching the expected signature for payload.

[Paste the full error, stack trace, and the file it points to here]

Likely cause: Stripe signs the raw request body. Your code verified a parsed or modified body, or used the wrong signing secret.

Task: Make my Stripe webhook route verify the signature against the raw request body with the correct endpoint secret for each environment, without disabling verification.

Rules:
- First explain the root cause in 2 sentences and list the files you'll change.
- Make the smallest change that fixes it. Don't refactor unrelated code.
- Don't disable security or checks (RLS, auth, signature verification, type checking, CORS allow-all) to make the error disappear.
- Never print or hard-code secret keys.
- Finish by telling me exactly how to verify the fix.

Common with: Cursor, Bolt, Lovable, Replit. Last reviewed 2026-11-13.

Related fixes

← All fixes · Still stuck? Use the diagnose-first prompt