> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useunitpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Settlement model

> How money-moving mutations resolve

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

```tsx theme={null}
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>
  );
}
```

<Note>
  `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).
</Note>

On success, the hook also invalidates the affected queries (customer, subscriptions, invoices, wallets) so the rest of your UI refreshes automatically.
