Nozle
SDKsReact SDK

Components

Drop-in billing UI components for React

All components are exported from @nozle-js/react and use --nozle-* CSS custom properties for theming. They work with any design system -- just set the CSS variables on a parent element or :root.

Components that make API calls (CheckoutButton, UpgradeButton, CreditTopUpButton) must be wrapped in a BillingPortalProvider. Components that read subscription data (CurrentPlan, CreditBalance, CreditHistory, InvoiceList) require a BillingProvider ancestor.


Pricing Components

PricingTable

Renders plan cards in a responsive grid with a monthly/annual toggle. Auto-fetches plans from the API when no plans prop is provided, and auto-detects the current plan when customerId is set.

import { PricingTable } from '@nozle-js/react';

// Auto-fetch plans from API, auto-detect current plan
<PricingTable
  customerId="cust_123"
  highlightPlan="pro"
  onSelect={(plan) => handleUpgrade(plan)}
/>

// Or pass plans explicitly
<PricingTable
  plans={[
    { code: 'starter', name: 'Starter', amount_cents: 2900, amount_currency: 'USD', interval: 'monthly' },
    { code: 'pro', name: 'Pro', amount_cents: 9900, amount_currency: 'USD', interval: 'monthly', description: 'Most popular' },
  ]}
  features={[
    ['10K API calls', 'Email support'],
    ['100K API calls', 'Priority support', 'Analytics'],
  ]}
  currentPlanCode="starter"
  highlightPlan="pro"
  onSelect={(plan) => console.log('Selected:', plan.code)}
  showToggle={true}
  enterpriseEmail="sales@example.com"
  className="my-pricing"
/>;
PropTypeDefaultDescription
customerIdstring--Customer ID for auto-detecting current plan via API
currentPlanCodestring--Explicitly set current plan (overrides auto-detect)
plansPricingPlan[]--Plans to display (auto-fetched from /api/v1/plans if omitted)
featuresstring[][]--Feature lists per plan (index-matched to plans array)
onSelect(plan: PricingPlan) => void--Called when a plan's CTA is clicked
highlightPlanstring--Plan code to highlight as "Most Popular"
enterpriseEmailstring--Email for enterprise plan "Contact Sales" mailto link
showTogglebooleantrueShow monthly/annual toggle (only renders when annual plans exist)
classNamestring--CSS class for the outer wrapper

PricingPlan type

FieldTypeRequiredDescription
codestringYesUnique plan identifier (matches plan code from API)
namestringYesDisplay name
amount_centsnumberYesPrice in cents
amount_currencystringYesCurrency code (USD, EUR, GBP, JPY)
intervalstringYesBilling interval (monthly or yearly)
descriptionstringNoSubtitle below the plan name

CSS Variable Theming

PricingTable uses CSS custom properties for full theming control. Component-specific variables fall back to global Nozle variables, which fall back to sensible defaults:

:root {
  /* Component-specific (highest priority) */
  --nozle-pricing-bg: #ffffff;
  --nozle-pricing-card-bg: #ffffff;
  --nozle-pricing-highlight: #6366f1;
  --nozle-pricing-border: #e5e7eb;
  --nozle-pricing-radius: 12px;

  /* Global Nozle variables (fallbacks) */
  --nozle-background: #ffffff;
  --nozle-card: #ffffff;
  --nozle-primary: #6366f1;
  --nozle-border: #e5e7eb;
  --nozle-radius: 12px;
  --nozle-foreground: #111827;
  --nozle-muted-foreground: #6b7280;
  --nozle-muted: #f3f4f6;
  --nozle-primary-foreground: #ffffff;
}

PlanCard

Individual pricing plan card. Used internally by PricingTable, but can be rendered standalone for custom layouts.

import { PlanCard } from '@nozle-js/react';

<PlanCard
  id="pro"
  name="Pro"
  monthlyPrice={99}
  annualPrice={990}
  features={['100K API calls', 'Priority support', 'Analytics']}
  isAnnual={false}
  isCurrent={false}
  onSelect={() => handleUpgrade('pro')}
