Stripe webhook · server log
No signatures found matching the expected signature
StripeSignatureVerificationError: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?What it means
The signature is computed over the exact bytes Stripe sent. If your code parses the body as JSON and stringifies it again, or anything changes whitespace or encoding, the HMAC no longer matches. If the body is untouched, the secret is wrong (see the next entry).
Common causes
- Calling req.json() and then JSON.stringify() before constructEvent
- A wrapper, logger or middleware that reads and re-serialises the body
- The right body but the wrong whsec_ secret
How to fix it
- In an App Router route handler, read the body once with await req.text()
- Pass that string, the stripe-signature header and STRIPE_WEBHOOK_SECRET to constructEvent
- Only JSON-parse after verification (event is already parsed for you)
- If it still fails, check which whsec_ secret is in use
// src/app/api/stripe/webhook/route.ts
import Stripe from "stripe";
export const runtime = "nodejs";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature");
if (!sig) return new Response("Missing signature", { status: 400 });
const body = await req.text(); // raw body: never req.json()
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
} catch (err) {
return new Response(`Invalid signature: ${(err as Error).message}`, { status: 400 });
}
// ...handle event.type...
return Response.json({ received: true });
}stripe listen --forward-to localhost:3000/api/stripe/webhook
# put the whsec_... it prints in .env.local, then restart npm run dev
stripe trigger checkout.session.completed
pass if stripe listen prints [200] for every forwarded event, not 400 or 500.
Prompt for Cursor or Claude Code
My Stripe webhook fails with 'No signatures found matching the expected signature'. Open src/app/api/stripe/webhook/route.ts and make sure the body is read once with await req.text() and passed unmodified to stripe.webhooks.constructEvent with the stripe-signature header. Remove any req.json(), JSON.stringify or body-parsing wrapper before verification. Don't change the event handling.Not quite your error? Paste yours into the free VibeBoot Doctor or browse the Stripe webhook fixer.
next: skip the next one
Skip the debugging. The VibeBoot SaaS Starter ships with this already handled: a signature-verified webhook (raw body + constructEvent) that re-fetches the subscription from Stripe before saving it, with Vitest tests. Plus auth and a database on Next.js 16.4.3. $49, one-time.
14-day money-back guarantee · lifetime updates
Other Stripe webhook errors
$ fixed it? get the next one first
New fixes for what AI agents break, by email.
When we add a fix or a Cursor rule for a new Next.js, Auth.js, Prisma or Stripe break, it goes out in the VibeBoot newsletter. Free, occasional, unsubscribe in one click.