top of page

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

  1. Review delivery attempts in the Stripe dashboard. Check response codes, response bodies, and which events were actually sent.

  2. Confirm mode and secret. Match the endpoint's mode and signing secret against the deployed environment variables.

  3. Inspect the raw body path. Trace the request through middleware to confirm the body reaches verification unmodified.

  4. Check subscribed events. Compare the event types your code handles with the endpoint's subscriptions.

  5. Measure handler time and errors. Find slow operations and exceptions that prevent a 2xx response.

  6. 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.


Get Help Now




bottom of page