Skip to main content
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

kindMeaningHandler
charged_inlineCard charged + invoice paid immediatelyonChargedInline
requires_formA hosted PSP form is needed (3DS / new card) — open result.clientonRequiresForm
invoice_sentNET-terms invoice issued + emailed (send-invoice customers)onInvoiceSent
invoice_addedCharge appended to the next invoiceonInvoiceAdded
deferredScheduled for a future dateonDeferred
created_no_chargeCreated with nothing to chargeonCreated
no_actionAlready settled / zero amountonNoAction

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.