/>;
PropTypeDefaultDescription
...PlanPlan--All fields from the Plan type (see above)
isAnnualboolean--Whether to show annual or monthly price
isCurrentboolean--Highlights card border and disables CTA
onSelect() => void--Click handler for the CTA button
childrenReactNode--Custom content below the features list

PlanComparison

Side-by-side feature comparison table. Boolean values render as check/cross icons; strings render as text.

import { PlanComparison } from '@nozle-js/react';

<PlanComparison
  plans={plans}
  features={[
    { key: 'api_calls', label: 'API Calls', values: { starter: '10K', pro: '100K' } },
    { key: 'analytics', label: 'Analytics', values: { starter: false, pro: true } },
    { key: 'support', label: 'Priority Support', values: { starter: false, pro: true } },
  ]}
/>;
PropTypeDefaultDescription
plansPlan[]--Plans used as column headers
featuresComparisonFeature[]--Rows in the comparison table

ComparisonFeature type

FieldTypeDescription
keystringUnique row identifier
labelstringHuman-readable feature name
valuesRecord<string, string | boolean>Map of plan.id to value. Booleans render as check/cross icons.

PlanBadge

Inline badge displaying the plan name with tier-based coloring.

import { PlanBadge } from '@nozle-js/react';

<PlanBadge plan="Pro" tier="pro" />
<PlanBadge plan="Free" tier="free" />
<PlanBadge plan="Enterprise" tier="enterprise" />
PropTypeDefaultDescription
planstring--Text displayed inside the badge
tier'free' | 'starter' | 'pro' | 'enterprise''free'Controls background and text color

Checkout and Billing Actions

CheckoutButton

Initiates a checkout session and routes to the appropriate payment processor. Supports Stripe (hosted redirect and embedded Elements) and Razorpay.

Must be used inside a BillingPortalProvider.

import { CheckoutButton } from '@nozle-js/react';

// Stripe hosted checkout (redirect)
<CheckoutButton
  planId="pro_monthly"
  label="Subscribe"
  onError={(err) => console.error(err)}
/>

// Stripe embedded checkout
<CheckoutButton
  planId="pro_monthly"
  onStripeClientSecret={(secret) => setClientSecret(secret)}
/>

// Razorpay checkout
<CheckoutButton
  planId="pro_monthly"
  razorpayKeyId="rzp_live_xxx"
  onSuccess={(paymentId) => console.log('Paid:', paymentId)}
/>
PropTypeDefaultDescription
planIdstring--Plan to check out
labelstring'Get Started'Button text
apiBaseUrlstring'https://api.nozle.app'API base URL
classNamestring--CSS class for the button
styleReact.CSSProperties--Inline styles
onError(error: Error) => void--Called on checkout failure
razorpayKeyIdstring--Razorpay key_id (required for Razorpay path)
onStripeClientSecret(clientSecret: string) => void--Called with the Stripe client secret for embedded Elements
onSuccess(paymentId: string) => void--Called with Razorpay payment ID on success

Checkout

Stripe Elements drop-in checkout form. Mount this after receiving a clientSecret from CheckoutButton or your own backend.

Requires @stripe/react-stripe-js and @stripe/stripe-js as peer dependencies.

import { Checkout } from '@nozle-js/react';

<Checkout
  clientSecret="pi_xxx_secret_xxx"
  publishableKey="pk_live_xxx"
  submitLabel="Pay now"
  onSuccess={(paymentIntentId) => router.push('/success')}
  onError={(err) => toast.error(err.message)}
  onReady={() => setLoading(false)}
/>
PropTypeDefaultDescription
clientSecretstring--Stripe PaymentIntent client secret
publishableKeystring--Stripe publishable key
stripeAccountstring--Stripe Connect account ID
submitLabelstring'Pay now'Text on the submit button
onSuccess(paymentIntentId: string) => void--Called when payment succeeds without redirect
onError(error: Error) => void--Called on payment failure
onReady() => void--Called when the PaymentElement becomes interactive
classNamestring--CSS class for the outer wrapper
styleReact.CSSProperties--Inline styles for the outer wrapper

