Money-moving mutations — useCreateSubscription, useChangePlan, useTopUp, usePayInvoice, and friends — resolve to a SettleOutcome: a discriminated union on kind that tells you exactly how the money moved. Pass the matching on* handler in the hook’s options, or call client.handleSettlement(result, handlers).
Outcomes
kind | Meaning | Handler |
|---|
charged_inline | Card charged + invoice paid immediately | onChargedInline |
requires_form | A hosted PSP form is needed (3DS / new card) — open result.client | onRequiresForm |
invoice_sent | NET-terms invoice issued + emailed (send-invoice customers) | onInvoiceSent |
invoice_added | Charge appended to the next invoice | onInvoiceAdded |
deferred | Scheduled for a future date | onDeferred |
created_no_charge | Created with nothing to charge | onCreated |
no_action | Already settled / zero amount | onNoAction |
Usage
import { useCreateSubscription } from '@unitpay/react';
export default function Subscribe() {
const { createSubscription, isPending } = useCreateSubscription({
onChargedInline: ({ subscription }) => router.push(`/welcome/${subscription?.id}`),
onRequiresForm: ({ client, reason }) => openHostedCheckout(client, reason),
onInvoiceSent: ({ invoice }) => toast(`Invoice ${invoice.invoiceNumber} on its way`),
});
return (
<button disabled={isPending} onClick={() => createSubscription({ planId: 'pro' })}>
Subscribe
</button>
);
}
requires_form carries a PSP client payload and a reason code — hand it to your hosted
checkout / Stripe Elements flow to collect authentication or a new card. The other outcomes are
terminal: the money has already moved (or there was nothing to do).
On success, the hook also invalidates the affected queries (customer, subscriptions, invoices, wallets) so the rest of your UI refreshes automatically.