Implement Stripe subscription billing end to end: Checkout, the subscription lifecycle webhooks, dunning with Smart Retries, and time-travel testing with test clocks. Use when wiring paid tiers, handling failed renewals, setting up the Customer Portal, or debugging billing events.
./install.sh stripe-billing-integrationname: stripe_billing_integration description: > Implement Stripe subscription billing end to end: Checkout, the subscription lifecycle webhooks, dunning with Smart Retries, and time-travel testing with test clocks. Use when wiring paid tiers, handling failed renewals, setting up the Customer Portal, or debugging billing events.
Ship the production billing patterns Stripe integrations need but most tutorials skip: the full subscription lifecycle, webhook handling done safely, retry and dunning behavior that actually recovers failed payments, and a test strategy that covers trials, renewals, and proration without waiting 30 days.
trialing and active mean provisioned. past_due means keep access during the grace window and run dunning, not a lockout. canceled, unpaid, and incomplete_expired mean revoke. incomplete means never provision.checkout.session.completed, customer.subscription.created, customer.subscription.updated, customer.subscription.deleted, invoice.paid, invoice.payment_failed, invoice.payment_action_required, customer.subscription.trial_will_end. See references/billing-webhooks.md for the event matrix and the raw-body verification code.event.id (Stripe retries non-2xx deliveries for up to about 3 days). Events can arrive out of order, so when two events disagree about a subscription, re-read its current state from the Stripe API instead of trusting whichever event arrived last.past_due, and when retries run out the subscription moves to the end state you configured (usually unpaid or canceled). Pair this with your own reminder emails that link the customer to the Customer Portal. Details and the decline-code taxonomy are in references/dunning.md.references/test-clocks.md. For quick smoke tests without clocks, use the Stripe CLI: stripe trigger invoice.payment_failed and stripe listen --forward-to http://localhost:3000/webhooks/stripe.A Stripe billing integration that:
stripe.webhooks.constructEvent(rawBody, sig, endpointSecret)). A body that was parsed and re-serialized will fail verification, because the bytes differ from what Stripe signed. On failure return HTTP 400, never 500.success_url. It is a display page, and users can visit it without paying. Webhooks are the only fulfillment source.checkout.session.completed is amount_total in cents. Not amount, not total.proration_behavior: 'create_prorations'. Never compute prorations by hand.default_payment_method wins over the customer's default when retries charge. If you update one, make sure it is the one retries use.insufficient_funds, do_not_honor, processing_error) are worth retrying, hard declines (lost_card, stolen_card, card_not_supported) are not, and authentication_required (3DS/SCA) never self-resolves, so it goes straight to customer action.publisher key 2e43c913833850e6d80f939677e3de76e806d47785c0f1caaca90f9d18c98e1e
No ratings yet — be the first to rate it.