DEV Community

GraceSoft
GraceSoft

Posted on

What a Failed Ebook Purchase Taught Me About Actually Testing a Payment Flow

A few days ago someone close to me bought one of my ebooks. Stripe took the payment. The download never showed up.

That one bug report turned into a two-to-three-day deep dive across two separate Astro storefronts I run — my personal site (formerly davinaleong.com, now davdevs.dev) and Davina's Ministries, the new home for my Christian content. Both sell ebooks independently, both are wired to Stripe, and both, it turned out, had the same underlying weakness: I'd tested the payment thoroughly, but never the full payment → fulfillment → delivery pipeline end to end.

Here's what the debugging actually looked like.

Root causes

  1. The ebook retrieval step after a successful payment was buggy — the "product delivered" side of the flow hadn't been exercised nearly as hard as the "payment accepted" side.
  2. I simply hadn't tested the whole flow thoroughly, start to finish, in a way that would surface either of these. ### Rebuilding the flow properly, in sandbox first

Rather than patch live, I stood up proper Stripe sandbox environments for both projects and mirrored the real product catalog with sandbox products and prices. Every local Astro dev environment got pointed at the sandbox keys, and I went back through .env.example on both repos to make sure it actually matched the environment variables in real use — a small thing, but it's saved me from "works on my machine" surprises before.

From there I ran the flow with Stripe's test cards: successful charges, declines, the works.

Webhooks: the part everyone underestimates

Getting webhook testing working locally meant exposing my dev server through ngrok and explicitly allow-listing the ngrok host in the Astro dev server config on both sites. This is also where I found my most embarrassing bug: for a stretch of testing, I was pointed at the wrong webhook endpoint entirely, quietly confirming nothing while I assumed it was working. Lesson relearned: verify the webhook is actually firing against the endpoint you think it is before you trust any "it works" signal downstream of it.

Once that was sorted, I added an orders table migration so order state has a real source of truth to reconcile against, instead of trusting the happy path implicitly.

Storage and delivery

The manuscript files themselves needed work too. I migrated ebook manuscript storage off Vercel Blob and onto Cloudflare R2, and had to make sure every manuscript's file key and naming was accurate and consistently retrievable — a mismatched key here is exactly the kind of thing that produces "payment succeeded, download broken." I also moved ebook cover images to be served from my own domain rather than a third-party host, for both consistency and one less dependency in the critical path.

Email deliverability

Order confirmation emails were going out over Gmail SMTP, which is not built for transactional volume or reliability guarantees. I switched that over to Resend and cleaned up the order-confirmation email styling while I was in there, since a broken-looking confirmation email undermines trust just as much as a broken download link.

Going live

Only after the full flow — checkout, webhook, order record, email, file retrieval — passed cleanly in sandbox on both sites did I wire up the real, live Stripe price IDs and manuscript file keys, then flip both storefronts to publish all ebooks live.

Takeaways

  • Test the pipeline, not the step. A successful Stripe charge tells you almost nothing about whether the customer actually receives what they paid for.
  • Sandbox parity matters. If your sandbox products don't mirror your live catalog, you're not really testing the thing you're about to ship.
  • Webhooks are a common blind spot. "It's probably hitting the right endpoint" is not a thing to assume — verify it.
  • Treat file storage keys as part of the payment flow, not a separate concern. A rename or a bad key downstream of a successful charge is still a failed sale from the customer's point of view.
  • Transactional email is infrastructure, not an afterthought. Gmail SMTP is fine for a hobby project; it's the wrong tool once real money and real customers are involved. Both storefronts now have a fully tested, verified payment-to-download flow. It took an uncomfortable bug report from someone I love to force the kind of end-to-end testing rigor I should have had from day one — but I'll take the lesson.

Top comments (0)