DEV Community

Kaibalya Kar
Kaibalya Kar

Posted on

Debugging Stripe Webhook Signature Verification Errors in Production

If you're integrating Stripe in a Node.js backend, you're likely using webhooks to handle events like checkout.session.completed. One of the common pitfalls during deployment is related to webhook signature verification failures, and recently, I ran into exactly this issue.

In this post, I’ll walk through the problem I faced, how I fixed it, and what best practices you can follow to avoid the same mistake.

app.post(
  "/api/v1/webhook/stripe",
  express.raw({ type: "application/json" }),
  stripeWebhookHandler
);

// JSON body parser for all other routes
app.use((req, res, next) => {
  if (req.originalUrl === "/api/v1/webhook/stripe") {
    next(); // Skip body parsing for Stripe
  } else {
    express.json()(req, res, next);
  }
});

Enter fullscreen mode Exit fullscreen mode

This is required because Stripe needs access to the raw body to verify the signature using the stripe.webhooks.constructEvent() method.

**

❌ The Problem

**
After deploying to production, Stripe kept returning this error:

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

I was sure my raw body handling was correct, and the endpoint URL was accurate. Locally, everything worked using the Stripe CLI. But in production… webhook requests kept failing.

🔍 The Root Cause

Turns out the issue was very simple but easy to overlook:
👉 I was using the Test Mode webhook signing secret (whsec_...) in production, while Stripe was sending Live Mode events.

Stripe signs test and live events with different secrets, and if you mismatch them, signature verification will always fail — even if your code is perfect.

✅ The Fix: Environment-Based Configuration
To avoid this, I updated my environment variables and Stripe initialization code to handle different modes based on the environment

🧪 Bonus Tip: Use Stripe CLI for Local Testing

To test webhooks locally with the Stripe CLI:

stripe login
stripe listen --forward-to localhost:5000/api/v1/webhook/stripe
stripe trigger checkout.session.completed

Enter fullscreen mode Exit fullscreen mode

Make sure your local environment uses the test mode secrets to match the CLI’s default behavior.

💡 Final Thoughts
Small mistakes like using the wrong webhook secret can cost you hours of debugging. If you're getting a "Webhook signature verification failed" error, double-check your mode (test/live) and environment configuration.

If this helped you, share it with someone struggling with Stripe setup — and happy coding! ⚡

Top comments (2)

Collapse
 
kxbnb profile image
kxbnb

The Test Mode vs Live Mode secret mismatch is such a common gotcha - I've seen it catch multiple teams. Good callout on keeping environment configs explicit.

One thing that's helped me with webhook debugging: having visibility into the actual request as it arrives, before any middleware processing. When you can see the raw payload and headers hitting your endpoint, it's much easier to verify everything is aligned.

At toran.sh we focus on this kind of API observability - seeing exactly what's coming over the wire. For webhook-heavy workflows (especially payments), that visibility layer has saved me from many similar debugging sessions.

What's your approach for debugging webhooks in production when you can't easily reproduce the exact payload that failed?

Collapse
 
kingaspx profile image
Abner Rodrigues

THANK YOU SO MUCH! I WAS HAVING THIS ISSUE, I SAW YOUR POST AND IT HELPED ME A LOT!!! THANK YOU THANK YOU THANK YOU