The useCheckout hook is available inside the Checkout tree for programmatic control:

import { useCheckout } from '@nozle-js/react';

function CustomSubmit() {
  const { confirmPayment, isProcessing, error } = useCheckout();
  return <button onClick={confirmPayment} disabled={isProcessing}>Pay</button>;
}

UpgradeButton

Opens an UpgradeModal with a live proration preview. Must be used inside a BillingPortalProvider.

import { UpgradeButton } from '@nozle-js/react';

<UpgradeButton
  targetPlanId="pro_monthly"
  label="Upgrade to Pro"
  onUpgraded={() => router.refresh()}
/>
PropTypeDefaultDescription
targetPlanIdstring--Plan the customer is upgrading to
labelstring'Upgrade'Button text
apiBaseUrlstring'https://api.nozle.app'API base URL
classNamestring--CSS class for the button
styleReact.CSSProperties--Inline styles
onUpgraded() => void--Called after the upgrade is confirmed

UpgradeModal

Modal dialog showing a proration preview before confirming a plan change. Fetches preview from POST /api/v1/subscriptions/preview and confirms via POST /api/v1/subscriptions/change.

Displays: credit from current plan, new plan charge, net amount due today, and next billing date.

import { UpgradeModal } from '@nozle-js/react';

<UpgradeModal
  isOpen={showModal}
  targetPlanId="pro_monthly"
  customerId="cus_xxx"
  apiBaseUrl="https://api.nozle.app"
  apiKey="pk_xxx"
  onConfirm={() => setShowModal(false)}
  onCancel={() => setShowModal(false)}
/>
PropTypeDefaultDescription
isOpenboolean--Controls modal visibility
targetPlanIdstring--Plan the customer is upgrading to
customerIdstring--Customer identifier
apiBaseUrlstring'https://api.nozle.app'API base URL
apiKeystring''API key for authorization
onConfirm() => void--Called after successful upgrade
onCancel() => void--Called when the user dismisses the modal

ProrationPreview type

FieldTypeDescription
creditnumberCredit from the remaining time on the current plan
debitnumberCharge for the new plan
netnumberAmount due today (debit - credit)
nextBillingDatestringISO date string of the next billing cycle

CreditTopUpButton

Opens a dialog for purchasing credits. Displays preset amounts ($10, $25, $50, $100, $250) with an optional custom amount input.

Must be used inside a BillingPortalProvider.

import { CreditTopUpButton } from '@nozle-js/react';

<CreditTopUpButton
  label="Add Credits"
  onSuccess={(amount) => toast.success(`Added $${amount} in credits`)}
  onError={(err) => toast.error(err.message)}
/>
PropTypeDefaultDescription
labelstring'Add Credits'Button text
apiBaseUrlstring'https://api.nozle.app'API base URL
classNamestring--CSS class for the button
styleReact.CSSProperties--Inline styles
onSuccess(amount: number) => void--Called with the purchased amount
onError(error: Error) => void--Called on purchase failure

CancelSubscriptionButton

Two-step cancellation flow. Step 1 shows a confirmation dialog. Step 2 presents a reason survey with five options: Too expensive, Missing features, Switching to competitor, Not using it enough, and Other (with free-text input). Submits DELETE /api/v1/subscriptions/{id} with the selected reason.

import { CancelSubscriptionButton } from '@nozle-js/react';

<CancelSubscriptionButton
  subscriptionId="sub_xxx"
  onCancelled={() => router.push('/goodbye')}
/>
PropTypeDefaultDescription
subscriptionIdstring--Subscription to cancel
onCancelled() => void--Called after the cancellation completes

The exported CANCEL_REASONS constant contains the five reason strings if you need them elsewhere:

import { CANCEL_REASONS } from '@nozle-js/react';
// ["Too expensive", "Missing features", "Switching to competitor", "Not using it enough", "Other"]

