Subscriptions and Recurring Billing
Creating a subscription with Checkout
session = stripe.checkout.Session.create(
mode="subscription",
customer=get_or_create_stripe_customer(current_user),
line_items=[{"price": plan.stripe_price_id, "quantity": 1}],
subscription_data={
"trial_period_days": 14,
"metadata": {"user_id": str(current_user.id), "plan": plan.code},
},
metadata={"user_id": str(current_user.id), "plan": plan.code},
success_url=url_for("billing.success", _external=True),
cancel_url=url_for("main.pricing", _external=True),
)
Store the Stripe customer ID on your user, so every subscription and invoice links to the same customer. Put metadata on the subscription itself (subscription_data) so subscription events can be matched to your user.
Subscription states
| Status | Meaning | Access? |
|---|---|---|
trialing |
in a free trial | yes |
active |
paid and current | yes |
past_due |
latest payment failed; retries in progress | your choice (often a grace period) |
unpaid / canceled |
retries exhausted or cancelled | no |
incomplete |
first payment not completed | no |
Keep a local copy of the status, updated from customer.subscription.created/updated/deleted and invoice.paid / invoice.payment_failed webhooks, and check it when users access paid features. Never trust a status sent from the browser.
The customer portal
Let customers update cards, download invoices, switch plans and cancel without you building those screens:
portal = stripe.billing_portal.Session.create(
customer=current_user.stripe_customer_id,
return_url=url_for("account.billing", _external=True),
)
return redirect(portal.url, code=303)
Configure what customers may do in the dashboard's portal settings.
Failed payments and dunning
Enable Stripe's automatic retries and failed-payment emails (Smart Retries). Show an in-app banner when status is past_due with a link to the portal to update the card.
Plan changes
Upgrades and downgrades are prorated by default. Decide whether downgrades take effect immediately or at the end of the period, and reflect plan limits in your app from the subscription's current price.
Security pitfall
Reactivating or granting a subscription must always be backed by a real Stripe subscription. An endpoint that flips a local active flag without checking Stripe lets users get paid features for free.
Exercise
Build monthly and yearly plans with a 14-day trial, a customer portal link, webhook-driven status syncing, a past_due banner and access checks on paid features. Test cancellation and a failed renewal with test cards and test clocks.
Check yourself
- Why store the Stripe customer ID on your user?
- Which subscription states should grant access?
- Why must access always come from Stripe-verified state?
Ваш прогресс сохраняется только в этом браузере.
Отправить на проверку (10 баллов)