Skip to main content
PlanChangeControl lets a customer move one subscription to another plan: it loads the plans they may change to from your backend, shows the exact quote, applies the change, collects payment for an upgrade and recovers a payment after a reload. When to use
  • The subscription section of your billing settings page.
  • Paid upgrades through Checkout, and downgrades scheduled for renewal.
  • Letting the customer withdraw a scheduled change with “Keep current plan”.
BillingPortal renders this control for you when you pass planChangeActions.
The Change plan button, light theme

Importing PlanChangeControl

Rendering PlanChangeControl

Pass the subscription and actions, the callbacks that call your authenticated backend (see Live data):
components/change-plan.tsx

What a change looks like

  1. “Change plan” opens the plan list: name, price, interval, and whether each choice is an upgrade or a downgrade.
  2. “Review change” calls preview and shows the review step with the quote in minor units: new plan charge, credits applied, due now, due at the effective date, the effective and renewal dates, and a Back button.
  3. “Confirm upgrade” or “Confirm downgrade” calls apply. A paid upgrade opens Checkout; a downgrade is scheduled for renewal.
While a payment is pending, the control checks the status every 5 seconds. Retries reuse the same idempotency key, so a retry never applies a change twice.

Data

load and status return a PlanChangeState:

Live data

actions calls your authenticated backend. Each callback receives the external subscriptionId and an AbortSignal; never send the signal in the request body. Create the object once, outside the component:
lib/plan-change-actions.ts
Your backend fills the adapter with the Node, Python or Go SDK: it authenticates the customer, checks that the subscription is theirs, converts the SDK’s snake_case responses into these camelCase types, and keeps quotes and idempotency keys. Billing portal and self-service lists each callback’s input and return value, and links runnable backends.

Data from the API

Examples

Plan list

“Change plan” opens a dialog with one choice per eligible plan, marked Upgrade or Downgrade. Inside a BillingProvider, each choice also shows the plan’s description and lines from the public catalog.
The Change plan dialog with Scale selected as an upgrade and Free as a downgrade, each with its price and lines, light theme

Review step

After “Review change”, the dialog shows the quote that preview returns. An end-of-period change says the current plan and access continue until the effective date; an immediate change with nothing due says “No payment is due now for this change.”; otherwise the plan changes after the payment is confirmed.
The Confirm upgrade step with new plan charge, credits applied, due now, due at effective date, and the Back, Close and Confirm upgrade buttons, light theme

Scheduled change

When load or status returns a pendingChange, the control shows “Current plan until <date>, then <plan> at <price> / <interval>.” and a “Keep current plan” button that withdraws the change.
A scheduled downgrade to Free with the Keep current plan button, light theme

API reference

string
required
The external subscription ID. A new ID resets the control.
PlanChangeActions
required
Your backend callbacks. Each one receives subscriptionId and an AbortSignal besides the fields below. Keep the object stable across renders; a new object reloads the control.
() => void
Fires after a change took effect, was scheduled or was withdrawn, and when a re-read finds the plan or the scheduled change changed. Refresh the rest of your page here.
(error: BillingPortalError) => void
Fires when a request fails and receives a BillingPortalError with code unauthorized, request or changed.
string
Change it when something else updated this subscription; the control re-reads its state with status.
string
Sent to apply, where the payment provider returns the customer. Defaults to the current page without its query.
string
default:"en-US"
Formats amounts and dates. The text is English.
string
default:"UTC"
Time zone of the dates: an IANA name, or a Nozle TZ_ name.
string
CSP nonce for the control’s <style> elements.
Appearance
Theme, variables and element overrides on top of the provider’s. See Appearance.

States

Appearance

planChangeControl (root, also class nozle-plan-change). The plan list and the review step use the UpgradeModal elements upgradeModal, upgradeModal__dialog and upgradeModal__actions.Style them with appearance.elements. See Elements.

CancellationControl

Cancel at period end, or keep the subscription.

BillingPortal

The whole customer portal, with this control inside.

Billing portal and self-service

Backend adapters and runnable examples.

UpgradeButton

A single upgrade with your own preview.