Billing Portal Components

BillingPortalProvider

Context wrapper that provides { customerId, apiKey } to all nested SDK components. Required by CheckoutButton, UpgradeButton, and CreditTopUpButton.

import { BillingPortalProvider } from '@nozle-js/react';

<BillingPortalProvider customerId="cus_xxx" apiKey="pk_xxx">
  <PricingTable plans={plans} />
  <CheckoutButton planId="pro" />
</BillingPortalProvider>
PropTypeDefaultDescription
customerIdstring--Customer identifier passed to all child components
apiKeystring--Publishable API key (pk_ prefix)
childrenReactNode--Child components

Access the context directly with the useBillingPortal hook:

import { useBillingPortal } from '@nozle-js/react';

const { customerId, apiKey } = useBillingPortal();

BillingPortal

Aggregated portal view that composes CurrentPlan, UsageDashboard, InvoiceList, and CreditBalance into a single vertical layout.

import { BillingPortal } from '@nozle-js/react';

<BillingPortal
  customerId="cus_xxx"
  usageFeatures={[
    { key: 'api_calls', label: 'API Calls', used: 8200, limit: 10000 },
    { key: 'storage', label: 'Storage (GB)', used: 3, limit: 10 },
  ]}
  onChangePlan={() => router.push('/plans')}
/>
PropTypeDefaultDescription
customerIdstring--Customer identifier
usageFeaturesUsageDashboardFeature[]--Usage data passed to the embedded UsageDashboard
usageLoadingbooleanfalseShows skeleton placeholders for the usage section
onChangePlan() => void--Called when the "Change Plan" button is clicked
subscriptionIdstring--Subscription ID for the cancel button
onCancelled() => void--Called after subscription cancellation

CurrentPlan

Displays the customer's active subscription: plan name (with PlanBadge), billing interval, status, and next billing date. Fetches from GET /api/v1/subscriptions/current.

import { CurrentPlan } from '@nozle-js/react';

<CurrentPlan
  customerId="cus_xxx"
  onChangePlan={() => router.push('/plans')}
/>
PropTypeDefaultDescription
customerIdstring--Customer identifier
onChangePlan() => void--Callback for the "Change Plan" button. If omitted, navigates to changePlanHref.
changePlanHrefstring'/plans'Fallback URL when onChangePlan is not provided

CurrentPlanData type

FieldTypeDescription
idstringSubscription ID
planNamestringDisplay name of the plan
intervalstringBilling interval (e.g., "monthly", "annual")
statusstringSubscription status (e.g., "active", "canceled")
nextBillingDatestringISO date of next charge
tier'free' | 'starter' | 'pro' | 'enterprise'Controls badge styling

CreditBalance

Displays the customer's current credit balance. Uses the useCredits hook internally.

import { CreditBalance } from '@nozle-js/react';

<CreditBalance customerId="cus_xxx" currency="USD" />
PropTypeDefaultDescription
customerIdstring--Customer identifier
currencystring'USD'Currency code for formatting (e.g., 'EUR', 'GBP')

CreditHistory

Renders a table of credit transactions sorted newest-first. Shows up to 20 rows with a "View all" link when there are more.

import { CreditHistory } from '@nozle-js/react';

<CreditHistory
  customerId="cus_xxx"
  viewAllHref="/billing/credits"
/>
PropTypeDefaultDescription
customerIdstring--Customer identifier
viewAllHrefstring'/billing/credits'Link target for "View all" when there are more than 20 transactions

CreditTransaction type

FieldTypeDescription
idstringTransaction ID
amountnumberCredit amount
typestringOne of 'grant', 'deduct', 'purchase', 'application'
descriptionstringHuman-readable description
createdAtstringISO timestamp

InvoiceList

Displays customer invoices in a table with status badges and PDF download links. Fetches from GET /api/v1/invoices.

import { InvoiceList } from '@nozle-js/react';

<InvoiceList customerId="cus_xxx" />
PropTypeDefaultDescription
customerIdstring--Customer identifier

