X Enterprises

nuxt-x-billing

Stripe billing layer for Nuxt 4 — useBilling() composable, plan/feature gating (XBBillingGate), and billing container components wired against a consumer-owned backend contract. The layer never talks to Stripe directly.

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.

No @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 helpers hasFeature() / 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)

KeyDefaultNotes
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.pricingtruefalse disables the default page (404)
entitledStatuses['active','trialing']Replaces the default when set
checkout.successUrl / checkout.cancelUrlSent to the checkout endpoint
portal.returnUrlSent to the portal endpoint
tenancy.enabledfalsePer-org billing (above)

Environment variables

VariableDescription
NUXT_PUBLIC_X_BILLING_BASE_URLBase 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.
Copyright © 2026