nuxt-x-billing
nuxt-x-billing
Nuxt 4 layer for Stripe billing: a useBilling() composable, plan/feature gating (XBBillingGate), and billing container components — all wired against a consumer-owned backend contract (Backend requirements). The layer never touches Stripe directly; your backend owns checkout/portal sessions, the Stripe webhook → subscription sync, and the entitlement source of truth.
Works standalone (user-level billing) and composes optionally with nuxt-x-tenancy for per-org billing — no hard dependency on any tenancy layer.
@better-auth/stripe. Wiring better-auth's official Stripe plugin was deliberately deferred (peer-chain constraints on the 1.6.x line). This layer exists precisely so billing works without it — the backend contract is the integration point.Installation
npm install @xenterprises/nuxt-x-billing
Peers: @xenterprises/nuxt-x-app ^1.1.0 (brings Nuxt UI + the XABilling* presentationals), @nuxt/ui ^4.9.0, nuxt ^4.0.0, vue ^3.0.0.
What the consumer writes
// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@xenterprises/nuxt-x-billing'],
})
// app/app.config.ts — everything optional; shown with its meaning
export default defineAppConfig({
xBilling: {
pages: { billing: true, pricing: true }, // default pages; false = opt out (404)
checkout: { successUrl: '/billing?ok=1', cancelUrl: '/billing/pricing' },
portal: { returnUrl: '/billing' },
// tenancy: { enabled: true }, // per-org billing (see below)
},
})
# .env — base URL of YOUR billing backend (empty = same origin)
NUXT_PUBLIC_X_BILLING_BASE_URL=
Then implement the eight endpoints from Backend requirements (checkout session, portal session, webhook → subscription sync, reads). The default routes /billing (subscription, payment methods, invoices) and /billing/pricing work immediately against them.
What the layer provides
Composables:
useBilling()— subscription/plans/invoices/payment-methods state,checkout()/openPortal()/cancel()/resume()actions, and entitlement helpershasFeature()/hasPlan()/canInviteMember().
Components (auto-imported, XB* prefix):
XBBillingGate— plan/feature gating wrapper (slots: default,fallback).XBSubscriptionCard— current subscription + manage/cancel/resume/upgrade actions.XBPricingGrid— plan grid with monthly/yearly toggle; select →checkout().XBInvoiceHistory— invoice table with download/view.
Containers wrap the presentational XABilling* components from @xenterprises/nuxt-x-app and drive them with useBilling() state. Details: Components.
Pages (opt-out):
/billing— subscription + payment methods + invoices (xBilling.pages.billing: false→ 404)./billing/pricing— plan grid (xBilling.pages.pricing: false→ 404).
See Pages & opt-outs.
Gating UI
<XBBillingGate feature="analytics">
<AnalyticsDashboard />
<template #fallback>
<UpgradePrompt />
</template>
</XBBillingGate>
Per-org billing (tenancy composition)
No peer on nuxt-x-tenancy. When xBilling.tenancy.enabled: true and a tenancy layer provides nuxtApp.$xTenantId (a Ref<string | null> or a zero-arg function), every request is scoped with the X-Tenant-ID header, checkout/portal payloads carry tenantId, and state refetches on tenant switch. canInviteMember() then enforces seats for the active tenant's subscription.
Config reference (xBilling)
| Key | Default | Notes |
|---|---|---|
baseUrl | '' (same origin) | Prefer NUXT_PUBLIC_X_BILLING_BASE_URL (env wins) |
endpoints.* | /api/billing/* | Per-endpoint path overrides (merged per key) |
pages.billing / pages.pricing | true | false disables the default page (404) |
entitledStatuses | ['active','trialing'] | Replaces the default when set |
checkout.successUrl / checkout.cancelUrl | — | Sent to the checkout endpoint |
portal.returnUrl | — | Sent to the portal endpoint |
tenancy.enabled | false | Per-org billing (above) |
Environment variables
| Variable | Description |
|---|---|
NUXT_PUBLIC_X_BILLING_BASE_URL | Base URL of your billing backend. Empty = same origin. Wins over xBilling.baseUrl. |
AI Context
package: "@xenterprises/nuxt-x-billing"
version: "0.1.0"
use-when: >
Adding Stripe billing to a Nuxt 4 app without coupling the frontend
to Stripe. The consumer backend implements eight endpoints (reads,
checkout/portal sessions, cancel/resume, webhook → subscription sync)
and owns entitlements; the layer ships useBilling(), XBBillingGate,
container components wrapping XABilling* presentationals, and default
/billing + /billing/pricing pages. Optional per-org billing composes
with nuxt-x-tenancy via the $xTenantId provider contract — no hard peer.
Backend requirements
What the backend must provide for nuxt-x-tenancy — the better-auth organization endpoints, the tenant id contract, and the X-Tenant-ID data-API contract.
useBilling
Billing state, actions, and entitlement helpers for nuxt-x-billing — subscription/plans/invoices/payment methods, checkout/portal/cancel/resume, hasFeature/hasPlan/canInviteMember.
