> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nozle.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# BillingPortal

> A customer billing portal in your app: subscriptions, usage, wallets, billing details and invoices, with optional plan changes and cancellation.

`BillingPortal` renders a full customer billing page inside your app, read from Nozle with a short-lived, customer-scoped session that your backend issues.

**When to use**

* A "Billing" page in your app's settings.
* A link from [`CurrentPlan`](/sdks/react/components/current-plan) ("Manage billing").
* Self-service for subscriptions, wallets, billing information and invoices in one place.

You do not need a `BillingProvider` or Tailwind for it.

**Light**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, light theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/light.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=5c7eb4cf2be05190e9940229a234842a)

**Dark**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, dark theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/dark.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=ecaecf886b0ca955d7ea47b10ec3f7c7)

**Minimal**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, minimal theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/minimal.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=48266840d58439d804bbb4ebc6dac131)

**Neobrutal**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, neobrutal theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/neobrutal.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=21e4e3aad1b282c5ab639e0a7aff07e3)

**Nozle**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, nozle theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/nozle.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=987253a76d7edea95629593115bcb3e2)

**Nozle Dark**

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, nozleDark theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/nozle-dark.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=97bedc049c096b59bbf766f0563f275c)

## Importing BillingPortal

```tsx theme={null}
import {
  BillingPortal,
  BillingPortalError,
  type BillingPortalSession,
  type CreateBillingPortalSession,
} from '@nozle-js/react'
```

## Rendering BillingPortal

`createSession` asks your backend for a portal session:

```tsx app/settings/billing/page.tsx theme={null}
'use client'

const createSession: CreateBillingPortalSession = async ({ signal }) => {
  const response = await fetch('/api/billing/session', {
    method: 'POST',
    credentials: 'same-origin',
    signal,
  })
  if (!response.ok) throw new Error(`Billing session failed: ${response.status}`)
  const session: BillingPortalSession = await response.json() // { token, apiUrl }
  return session
}

export default function CustomerBilling() {
  return (
    <BillingPortal
      createSession={createSession}
      locale="en-US"
      onError={(error) => console.warn(error.code)}
    />
  )
}
```

Any rejection of `createSession` shows as a `session` error. Keep `createSession` stable across renders: a new function starts a new session. Change `key` when the signed-in account changes.

### What the portal shows

* Subscriptions with status, price, current period and usage details.
* Wallets with their balance and a top-up form.
* Billing information with an edit form.
* Invoice history with search, pages and PDF downloads.

## Data

`createSession` returns a `BillingPortalSession`: `{ token, apiUrl }`. The portal reads everything else itself.

### Live data

Your backend issues the session. It reads the customer's portal URL from Core (`GET /api/v1/customers/{external_id}/portal_url`) with your secret key, takes the token from it, and returns `{ token, apiUrl }`. The portal then reads subscriptions, usage, wallets and invoices from Core's customer-portal GraphQL with that token. [Billing portal and self-service](/sdks/react/billing-portal#issue-the-portal-session) shows the backend step and the plan-change and cancellation adapters.

## Examples

### Plan changes and cancellation

With `planChangeActions` and `cancellationActions`, each subscription shows [`PlanChangeControl`](/sdks/react/components/plan-change-control) and [`CancellationControl`](/sdks/react/components/cancellation-control).

![BillingPortal with a Pro subscription, a prepaid credits wallet, billing information and two paid invoices, light theme](https://mintcdn.com/nozle-d78f01d8/Ae2cAgwEfN_SPqzG/images/react/components/billing-portal/light.png?fit=max\&auto=format\&n=Ae2cAgwEfN_SPqzG\&q=85\&s=5c7eb4cf2be05190e9940229a234842a)

```tsx theme={null}
import type { CancellationActions, PlanChangeActions } from '@nozle-js/react'

export function FullPortal(props: {
  accountId: string
  createSession: CreateBillingPortalSession
  cancellationActions: CancellationActions
  planChangeActions: PlanChangeActions
}) {
  return (
    <BillingPortal
      key={props.accountId}
      createSession={props.createSession}
      cancellationActions={props.cancellationActions}
      planChangeActions={props.planChangeActions}
    />
  )
}
```

## API reference

**createSession** `(\{ signal \}: \{ signal: AbortSignal \}) =\> Promise\<BillingPortalSession\>` *required*

Fires on mount, on "Reconnect" and on "Refresh portal", and receives an `AbortSignal`. Returns `{ token, apiUrl? }`. `apiUrl` is the Core base URL without `/graphql` and defaults to `https://api.nozle.app/core`. The token stays in memory.

**planChangeActions** `PlanChangeActions`

Shows [`PlanChangeControl`](/sdks/react/components/plan-change-control) on each subscription. Without it there are no plan changes.

**cancellationActions** `CancellationActions`

Shows [`CancellationControl`](/sdks/react/components/cancellation-control) on each subscription. Without it there is no Cancel or Keep.

**locale** `string` (default: en-US)

Formats amounts and dates. The text is English.

**onError** `(error: BillingPortalError) =\> void`

Fires when a request fails and receives a `BillingPortalError` whose `code` is `session`, `unauthorized`, `request` or `changed`. The message never contains the token or response details.

**className** `string`

Class names on the root, after `nozle-billing-portal`.

**style** `CSSProperties`

Inline styles on the root.

**nonce** `string`

CSP nonce for the portal's `<style>` elements.

**appearance** `Appearance`

Theme, variables and element overrides on top of the provider's, also applied to the controls and dialogs inside. The older `--nozle-portal-*` variables still work. See [Appearance](/sdks/react/styling).

### States

| State | What shows |
| - | - |
| Starting | "Starting billing session…", then "Loading billing data…". |
| Session failed or took over 20 seconds | "Could not start your billing session. Please try again." with "Try again". |
| Session expired | "Your billing session has expired. Reconnect to continue." with "Reconnect". |
| A request failed | "Could not complete this billing request. Please try again." with "Try again". |

The portal shows [Powered by Nozle](/sdks/react/components/powered-by-nozle) when its session says to.

### Appearance

> **Element keys**
>
> `billingPortal` (root), `billingPortal__section`, `billingPortal__card` (subscription and wallet cards), `billingPortal__table` (usage and invoice tables), `billingPortal__error`.
>
> Style them with `appearance.elements`. See [Elements](/sdks/react/styling#elements).

## Related

> **[Billing portal and self-service](/sdks/react/billing-portal)**
>
> Session, adapters and runnable backends.

> **[PlanChangeControl](/sdks/react/components/plan-change-control)**
>
> Plan changes on your own page.

> **[CancellationControl](/sdks/react/components/cancellation-control)**
>
> Cancel and Keep on your own page.

> **[CurrentPlan](/sdks/react/components/current-plan)**
>
> A compact plan summary.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.