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

# Payouts

> Send money out of your balance, to a bank account or a wallet.

A payout moves money out of your balance to a **beneficiary** you have already registered. It is a
single, idempotent, unattended call: no step-up authentication, no multi-call preview-then-confirm.

There are two rails, and they behave the same way in every respect except where the money lands.

| Rail                                     | Operation                | Money arrives as                         |
| ---------------------------------------- | ------------------------ | ---------------------------------------- |
| [Fiat](/guides/payouts-fiat)             | `POST /v1/payouts/fiat`  | A bank transfer to an account            |
| [Stablecoin](/guides/payouts-stablecoin) | `POST /v1/payouts/token` | An on-chain transfer to a wallet address |

Both take the **same request body**. The rail you call, and the beneficiary you name, decide
everything else — there is no rail field, no network field and no token field to set.

This page covers what the two rails share. The per-rail pages cover what differs.

## You pay a beneficiary, not an address

You cannot send money to a raw account number or wallet address. You
[register a beneficiary](/guides/beneficiaries) first, and then pay out to its `beneficiaryId`.

```bash theme={null}
curl https://api.stablemint.net/v1/beneficiaries \
  -H "ApiKey: $STABLEMINT_API_KEY" \
  -H "Timestamp: $TIMESTAMP" \
  -H "Nonce: $NONCE" \
  -H "Signature: $SIGNATURE"
```

A beneficiary is bound to one rail. A bank-rail beneficiary cannot receive a stablecoin payout and
a wallet-rail beneficiary cannot receive a fiat one.

<Warning>
  **A wrong-rail beneficiary fails with `400`, not `404`.** The beneficiary is yours, so it
  resolves; the call then fails on the rail details it does not carry — sending a bank-rail
  beneficiary to `POST /v1/payouts/token` returns `400` with `errorKey: InvalidWalletAddress`.
  A `404` here means the id is unknown or belongs to another partner, which is a different fix.
  Check `rail` on the beneficiary before you pay it.
</Warning>

## Idempotency

Every payout requires an `idempotencyKey`, and it is the mechanism that makes a retry safe.

* **The key namespace is shared across both rails.** A key used for a fiat payout cannot be reused
  for a stablecoin payout.
* **Replay detection hashes the mapped request, not the raw bytes.** Whitespace or field ordering
  in your JSON cannot cause a spurious conflict.
* **Reusing a key with a different payload returns `409`** with `idempotency_key_reuse`.
* A blank key is treated as absent rather than as a value, so blanks do not collide with one
  another. Send a real key.

<Tip>
  Generate the key from something stable in your own system — an invoice or order id — rather than
  a random value. A random key regenerated on retry defeats the protection entirely.
</Tip>

## `status` is the outcome, not the HTTP code

<Warning>
  A `201` means the payout was **accepted**, not that it settled. Treat `status` as an **open set of
  strings**, not a fixed enum — new values can be added without a breaking version change, so match
  on the values you know and handle the rest gracefully rather than failing closed.

  Settlement is asynchronous on both rails. The terminal state arrives by webhook, never in the
  response to the call that created the payout.
</Warning>

## Errors

| Status | Meaning                                                                             |
| ------ | ----------------------------------------------------------------------------------- |
| `400`  | Malformed request, failed validation, or a beneficiary on the other rail.           |
| `401`  | Signature, timestamp or nonce failed. See [Authentication](/guides/authentication). |
| `402`  | Insufficient balance.                                                               |
| `403`  | Valid signature, but the service account is not allowed to make this call.          |
| `404`  | No such beneficiary, or it is not yours.                                            |
| `409`  | `idempotency_key_reuse` — same key, different payload.                              |

## Tracking a payout

The `reference` on the response is the business reference. Use it to look the payout up in
[Transactions](/guides/transactions), and subscribe to `transaction.status.changed` to be told when
it settles rather than polling. See [Receiving webhooks](/guides/webhooks).