Invoice type

FieldTypeDescription
idstringInvoice ID
numberstringInvoice number (e.g., INV-001)
datestringISO date string
amountnumberAmount in cents
currencystringCurrency code
status'draft' | 'open' | 'paid' | 'void' | 'uncollectible'Invoice status
pdf_urlstringURL to download the invoice PDF

PaymentMethodDisplay

Shows the customer's saved payment method (card brand, last 4 digits, expiry) with an "Update Payment Method" button.

import { PaymentMethodDisplay } from '@nozle-js/react';

<PaymentMethodDisplay
  paymentMethod={{
    brand: 'visa',
    last4: '4242',
    expMonth: 12,
    expYear: 2027,
  }}
  onUpdatePaymentMethod={() => setShowCheckout(true)}
/>
PropTypeDefaultDescription
paymentMethodPaymentMethod--Card details to display. Shows "No payment method on file." when undefined.
onUpdatePaymentMethod() => void--Click handler for the update button. If omitted, navigates to updateHref.
updateHrefstring'/billing/update-payment'Fallback URL when onUpdatePaymentMethod is not provided

PaymentMethod type

FieldTypeDescription
last4stringLast 4 digits of the card
brandstringCard brand (visa, mastercard, amex, discover, jcb, diners, unionpay)
expMonthnumberExpiration month (1-12)
expYearnumberExpiration year (4-digit)

Usage Components

UsageMeter

Progress bar with automatic color thresholds based on usage percentage.

PercentageColor zone
< 80%Primary (normal)
80 -- 94%Warning (amber)
>= 95%Destructive (red)
import { UsageMeter } from '@nozle-js/react';

<UsageMeter used={8200} limit={10000} label="API Calls" />
<UsageMeter used={9800} limit={10000} label="API Calls" showText={false} />
PropTypeDefaultDescription
usednumber--Current usage count
limitnumber--Maximum allowed usage
labelstring--Label shown above the progress bar
showTextbooleantrueWhether to display the "used / limit" text

The getUsageMeterColor helper is also exported for use in custom components:

import { getUsageMeterColor } from '@nozle-js/react';

const color = getUsageMeterColor(92); // returns the warning CSS variable

UsageDashboard

Renders multiple UsageMeter bars for all tracked features. Shows skeleton placeholders when loading.

import { UsageDashboard } from '@nozle-js/react';

<UsageDashboard
  features={[
    { key: 'api_calls', label: 'API Calls', used: 8200, limit: 10000 },
    { key: 'storage', label: 'Storage (GB)', used: 3, limit: 10 },
    { key: 'seats', label: 'Team Seats', used: 4, limit: 5 },
  ]}
/>
PropTypeDefaultDescription
featuresUsageDashboardFeature[][]Array of usage features to display
loadingbooleanfalseShows skeleton placeholders when true

UsageDashboardFeature type

FieldTypeDescription
keystringUnique feature identifier
labelstringHuman-readable feature name
usednumberCurrent usage count
limitnumberMaximum allowed usage

UsageAlert

Dismissible warning banner shown when any feature's usage percentage meets or exceeds the threshold. Includes an upgrade link.

import { UsageAlert } from '@nozle-js/react';

<UsageAlert
  features={[
    { key: 'api_calls', label: 'API Calls', percentage: 92 },
    { key: 'storage', label: 'Storage', percentage: 45 },
  ]}
  threshold={80}
  upgradeHref="/plans"
/>

Only features at or above the threshold are shown. In the example above, only the "API Calls" alert would render (92% >= 80%). The "Storage" alert would not appear (45% < 80%).

PropTypeDefaultDescription
featuresUsageAlertFeature[]--Array of features with their current usage percentage
thresholdnumber80Minimum percentage to trigger a warning
upgradeHrefstring'/plans'URL for the "Upgrade" link in each alert

UsageAlertFeature type

FieldTypeDescription
keystringUnique feature identifier
labelstringHuman-readable feature name
percentagenumberCurrent usage percentage (0-100)

On this page