Subscription Lifecycle
NuxtBase treats subscriptions as organization-level state.
The active organization is the billing subject, and only organization managers can mutate that state.
The Effective Lifecycle
Section titled “The Effective Lifecycle”For the shipped template, the practical lifecycle is:
- an organization starts on
free - a manager opens checkout for a paid plan
- Stripe completes checkout and returns the user to
/dashboard/billing - Stripe webhooks create or update the local subscription record
- managers can later change plan, schedule cancellation, or resume
- if no operable subscription remains, the organization falls back to
free
Operable Subscription States
Section titled “Operable Subscription States”The app considers only these Stripe-style states “operable” for billing actions:
const operableBillingSubscriptionStatuses = [ "active", "trialing", "past_due",];That affects:
- which subscription the app treats as current
- whether plan changes are allowed
- whether cancel and resume actions are allowed
- whether the organization is treated as paid or free
If the current record is outside those states, billing mutations return a conflict instead of guessing.
Checkout Behavior
Section titled “Checkout Behavior”Checkout starts from POST /api/billing/checkout.
Important shipped behavior:
- it requires an active organization
- it requires the current user to be an
owneroradmin - it rejects checkout if an operable subscription already exists
- it defaults success and cancel return URLs to the billing page
The default return URLs are:
/dashboard/billing?checkout=success/dashboard/billing?checkout=canceledThe endpoint also rejects cross-origin return URLs. They must use the same
origin as NUXT_PUBLIC_SITE_URL.
Plan Change Behavior
Section titled “Plan Change Behavior”Changing from one paid plan to another uses a dedicated mutation, not a second checkout session.
The shipped behavior is:
- find the current operable subscription for the active organization
- verify its state allows plan changes
- update the Stripe subscription item price
- sync the new price back into the local billing tables immediately
The Stripe update uses:
proration_behavior: "always_invoice"That matters because upgrades or downgrades can generate immediate proration invoices depending on your Stripe configuration.
Cancel And Resume
Section titled “Cancel And Resume”NuxtBase does not immediately delete a paid subscription when the user clicks cancel in the app.
Instead:
- cancel sets
cancelAtPeriodEnd = true - resume sets
cancelAtPeriodEnd = false
So the common user-facing pattern is “scheduled to cancel at period end”, not “subscription already gone”.
Portal Access
Section titled “Portal Access”The dashboard also exposes a “manage subscription” action for paid plans. That opens the Stripe customer portal when a billing customer exists.
If the organization does not yet have a linked billing customer, the portal
endpoint returns 404 instead of fabricating a management session.
What Buyers Should Test
Section titled “What Buyers Should Test”- start checkout from the active organization as an owner or admin
- confirm the billing page reflects the paid plan after webhook sync
- change from monthly to yearly or between paid plans
- schedule a cancellation and verify the period-end state appears in the UI
- resume before period end and confirm the cancellation flag clears
- confirm regular members can view billing but cannot mutate it