Skip to main content
The data hooks are built on TanStack Query v5, a peer dependency:
Requires @nozle-js/react 0.11.0 and a backend on @nozle-js/node 0.13.0. usePlans reads the public plan catalog with the publishable key. The customer hooks read the signed-in customer’s billing data from a route on your own backend, so the browser never holds a secret key and can only see its own customer.

Customer hooks

Serve the hooks from your backend

createBillingHandler from @nozle-js/node is a web-standard request handler that serves every customer hook with your secret key. The customer always comes from getCustomerId, read from your session; a customer id sent by the browser is ignored.
app/api/nozle/[route]/route.ts
The last path segment picks the route: subscription, entitlement, credits, credit-history, usage, preview, invoices or invoice-download. invoices lists only the signed-in customer’s finalized invoices, and invoice-download answers 404 for an invoice of another customer. The handler answers 401 without a customer, passes Nozle’s 4xx errors through with their code, and answers 502 billing_unavailable for upstream failures without internal detail. It runs in Next.js route handlers, Hono, Remix, Bun and Deno. Then point the provider at it:
billingHeaders adds headers such as a CSRF token. Pass your app’s queryClient to share its cache and devtools; without one the provider makes its own. The hooks pass their client explicitly and never replace your app’s QueryClientProvider.

The hooks

Each hook returns TanStack Query’s result (data, isPending, error, refetch and the rest). useBillingRefresh() returns a function that reloads every billing hook, for example after checkout or a plan change.
A failed request throws BillingRequestError with status, code and requestId. A 4xx is not retried; other failures are retried twice. For subscription changes with confirmation and recovery, use the billing portal action adapters.

usePlans

Fetches GET /api/v1/plans through the BillingProvider catalog client. Calls share one cached request per publishableKey and baseUrl, kept for five minutes. A failed load is not retried automatically; call refetch(). usePlans does not fetch during server rendering; it renders the initial loading state.

Return value

CatalogPlan: type versus runtime

The TypeScript type CatalogPlan declares code, name, amount_cents, amount_currency and interval, and the optional description (string | null), entitlements, credit_grant_rules and charges. Its plans pass to PricingTable, PlanCard and PlanComparison as they are. At runtime, each item in plans is the trimmed plan object the API returns to a publishable key. usePlans does not remove or rename fields. Besides the declared fields, a plan carries nozle_id, trial_period, pay_in_advance, usage_thresholds, taxes, credit_pool_policies, and metadata when set. Invoice names, internal ids, margin settings, grant policies and timestamps are not sent to a publishable key. See the public plan catalog for every field. The list is not filtered. It includes trial plans and pay-in-arrears plans, and not plans that are pending deletion. Decide in your component which plans to show. To read an undeclared field, widen the type:
The publishable key is public, so every field it receives, including charges, taxes, minimums, credit grants and metadata, is readable by anyone who has it. Do not put sensitive or negotiated pricing in plans of an organization whose publishable key you ship. See Keep sensitive pricing out of the catalog.

useCheckoutSession

Calls BillingProvider.createCheckout with a plan code and return URL.
fetchClientSecret passes only planCode and returnUrl to createCheckout. It sends no idempotency key; use CheckoutButton when you need one. The hook returns a string only for a Stripe client secret. For a hosted result (or a result with a url), it navigates to the URL and returns null. For completed, scheduled, razorpay, and processing results it returns null without opening Razorpay or polling; read the result from checkout and handle it yourself, for example with Checkout’s checkout prop. Any other result throws Checkout response did not include a supported result type.

Return value

useBillingContext

Returns the required billing context and throws outside BillingProvider.
Use this only when building a custom catalog or checkout component. Prefer usePlans and useCheckoutSession for common flows.

useOptionalBillingContext

Returns the billing context or null outside a provider. PricingTable uses this behavior so caller-supplied plans can render without a catalog provider.

useNozleClient

Returns the browser-safe NozleClient:
catalogFetch is for public catalog endpoints only. Do not use it to proxy customer billing requests.

BillingContext

BillingContext is exported for advanced integrations that need React’s direct context API. Its value is either null or:
Prefer useBillingContext or useOptionalBillingContext in application components so missing-provider behavior stays explicit.

Checkout result types

createCheckout returns the result your merchant backend received from Nozle. It may be: Razorpay fields are snake case. A { type: 'razorpay', orderId } result fails: useCheckoutSession returns null, and CheckoutButton shows Razorpay checkout requires server-issued checkout_id, key_id and order_id. Polling calls getCheckoutStatus up to 30 times, one second apart, until both status and fulfillment_status are succeeded. The components also accept { type: 'stripe', url } and a legacy { url }, and redirect to them. Plan and invoice checkout do not return either; they return a client secret. Stripe webhooks remain authoritative. A browser redirect or completion callback does not activate a paid plan by itself.