← StripeCheckup

The Stripe bug I shipped three times in one month

Over about four weeks I built five separate products, each with its own Stripe integration: subscriptions, one-time payments, payment links, the works. Same underlying pattern each time — Checkout Session or Payment Link, a webhook to fulfill on the backend, a small ledger to track who paid for what.

The first time, a real subscriber paid and the ledger never noticed. Not a failed charge — Stripe took the money fine. The webhook that was supposed to record it just never ran cleanly, and there was no other path checking whether it had. The subscriber sat there, paid and unacknowledged, for a week, until a routine check against Stripe's own Checkout Sessions API turned up the mismatch.

The fix was obvious in hindsight: never trust a single webhook delivery as your only record of a sale. Poll the source of truth (Stripe itself) as a backstop. Fixed it, moved on, built the next product.

Second product, different bug, same root cause. This time the webhook handled customer.subscription.deleted — cancellations — but not customer.subscription.updated. When a card fails and Stripe's dunning settings mark a subscription unpaid instead of canceling it outright, nothing fired the event my code was actually listening for. A non-paying customer could, in theory, keep paid access indefinitely. Same shape of bug: an event Stripe was sending that the integration silently wasn't handling.

Third product: a payment link that worked perfectly, took money cleanly, and gave absolutely no way to know what the buyer actually wanted — no metadata, no custom field, nothing distinguishing this sale from any other product on the same Stripe account. Not a lost sale, but a fulfillment dead end.

Three different products, three different specific bugs, one common shape: Stripe did exactly what it was told, and the integration around it had a blind spot for something Stripe was already telling it. None of these show up in local testing. They show up weeks later, in production, usually because a human happens to notice a number that doesn't add up.

So I wrote the check I wish I'd had before any of the three: connect a read-only key, pull your actual event history and webhook configuration, and diff them. If Stripe fired an event type in the last hundred events that nothing in your webhook config is subscribed to, that's not hypothetical — it's a thing that already happened in your account that your code never heard about. Same for subscriptions stuck unpaid, payment links with no metadata, and paid Checkout Sessions with no customer record attached.

That check is StripeCheckup — $49, one-time, read-only key, report in under a minute.