Payments taking money and doing nothing?
Stripe took the money. Your customer got nothing.
This is the worst bug in the catalogue, because it costs you the customer and the money at the same time, and you usually find out from an angry email rather than from your own monitoring. It is almost never a Stripe problem. It is one of about six things on your side, and they are all fixable inside a sprint.
Fixed £4,500 · 3 days · pass-or-refund · next slot w/c 3 August
What actually breaks
- Provisioning happens on the success redirectThe most common cause by a distance. Access is granted by the page the customer lands on after paying. Anyone who closes the tab, loses signal, or has a slow redirect pays you and gets nothing. It also means anyone who visits that URL directly gets provisioned without paying.
- The webhook signature is never verifiedWithout verification, your webhook endpoint is a public URL that grants paid access to whoever posts the right shaped JSON at it. This is both the reason people don't get provisioned and the reason strangers sometimes do.
- No idempotency, so retries double everythingStripe retries webhooks. If the same event arriving twice runs the provisioning twice, customers get two subscriptions, two licences, or two of whatever you grant, and your reconciliation stops matching.
- Listening for the wrong eventpayment_intent.succeeded and checkout.session.completed do not fire in the same circumstances, and neither covers asynchronous payment methods that settle later. Subscribing to the wrong one means a whole class of customers silently never provisions.
- The endpoint errors and nobody finds outThe webhook returns a 500, Stripe retries on a schedule, eventually gives up, and the event is gone. With no alerting on the failure path, the first signal is a customer complaint days later.
- Test and live keys crossedLive payments hitting a test webhook secret, or a test key left in production. Payments look fine in the dashboard and nothing downstream ever runs.
How this gets fixed
Provisioning moves off the redirect and onto a verified webhook, signature checked with a constant-time comparison against your webhook secret, with the endpoint failing closed if the secret is missing. Every event gets an idempotency key so a retry is a no-op rather than a duplicate. The events you actually need get subscribed, the failure path gets alerting so a silent drop becomes an email to you, and the whole thing gets a test that replays a real captured event, twice, and asserts the customer ends up provisioned exactly once.
What “done” looks like
We agree one of these in writing before you pay anything. If it passes, the sprint passed. If it doesn't, you get a full refund and keep the work.
- A completed checkout provisions the customer every time, including when the customer closes the tab immediately after paying.
- The same webhook event delivered twice provisions the customer exactly once.
- An unsigned or wrongly signed request to the webhook endpoint is rejected.
- A failure in the provisioning path raises an alert to you rather than failing silently.
We agree the acceptance test before any work starts. If it doesn't pass within three working days, you get a full refund and keep every change I've committed. The risk is mine, not yours.
Other things that block launches
- Your Lovable app works in the preview. It breaks in production.
- Your Bolt.new app runs fine in the preview. The published version doesn't.
- Your Replit app works in the workspace. The published version doesn't.
- Your v0 app looks ready to ship. The part that breaks is the part you can't see.
- Your Base44 app works when you use it. It breaks when your customers do.
- Your Cursor app runs on your machine. That is the only place it has ever been tested.
- Your customers can see each other's data. It is never just the one screen you found.
- Users can't sign in. It worked every time you tested it.
- It runs on your laptop. It will not deploy anywhere else.
- Your AI feature is impressive when it works. You can't put it in front of a customer.
- The full The Launch-Blocker Sprint