Friendly Experts
Home / Problems / Cursor
CursorPayments

Stripe webhooks failing in your Cursor-built app? It is almost always one of these.

Updated October 24, 2026

Short answerStripe signs the exact bytes it sends. If your framework parses the JSON before you verify, or you use the wrong signing secret, verification fails with "No signatures found matching the expected signature for payload". Verify against the raw body with the secret for that exact endpoint and mode.

Your framework parsed the body first

stripe.webhooks.constructEvent needs the raw request body. Express's json middleware, or any body parser that runs before your handler, changes those bytes and breaks the signature.

// Express: raw body on the webhook route, before express.json()
app.post("/api/stripe/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const event = stripe.webhooks.constructEvent(
    req.body, req.headers["stripe-signature"], process.env.STRIPE_WEBHOOK_SECRET
  );
  res.json({ received: true });
});

// Next.js App Router: read the text body
export async function POST(req) {
  const body = await req.text();
  const sig = req.headers.get("stripe-signature");
  const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET);
  return Response.json({ received: true });
}

You're using the wrong signing secret

Each endpoint has its own whsec_ secret. The Stripe CLI's stripe listen command prints a different secret from the one on your Dashboard endpoint, and test mode and live mode endpoints have different secrets too. Match the secret to where the events come from.

Not sure which of these it is? We'll tell you in 24 hours, free.

Get a free health check

The endpoint redirects or needs a login

Stripe treats a redirect as a failed delivery. A www redirect, a trailing slash redirect, or auth middleware in front of the route will all cause failures. Point the endpoint at the final URL and exclude the webhook route from login checks.

Orders get processed twice

Stripe can deliver the same event more than once and retries when your endpoint doesn't return a 2xx in time. Return 200 quickly, do slow work afterwards, and record each event.id so you can skip ones you've already handled.

Questions people ask

Why does Stripe webhook verification work locally but fail in production?

Locally you are probably using the secret printed by stripe listen. Production needs the signing secret shown for your Dashboard endpoint, in the same mode (test or live) as the events.

How do I see why a Stripe webhook failed?

Open the endpoint in the Stripe Dashboard to see each delivery attempt, the status code your server returned, and the response body. Resend a single event from there after you fix the code.

Find out what's broken, free.

Paste your link. In 24 hours you'll know what's broken and what it costs to fix.

Get a free health check