Skip to main content
Hooks for the wallet surface of a customer portal — list saved methods and set-default / detach them, preflight what a detach would break, capture a new method, and atomically swap an in-use default. Together they cover the “you can’t just delete the card that’s paying for things” flow safely. Every hook returns loading/error state — reads via isLoading: boolean, mutations via isPending: boolean — plus error: Error | null. See Introduction. The sections below list each hook’s specific returns.

usePaymentMethods

Loads the customer’s saved payment methods and exposes the two write actions a wallet UI needs: setDefault(id) and detach(id). Both invalidate the customer scope on success so the list re-renders. Takes no arguments; the customer comes from <UnitPayProvider> context. Returns
  • paymentMethodsPaymentMethod[] — the customer’s saved methods, or [] while loading or when none exist. Card fields (cardLast4, cardBrand, expMonth, expYear) are null for non-card types.
  • setDefault(paymentMethodId)(id: string) => Promise<void> — points the customer default at this method. Invalidates the customer scope on success.
  • detach(paymentMethodId)(id: string) => Promise<void> — removes the method. Invalidates the customer scope on success. Throws PmInUseError when the method is a default still powering an active sub or auto-topup rule (see the warning below).
  • isActingbooleantrue while a setDefault or detach mutation is in flight.
detach() throws PmInUseError when the method is the customer default and is still powering an active subscription or auto-topup rule (server 409 pm_in_use). The error carries paymentMethodId, activeSubscriptionIds, autoTopupAccountIds, and requestId from error.details — render the block reason and route the user to the replace flow. Preflight it with usePaymentMethodDependencies so you never show a “Remove” button that’s doomed to throw.

usePaymentMethodDependencies

The preflight query for a “remove card” confirmation modal. It returns whether the method is the customer default and, if so, the active subscriptions and auto-topup credit accounts that a detach would orphan. data.blocksDetach mirrors the server-side guardrail — when true, route the user to the replace flow instead of letting them click “Delete”. Parameters
string
required
The method to inspect. The query is disabled while this is null / undefined.
boolean
When false, the query is disabled — useful for a modal that fetches on open (enabled: isOpen). Defaults to true.
Returns — a TanStack UseQueryResult<PaymentMethodDependencies, Error> (short staleTime of 10s, because dependency state changes whenever subs / auto-topup rules change). data once loaded is PaymentMethodDependencies:
  • paymentMethodId string
  • isDefault boolean — whether this is the customer default.
  • blocksDetach booleantrue when detaching would orphan an active sub or auto-topup rule.
  • activeSubscriptionsArray<{ id, status, planId, collectionMethod, currentBillingPeriodEnd }>.
  • autoTopupAccountsArray<{ id, creditCurrencyId, autoTopupThreshold, autoTopupAmount, autoTopupPackageId }>.

useSetupPaymentMethod

Mutation that captures a new payment method via a PSP SetupIntent. It always resolves to a requires_form SettleOutcome — the server mints a SetupIntent and returns the PSP client envelope, which you mount in <PaymentForm mode="save_only">. After the customer completes setup and the PSP webhook attaches the method, the payment-methods cache is invalidated so the next render shows it. Parameters
HandleSettlementOptions
Settlement callbacks dispatched after the mutation resolves — wire onRequiresForm to mount the inline form. See the Settlement model.
The setupPaymentMethod(input?) alias accepts an optional input:
string
Where to send the customer after a successful hosted-mode setup.
string
Where to send the customer if they abandon a hosted-mode setup.
'embedded' | 'hosted'
Whether to render the form inline (embedded) or redirect to the PSP-hosted page (hosted).
Returns — a TanStack UseMutationResult extended with setupPaymentMethod(input?), which triggers the SetupIntent and resolves to a requires_form outcome whose client.token is the Stripe Elements clientSecret.

useReplacePaymentMethod

Mutation that performs an atomic “swap A for B” — it flips the customer default to the new method and detaches the old one in one server transaction. It’s the resolution path when usePaymentMethodDependencies reports blocksDetach: the old default is still powering active subs / auto-topup rules, so you can’t just detach it. Parameters — the hook takes no arguments; the replacement pair goes to the replacePaymentMethod(input) alias:
string
required
The method being replaced — typically the customer’s current default.
string
required
The method to become the new default. Must already be attached and active (capture one first with useSetupPaymentMethod).
Returns — a TanStack UseMutationResult extended with replacePaymentMethod(input), which runs the swap and resolves to a ReplacePaymentMethodResult. On success it invalidates all customer-scoped queries (the PM list, default pointer, sub references). The result carries:
  • customerId string
  • oldPaymentMethodId string
  • newPaymentMethodId string
  • becameDefault booleantrue iff the default pointer actually moved this call.
  • clearedOldDefault booleantrue iff the old method was the default (and is now cleared).

See also

Invoices

Collect payment with usePayInvoice once a method is on file.

Settlement model

The requires_form outcome and client envelope behind card capture.

Error handling

The SDK error model and PmInUseError.

Customer

setupPayment() on useCustomer mints a hosted-link alternative.