neonFin
Components

createNeonfin client

Browser client for custom credit, checkout, and wallet UI.

createNeonfin() is the zero-dependency browser client behind the React components. Use it when you want custom UI but still want the same wallet, checkout, balance, and feature logic that NeonfinProvider uses internally.

The client uses a publishable key (nf_pk_...) and stores anonymous wallet credit codes in localStorage. If your app has logged-in users and you want credits tied to your own user ids, use the server client instead.

Install

npx shadcn@latest add https://pay.vantezzen.io/r/neonfin-client.json

Create a client

import { createNeonfin } from "@/lib/neonfin";

export const neonfin = createNeonfin({
  baseUrl: process.env.NEXT_PUBLIC_NEONFIN_URL!,
  publishableKey: process.env.NEXT_PUBLIC_NEONFIN_KEY!,
});

Config

FieldTypeDescription
baseUrlstringPublic URL of your neonFin instance.
publishableKeystringProject publishable key. Safe for browser use.
storageKeystringOptional custom localStorage key for credit codes.

Common calls

const products = await neonfin.getProducts();
const code = await neonfin.getOrCreateCode();
const wallet = await neonfin.getWallet();
const result = await neonfin.deduct(10, { idempotencyKey: "job_123" });

await neonfin.startCheckout("price_..."); // popup on desktop, redirect on mobile

Credit-code methods

MethodReturnsDescription
getCode()string | nullReads the stored browser code.
setCode(code)voidSaves a recovery code, usually after restore or checkout.
clearCode()voidRemoves the stored code. The next wallet call creates a fresh wallet.
getOrCreateCode()Promise<string>Creates a wallet if needed and stores the code.

If the stored code is missing, expired, or deleted server-side, balance, deduct, and checkout calls clear it and create a fresh wallet automatically.

Catalog and wallet

MethodReturnsDescription
getProducts()Promise<Product[]>Reads active products and prices.
getWallet(code?)Promise<WalletInfo>Reads balances, features, and subscriptions in one call.
getBalances(code?)Promise<Balance[]>Reads all balances for a code wallet.
getBalance(productId?, code?)Promise<Balance | null>Reads one product balance. Without productId, returns the only product or first product.
getFeatures(code?)Promise<string[]>Reads unlocked feature slugs.
hasFeature(feature, code?)Promise<boolean>Checks whether a feature is unlocked.
hasCredits(amount, opts?)Promise<boolean>Checks whether the wallet has enough credits.

Spending credits

await neonfin.deduct(10, {
  productId: "prod_...",
  idempotencyKey: "job_123",
  meta: { feature: "render" },
});
MethodReturnsDescription
deduct(amount, opts?)Promise<{ balance: number; deducted: boolean }>Deducts credits from the browser wallet.

Pass a stable idempotencyKey for retryable work, such as a render job id or request id. If you omit it, the client generates one, which is fine for a single button click but not for server retries.

Checkout

For custom purchase UI, prefer startCheckout. Its default flow: "auto" opens a popup on desktop and uses redirect checkout on touch/mobile devices:

await neonfin.startCheckout("price_...");

Force redirect checkout when your app cannot support popups:

await neonfin.startCheckout("price_...", { flow: "redirect" });
MethodReturnsDescription
startCheckout(priceId, opts?)Promise<CheckoutResult>One-call checkout. Creates the session, remembers the order, and uses popup or redirect checkout.
createCheckout(priceId, opts?)Promise<CheckoutResult>Lower-level checkout. Returns the provider URL; you handle redirect and resume.
getOrder(ref)Promise<OrderStatus>Polls an order by order id or provider checkout id.

CheckoutResult contains:

type CheckoutResult = {
  url: string;
  checkoutId: string;
  orderId: string;
};

Billing portal

Use the portal URL when a wallet has completed at least one purchase and the user wants invoices, refunds, payment methods, or subscription management:

const url = await neonfin.getPortalUrl({
  returnUrl: window.location.href,
});

window.location.href = url;
MethodReturnsDescription
getPortalUrl(opts?)Promise<string>Creates a payment-provider customer portal URL for the current wallet.

Error handling

import { NeonfinError } from "@/lib/neonfin";

try {
  await neonfin.deduct(100);
} catch (err) {
  if (err instanceof NeonfinError && err.isInsufficientCredits) {
    console.log(`Need ${err.requested}, have ${err.balance}`);
  }
}

NeonfinError includes status, optional stable code, and for insufficient credits also balance and requested. See Errors for common status codes.