Stripe & checkout
Flow
- Client collects email + GitHub username, then POSTs to your checkout API.
- Server creates a Stripe Checkout Session with metadata (persisted on the session).
- User pays on Stripe-hosted checkout; success URL includes
{CHECKOUT_SESSION_ID}so the app can poll until the order exists before showing success. checkout.session.completedwebhook creates/updates the order row (idempotent). GitHub invite and email run only after a successful insert.
Good practices
- Use webhook signing secret per environment (test vs live
whsec_differ). - Verify the raw body for signature verification — do not parse JSON before verify.
- Return
200quickly after persisting the order; run email/GitHub side effects after insert, and useON CONFLICT DO NOTHING(or equivalent) so Stripe retries do not duplicate work. - Store
customer_emailfrom session + metadata fallback so receipts always have an address.
Local testing
stripe listen --forward-to localhost:3000/api/webhooks/stripeUse the CLI's whsec_ in .env.local while developing.
Price IDsUI price ($99) must match the Stripe Price amount, or customers see one number and pay another. Create a one-time price in Dashboard and set
STRIPE_PRICE_ID.