Billing Issues
Most billing confusion in NuxtBase comes from one of two misunderstandings:
- checkout does not directly create the local subscription record
- non-empty Stripe keys change the runtime path even if the values are fake
Problem: Checkout Opens, But Billing Still Looks Like free
Section titled “Problem: Checkout Opens, But Billing Still Looks Like free”This usually means the Stripe redirect succeeded, but webhook processing did not complete.
In the template:
checkoutcreates a Stripe Checkout Session and returns a URL- local subscription creation and updates are mainly done by the Stripe webhook
- only some direct mutations, like
change-plan, also sync local state during the mutation itself
What To Check
Section titled “What To Check”- confirm the Stripe checkout session completed in Stripe
- confirm your webhook endpoint is reachable
- confirm
NUXT_STRIPE_WEBHOOK_SECRETmatches the current Stripe listener or dashboard endpoint - inspect webhook logs before changing billing UI code
Problem: Stripe Webhook Returns Invalid signature
Section titled “Problem: Stripe Webhook Returns Invalid signature”This usually happens because the webhook secret does not match the current listener or endpoint secret.
Typical server-side responses:
400 No body400 No signature400 Invalid signature500 Webhook processing failed
Common Local Cause
Section titled “Common Local Cause”If you restart stripe listen, Stripe gives you a new signing secret. If you do
not update NUXT_STRIPE_WEBHOOK_SECRET and reload the server, webhook
verification fails even though checkout itself still works.
Problem: Checkout Fails With “Stripe price is not configured”
Section titled “Problem: Checkout Fails With “Stripe price is not configured””This means the template could not resolve a Stripe price ID for the selected plan and interval.
Typical error:
Stripe price is not configured for plan "pro" (monthly)Check the matching env variables for the plan you are trying to sell:
NUXT_STRIPE_PRO_MONTHLY_PRICE_IDNUXT_STRIPE_PRO_YEARLY_PRICE_IDNUXT_STRIPE_PLUS_MONTHLY_PRICE_IDNUXT_STRIPE_PLUS_YEARLY_PRICE_ID
If you are not ready to use real Stripe yet, make sure the Stripe secret key is actually blank so mock checkout is the active path.
Problem: Billing Is Using Stripe When You Expected Mock Checkout
Section titled “Problem: Billing Is Using Stripe When You Expected Mock Checkout”BillingService initializes Stripe whenever NUXT_STRIPE_SECRET_KEY is a
non-empty string.
That means a fake placeholder key is enough to move you off the mock path.
Use an empty value, not a fake one:
NUXT_STRIPE_SECRET_KEY=NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=NUXT_STRIPE_WEBHOOK_SECRET=Problem: Portal, Cancel, Resume, Or Change-Plan Returns 404
Section titled “Problem: Portal, Cancel, Resume, Or Change-Plan Returns 404”These actions expect an existing operable subscription or customer record.
Typical causes:
- checkout never completed
- webhook never synced the subscription into the local database
- you are testing against the wrong active organization
Typical API messages include:
No active subscription found to updateNo active subscription found to cancelNo active subscription found to resume
Problem: The User Already Has A Subscription, But Checkout Still Gets Triggered
Section titled “Problem: The User Already Has A Subscription, But Checkout Still Gets Triggered”NuxtBase guards checkout with a local active-subscription lookup.
If checkout says:
An active subscription already exists for this organizationthat is the template protecting you from double-checkout for the same organization.
Check whether:
- the active organization is the one you expected
- the subscription was already synced by a prior webhook
- you should be using
change-planinstead of a new checkout flow
Fastest Billing Debug Flow
Section titled “Fastest Billing Debug Flow”- confirm which organization is active
- confirm whether Stripe is in real mode or mock mode
- confirm the plan has a price ID
- confirm checkout completes in Stripe
- confirm webhook delivery succeeds and local sync follows