If Stripe shows a successful payment but your Cloudflare Workers app still marks the customer as unpaid, first check the webhook delivery—not the checkout page. A payment can be settled at Stripe while your Worker rejects the event, crashes during processing, or acknowledges it without updating your database.
The safest repair is to trace one real transaction through Stripe delivery → Worker signature check → durable event handling → database/payment state → customer access or fulfilment. If one step fails, repair that boundary and reconcile affected transactions before accepting more money. A full rebuild is rarely the first sensible purchase.
This guide is for founders and operators running a SaaS, membership app, marketplace or checkout backend on Cloudflare Workers. It focuses on production recovery and deciding when to hire an engineer, not on creating a Stripe account.
Read the Stripe delivery result before changing code
Open Stripe Workbench → Webhooks → your live event destination → delivery attempts. Confirm the endpoint URL, mode, event type, response code and attempt time. Then correlate the attempt with your deployed Worker’s logs and the customer record. Do not paste customer details, signing secrets or raw payment payloads into public bug reports.
| What Stripe reports | First thing to investigate | What it does not prove |
|---|---|---|
| 400 and signature error | Raw request body, endpoint signing secret, signature header | That the payment itself failed |
| 404 or 405 | Wrong route, deployment, HTTP method or gateway routing | That Stripe has the wrong customer |
| 500 or Worker exception | Runtime error, missing binding/secret, database write or incompatible library | That checkout needs replacing |
| 2xx but customer stays unpaid | Event type, queue, database update, entitlement or fulfilment logic | That the business effect completed |
| No delivery attempt | Event destination, selected event types, live/test mode and account | That the Worker rejected an event |
A 2xx response means the endpoint acknowledged delivery. It does not prove a subscription was activated, an order was fulfilled or a ledger entry was saved. Conversely, an HTTP 400 from the webhook does not reverse a payment already recorded by Stripe.
Stripe’s webhook troubleshooting guidance explains how to inspect delivery failures and signature errors.
Fix the three common Cloudflare-specific failure boundaries
1. The Worker verifies a changed request body
Stripe signs the exact body it sends. If middleware parses JSON and your code later serializes it again, even harmless changes to whitespace or key order can invalidate the signature.
Read the raw body once with the Worker’s Request API, preserve the `Stripe-Signature` header, and verify with the method supported by your installed Stripe SDK and event format. For a snapshot-event integration using the Node Stripe SDK on Workers, check the asynchronous verification path and Web Crypto provider rather than blindly copying a Node-only synchronous example. Stripe also supports thin events with different verification APIs; do not mix the two.
Check that the deployed Worker uses the signing secret for that exact Stripe endpoint. A local Stripe CLI listener has a different secret from a Workbench-managed endpoint, and test and live environments must not share credentials accidentally.
Use Stripe’s signature troubleshooting instructions and the Stripe-maintained Cloudflare Worker example as starting points. Do not disable signature verification to make the webhook return 200. That would allow untrusted requests to influence payment state.
2. The route works locally but fails after deployment
A deployed Worker may have a different route, environment, compatibility setting, database binding or secret than the preview environment. A gateway Worker can also intercept a path before it reaches the payment handler.
Check the exact public URL registered at Stripe, the route that receives POST requests, the active production Worker version and its environment bindings. Verify the expected `STRIPE_WEBHOOK_SECRET` is configured as a secret in the correct environment. Never put the secret in frontend code or a public repository.
Use a safe test event and the production logs to identify the first failing operation. A 500 may come from a missing D1 binding, failed Supabase call, invalid schema, unexpected runtime API or uncaught exception—not from Stripe itself.
If your migration also broke database-backed routes, the separate Cloudflare Workers and Supabase migration troubleshooting guide covers that infrastructure boundary.
3. The Worker acknowledges the event but loses the business update
This is the expensive failure because the payment provider may show a successful delivery while the app still has an unpaid order.
The handler might return 200 before a background task was durably queued, update the wrong customer ID, fail a database permission check, process only the initial purchase but not renewals, or ignore an event type that matters to the business.
For longer work, a useful architecture is verify → durably enqueue → acknowledge → process with retries. A queue is not mandatory for every tiny integration, but it can separate a fast HTTP acknowledgement from slow database and fulfilment work. Configure a dead-letter queue or equivalent recovery path, alerts and a process for inspecting failed messages. Cloudflare documents queue retries and dead-letter handling.
Make processing idempotent. Record stable Stripe event and payment-object identifiers and enforce uniqueness where the business effect is written. A retried event must not issue a second receipt, create another order or grant duplicate credits. If events arrive out of order, retrieve the current authoritative Stripe object and apply a deliberate state-transition rule rather than assuming the latest-delivered message is the latest state.
For general duplicate-payment protection, see the AI-built app webhook reliability guide. This article specifically owns Cloudflare Worker delivery and production repair.
Recover payments that happened during the outage
Fixing the endpoint only prevents the next failure. It does not automatically reconcile customers who paid while the handler was broken.
Create a controlled incident ledger containing the Stripe payment or invoice ID, expected app user/order, Stripe’s current state, local database state and intended business action. Use authorized server-side Stripe API access to verify each disputed transaction. Separate successful payments, failed payments, refunds and disputed charges. Never infer success from a browser redirect alone.
Stripe’s undelivered-event recovery documentation describes automatic retries for eligible failed deliveries and how to identify undelivered events. Its event listing has retention limits, so do not assume you can reconstruct an unlimited historical backlog from the Events API.
Reprocess only after the handler is repeat-safe. Stripe can retry an event while your manual recovery runs; both paths must converge on one correct result. Keep a reconciliation record of what was repaired, what remains unresolved and what requires a human refund or customer-service decision.
Example: A membership founder finds 26 successful Stripe charges and 19 active memberships in the app. The missing seven are not automatically seven refunds or seven new subscriptions. Match each charge to its intended account, verify current subscription status, then repair only the missing entitlements. This is an illustrative scenario, not a reported client incident.
Should you pay for a fix or a rebuild?
The purchase decision depends on the first failed boundary and how much production state is at risk.
| Situation | Sensible next step |
|---|---|
| Wrong live endpoint secret or route, no lost payments | Focused configuration repair and end-to-end retest |
| Repeated 400/500 failures after deployment | Worker runtime, routing and integration investigation |
| Paid customers missing access or orders | Repair plus transaction reconciliation, regression tests and monitoring |
| Several payment states, teams, products and databases disagree | Broader payment architecture and production reliability engagement |
A single incorrect secret should not be sold as a $1,000 rebuild. A business with recurring billing, lost fulfilment, historical discrepancies and no reliable deployment checks can reasonably need a $1,000+ engineering engagement, sometimes substantially more. Price the work after examining the event evidence, number of affected transactions, environments, state model and required acceptance tests—not from a generic hourly estimate.
Before hiring, ask the developer to define the diagnosis deliverable, the exact systems they need access to, the rollback plan and how they will prove that one successful payment creates exactly one correct business result. Grant scoped collaborator access where possible; do not send secret keys or account passwords in chat. Keep Stripe, GitHub, Cloudflare and database ownership in the business’s accounts.
Eight acceptance tests before declaring recovery
- A genuine live-mode payment event reaches the intended production endpoint and passes signature verification.
- A deliberately invalid signature is rejected without writing any payment state.
- The same valid event delivered twice creates only one business effect.
- A successful payment updates the correct customer/order even if the browser never returns from checkout.
- A failed, refunded or cancelled payment follows the intended business rules instead of being marked paid.
- A temporary database failure causes a visible retry or recoverable failed job, not a silent success.
- The affected historical transactions reconcile to Stripe without double fulfilment.
- The business owner can see delivery failures, review deployment changes and remove the developer’s access after handoff.
The repair is complete only when those tests pass against the actual architecture. Screenshots of a green checkout page are insufficient.
Need help recovering a live payment integration?
If your Cloudflare Workers app takes payments but Stripe events fail, subscriptions stay locked or paid orders do not reconcile, I can help scope the first broken boundary and decide whether it needs a targeted repair or a larger production hardening project.
See my MVP and product development service, or contact me with the symptom and affected workflow. Share redacted error codes, event delivery statuses and the architecture—not credentials or customer financial data.



