Stripe Webhook Not Working
Customers pay, Stripe shows the charge as successful, but your app never unlocks the subscription, creates the order, or sends the receipt. Every failed webhook is a paying customer waiting on support. A Codersarts engineer finds why events aren't landing and makes your payment flow reliable.
Stripe webhooks usually fail for one of five reasons: the request body is modified before signature verification, the wrong signing secret is used for the environment, the endpoint isn't subscribed to the right events, the handler responds too slowly or with an error, or duplicate and out-of-order events aren't handled. Stripe's dashboard records every delivery attempt and response code, which is the fastest way to see which one you have.
Typical symptoms | Payments succeed but orders don't update, signature verification errors, events never arrive, duplicate orders |
Most common causes | Parsed request body, wrong signing secret, missing event subscriptions, slow handlers |
How we fix it | Trace delivery attempts, fix verification, make the handler fast and idempotent, test with real event replays |
Turnaround | Same-day diagnosis; most fixes in 24–48 hours |
Price | Live Debug from $20; fixed-price quote for the full fix |
Signs Your Stripe Webhook Is Broken
Payments succeed in Stripe, but orders or subscriptions don't update in your app
Logs show No signatures found matching the expected signature for payload
Webhooks work with the Stripe CLI locally but fail in production
The Stripe dashboard shows failed deliveries with 400, 401, 404, or 500 responses
Events show as delivered, but nothing happens in your database
Customers get duplicate orders, emails, or credits
Subscription status in your app doesn't match Stripe
Why Stripe Webhooks Fail
1. The request body changes before verification
Stripe signs the exact raw bytes it sends. If your framework parses the body into JSON first, for example through a global JSON middleware in Express, the signature check fails even when the secret is correct. In Next.js route handlers, the body must be read as raw text before verification.
2. The wrong signing secret
Every webhook endpoint has its own signing secret, and test mode and live mode endpoints have different ones. The Stripe CLI also generates its own secret for local forwarding. Using the CLI secret in production, or the test secret with live events, causes every verification to fail.
3. Events not subscribed or sent elsewhere
The endpoint only receives the event types it's subscribed to. A handler waiting for invoice.paid never runs if the endpoint only listens for checkout.session.completed. Test mode events also never reach a live mode endpoint.
4. The handler is slow or doesn't return success
Stripe expects a quick 2xx response. Handlers that send emails, call other APIs, or update many records before responding can time out, which Stripe treats as a failure and retries. Authentication middleware, CSRF protection, firewalls, or redirects in front of the endpoint also block deliveries.
5. Duplicates and out-of-order events
Stripe may deliver the same event more than once and doesn't guarantee order. Handlers that don't check whether an event was already processed create duplicate orders, and handlers that trust event order can overwrite newer subscription states with older ones.
How We Diagnose the Webhook Failure
Review delivery attempts in the Stripe dashboard. Check response codes, response bodies, and which events were actually sent.
Confirm mode and secret. Match the endpoint's mode and signing secret against the deployed environment variables.
Inspect the raw body path. Trace the request through middleware to confirm the body reaches verification unmodified.
Check subscribed events. Compare the event types your code handles with the endpoint's subscriptions.
Measure handler time and errors. Find slow operations and exceptions that prevent a 2xx response.
Replay real events. Resend failed events to reproduce the issue safely.
How We Fix It
Root cause | Fix |
Parsed request body | Exclude the webhook route from JSON parsing and verify against the raw body |
Wrong signing secret | Store the correct secret per endpoint and environment, and separate test and live configuration |
Missing event subscriptions | Subscribe the endpoint to every event your business logic relies on |
Slow handler or timeouts | Verify, store the event, return 2xx immediately, and process work in a background job |
Blocked requests | Exempt the webhook route from auth and CSRF checks and remove redirects in front of it |
Duplicates and ordering | Record processed event IDs and fetch the latest object state from Stripe before updating records |
We finish by replaying failed events so customers who already paid get what they paid for.
Example Fix
Situation: A subscription SaaS on Node.js saw about one in five new subscribers stuck on the free plan after paying.
Cause: A global JSON body parser broke signature verification for some requests, and the handler also sent welcome emails and provisioned accounts before responding, causing timeouts and retries that created duplicate accounts.
Fix: Moved the webhook route before the JSON parser to verify the raw body, stored event IDs to ignore duplicates, and moved provisioning and emails into a background job. Then replayed every failed event from the Stripe dashboard.
Result: Paying customers were upgraded within seconds, duplicate accounts stopped, and previously stuck subscribers were restored.
How to Keep It From Happening Again
Alert on failed webhook deliveries instead of discovering them through support tickets.
Keep handlers thin: verify, store, respond, then process in the background.
Test every release with replayed events for checkout, renewal, failed payment, and cancellation.
What You Get
Root cause confirmed and explained
Reliable, verified, and idempotent webhook handler
Failed historical events replayed and reconciled
Monitoring for failed deliveries
Frequently Asked Questions
Why does Stripe webhook signature verification fail? Most often the request body was parsed or modified before verification, or the signing secret doesn't match the endpoint and mode sending the event. Verification must use the raw body and the exact secret for that endpoint.
Why do webhooks work locally with the Stripe CLI but not in production? The CLI uses its own signing secret and forwards events directly to your machine. Production needs the dashboard endpoint's secret, correct event subscriptions, and a route that isn't blocked by auth, redirects, or firewalls.
Does Stripe retry failed webhooks? Yes. Stripe retries failed deliveries over time, which is why slow or non-idempotent handlers often create duplicate orders or emails.
How do I stop duplicate orders from Stripe webhooks? Store each processed event ID and skip events you've already handled. For subscription changes, fetch the current object from Stripe instead of trusting event order.
Can you recover payments that were missed while the webhook was broken? Yes. Once the endpoint is fixed, failed events can be resent or reconciled against Stripe records so affected customers get their orders or subscriptions.
Related Problems
PayPal payment integration failing
Supabase auth not working
Shopify API integration broken
CORS error blocking API requests
Node.js app crashing in production
Stop Losing Paid Orders
Share the failed delivery details from Stripe. Get a diagnosis and a fixed price.