Payments Preflight · Check 10 of 15
Keep subscription state in sync with Stripe
Treat Stripe as the source of truth for subscription status. Sync it into your database from customer.subscription.* events and read access from that one place.
What it is
Stripe holds the real subscription status. Your app needs a copy so it can gate features, kept up to date from webhooks.
Why it matters
If access is decided in several places, or set once at checkout and never updated, cancellations, upgrades and failed renewals do not reach your app.
How to check
- Find every place your app decides if a user is paid. It should be one function reading one field.
- Confirm you handle
customer.subscription.created,customer.subscription.updatedandcustomer.subscription.deleted. - Cancel a test subscription and confirm access ends when it should.
How to fix it
- Store the Stripe customer id and subscription id against your user.
- On each subscription event, retrieve the subscription and save status, price and current period.
- Gate features through one helper such as
hasActivePlan(user).
Prompt for your AI coding tool
Paste into Cursor, Claude Code, Lovable or similar. Review the diff before you accept it.
Make Stripe the source of truth for subscription access. Store stripe_customer_id and stripe_subscription_id on the user, handle customer.subscription.created, updated and deleted by retrieving the subscription from the API and saving status, price id and current period, and replace every scattered paid check with one hasActivePlan(user) helper. Show the diff.
Sources
- Using webhooks with subscriptions Stripe docs
- How subscriptions work Stripe docs
Related checks
Sponsor this page: get in touch.