A Stripe subscription that stops itself after exactly three payments, with no database.
Online payments for a small coaching practice: server-created Stripe Checkout with prices locked to a server catalog, plus a 12-week program payable monthly whose subscription automatically stops after exactly three charges.
- charges, then the subscription cancels itself
- 3
- charges, then the subscription cancels itself
- unit tests across checkout and the installment cap
- 15
- unit tests across checkout and the installment cap
- real bugs caught by agent review before release
- 2
- real bugs caught by agent review before release
- from first checkout commit to reviewed, documented release
- ~2 h
- from first checkout commit to reviewed, documented release
The problem
Thrive Beyond Coaching is a small practice that coaches cancer survivors and caregivers. Its 12-week program is offered as $900 paid in full or $300 a month for three months. A plain Stripe monthly subscription keeps charging until someone remembers to cancel it, and for a one-person business that is a real risk of overcharging a client.
Constraints
- No database and no backend beyond two Next.js API routes on Vercel. Sale notifications go to email through Formspree.
- The person running the business shouldn't need to do anything in the Stripe dashboard after each sale.
- Prices must come from the server, never from the browser.
- Stripe webhooks can be retried or delivered more than once, so capping has to be idempotent, and a failure has to be retried rather than lost.
What I built
- Checkout Sessions created on the server (no static Payment Links), with a pinned Stripe API version and a server-side price catalog: four fixed-price offerings, a $50 to $100 sliding scale, and donations of at least $1.
- The monthly option creates a subscription tagged as a 3-cycle installment plan.
- A signature-verified webhook. On checkout.session.completed, it converts the subscription into a subscription schedule with a single 3-month phase and end_behavior set to cancel.
- Idempotent capping. A schedule counts as capped only if it is set to cancel and has a bounded phase. A schedule that exists but isn't capped yet is repaired in place, and a failed cap returns 500 so Stripe retries the event.
- The Stripe client is passed in, so the capping logic is a pure, testable unit.
How it's verified
- 15 Vitest cases: 8 for checkout (including "overrides tampered subscription price and mode with catalog values" and "rejects arbitrary client-priced payments") and 7 for the cap (including "repairs an existing-but-uncapped schedule in place" and "skips an already-capped subscription (idempotent no-op)").
- An automated agent review gate caught two real bugs before release. The checkout trusted prices sent by the browser, which was fixed by locking checkout to the catalog. The idempotency check also didn't detect a schedule's real cap state, which was fixed by checking end_behavior and a bounded phase.
- Known gap: Stripe event IDs aren't recorded, so a duplicated webhook can send a duplicate notification email. The cap itself is unaffected.
Results
- Every offering on the public shop page goes through server-priced Stripe Checkout, and the monthly plan ends itself after the third payment without anyone touching Stripe.
- The whole checkout and installment change shipped on the morning of 2026-07-11, from the first commit at 05:36 to the final docs sync at 07:24.
TODO (Matt): numbers to add
- TODO: Number of clients who have used checkout or the installment plan (only if the client is comfortable sharing it).
- TODO: How the full 3-charge cycle was confirmed against Stripe test mode, such as a test clock run. The repo doesn't document it.
How coding agents fit in
- Built with coding agents and run through the no-mistakes pipeline: automated review, lint, CI, and docs steps. Its review commits are where both bugs above were caught and fixed, before anything reached the live site.