Payments Overview
Email-first checkout: pay on Stripe, claim access by magic link.
What ships
- Stripe Checkout for one-time payments and subscriptions
- Email-first flow: pay first, claim access by magic link, no account needed to buy
- A webhook that records purchases, syncs subscriptions and processes refunds
- Customer portal for managing subscriptions and invoices
- Duplicate detection: a session is recorded once, however many times Stripe retries
Flow
1. The buyer picks a plan; /api/stripe/create-checkout creates a Checkout session for an allowed price ID
2. Stripe hosts the payment
3. checkout.session.completed hits /api/webhook/stripe, which writes a pending_purchases row and emails a magic link
4. The buyer signs in through that link; claim_pending_purchases marks the row claimed and sets has_access on their users row
5. Subscription events keep public.subscriptions in sync; charge.refunded clears access
Test it
Use Stripe test keys and the Stripe CLI to forward webhooks locally. The Playwright flow tests exercise checkout validation and claiming; npm run doctor confirms the key mode and that the price IDs resolve.
stripe listen --forward-to localhost:3000/api/webhook/stripe