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

# Payouts

> Create 1 to 100 payouts in one call, follow each through its lifecycle, and handle payouts on hold, failures and returns.

A **payout** transfers funds from one of your wallets to one payee's bank account, in the payee's currency. You create payouts with `POST /payouts`: a single call creates between 1 and 100 payouts, groups them in a [batch](https://docs.infinityapp.in/guides/batches.md), prices them, reserves their total in the wallet you choose, and sends every payout whose payee is ready.

## How it works

1. **Validate.** Infinity checks every item: the payee exists and can be paid in that currency, the amount meets the currency's rules, and each payee appears once.
2. **Price.** Each payout is priced at the current rate with your account's `fee_bearer`, exactly as a [quote](https://docs.infinityapp.in/guides/quotes-and-pricing.md) would price it.
3. **Reserve.** The total `debit_amount` is checked against the wallet's `available` amount and reserved.
4. **Send or hold.** Payouts to `active` payees are handed to the payout network as `pending`. Payouts to payees who aren't ready yet are created `awaiting_payee` and wait, with their funds reserved, until the payee is ready.

The call is atomic. If any item fails validation, or the total doesn't fit in the wallet, the request fails and no batch, payout or reservation is created, so you never have to reconcile a partially created set.

## Create payouts

```bash theme={null}
curl "$BASE/payouts" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: payout-run-2026-10" \
  -d '{
    "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
    "name": "October invoices",
    "description": "Contractor invoices, October",
    "reference": "run-2026-10",
    "items": [
      { "payee_id": "payee_c8pnahcrxqzd3z8d", "amount": "500.00", "currency": "eur", "reference": "inv-1042" },
      { "payee_id": "payee_x3k7r9mwq2dn8hat", "amount": "1200.00", "currency": "usd", "reference": "inv-1043", "metadata": { "project": "atlas" } }
    ]
  }'
```

```json Response (abridged) theme={null}
{
  "id": "batch_fcb4cuwtd6fcbmwr",
  "number": "PB-2026-21",
  "name": "October invoices",
  "description": "Contractor invoices, October",
  "status": "awaiting_payees",
  "wallet_id": "wallet_7t4m9k2qx8d3hn5r",
  "debit_currency": "usd",
  "total_debit": "1778.35",
  "total_fee": "20.00",
  "payee_count": 2,
  "payout_summary": { "total": 2, "pending": 1, "awaiting_payee": 1, "paid": 0, "...": 0 },
  "payouts": [
    {
      "id": "payout_4kz9xq7m2w8dn3ra",
      "payee_id": "payee_c8pnahcrxqzd3z8d",
      "amount": "500.00",
      "currency": "eur",
      "debit_amount": "568.35",
      "fee": "10.00",
      "rate": "0.8955",
      "payee_amount": "500.00",
      "status": "pending",
      "hold_expires_at": null,
      "reference": "inv-1042"
    },
    {
      "id": "payout_9dq3m7xk2wr5hn8t",
      "payee_id": "payee_x3k7r9mwq2dn8hat",
      "amount": "1200.00",
      "currency": "usd",
      "debit_amount": "1210.00",
      "fee": "10.00",
      "rate": "1.0000",
      "payee_amount": "1200.00",
      "status": "awaiting_payee",
      "hold_expires_at": "2026-11-25T10:05:00Z",
      "reference": "inv-1043"
    }
  ],
  "reference": "run-2026-10",
  "metadata": {},
  "created_at": "2026-10-26T10:05:00Z"
}
```

Maria is `active`, so her payout was sent immediately. Northwind Studio hasn't finished onboarding, so its payout is on hold until it does, and the batch reports `awaiting_payees`. The response is the batch, with every payout it created in `payouts`, in request order.

### Request

| Field | Required | Rules |
| - | - | - |
| `wallet_id` | Yes | The wallet that pays. Its `available` amount must cover `total_debit`. |
| `items` | Yes | 1 to 100 payouts. Each payee at most once per request. |
| `name` | No | Up to 255 characters, shown on your dashboard. Defaults to `API batch` followed by the UTC date and time. |
| `description` | No | Up to 500 characters. Applied to every payout in the batch. |
| `reference`, `metadata` | No | Your identifier and data for the batch. |

Each item:

| Field | Required | Rules |
| - | - | - |
| `payee_id` | Yes | A payee in your account that isn't `inactive`. |
| `amount` | Yes | A decimal string greater than 0 with at most 2 decimals, at or above the currency's [minimum](https://docs.infinityapp.in/guides/supported-currencies.md#payout-currencies). |
| `currency` | Yes | A currency with `payout_enabled: true`. An `active` payee can be paid only in their bank account's currency; a payee on hold only in the currency of their first payout. Accounts enabled for India enter INR payouts as `usd`. |
| `reference` | No | Your identifier for this payout, up to 100 characters, such as an invoice number. |
| `metadata` | No | Up to 20 string key-value pairs for this payout. |

The `Idempotency-Key` header is required. A retry with the same key and body returns the original batch instead of creating a second one; see [Idempotency](https://docs.infinityapp.in/guides/idempotency.md).

When a request fails validation, `param` points at the offending field, for example `items[1].amount`. Pricing and balance failures that concern the request as a whole return `param: null`.

## What you're charged

Each payout records what it cost:

| Field | Meaning |
| - | - |
| `debit_amount`, `debit_currency` | What the wallet was debited for this payout, fee included. |
| `fee` | Infinity's fee, in `debit_currency`. |
| `fee_bearer` | `account` (you paid the fee on top) or `payee` (it was deducted from the payee's side). |
| `rate` | Units of `payee_currency` per one unit of `debit_currency`. `null` until known; for INR, until settlement. |
| `payee_amount`, `payee_currency` | What the payee receives. An estimate until the payout is `paid`, and the settled amount after. |

[Quotes and pricing](https://docs.infinityapp.in/guides/quotes-and-pricing.md) explains how `fee_bearer` changes these amounts.

## Payout statuses

```mermaid theme={null}
stateDiagram-v2
  [*] --> pending: payee active
  [*] --> awaiting_payee: payee not ready
  awaiting_payee --> pending: released
  awaiting_payee --> awaiting_funds: released, wallet too low
  awaiting_funds --> pending: released
  awaiting_payee --> canceled
  awaiting_funds --> canceled
  awaiting_payee --> expired
  awaiting_funds --> expired
  pending --> processing
  pending --> failed
  processing --> paid
  processing --> failed
  paid --> returned
```

| Status | Meaning | Your action |
| - | - | - |
| `awaiting_payee` | The payee isn't ready. Funds are reserved. | None. It's released after the payee becomes `active`. |
| `awaiting_funds` | The payee is ready, but the wallet's available amount was too low at release. | Fund the wallet. It's retried at each daily release. |
| `pending` | Accepted and handed to the payout network. | None. |
| `processing` | In transit to the payee's bank. | None. |
| `paid` | Delivered to the payee's bank. | None, unless it's later `returned`. |
| `failed` | Not delivered. See `failure_code`. | Act on the [failure code](#failure-codes). The reservation is released. |
| `returned` | Delivered, then sent back by the payee's bank. | Verify the payee's details with them. |
| `canceled` | Canceled by you while on hold. | None. The reservation is released. |
| `expired` | The hold reached `hold_expires_at` before the payee was ready. | None. The reservation is released. |

`failed`, `canceled` and `expired` are terminal. `paid` is final except for one transition: a bank can return a payout days after crediting it, which moves it to `returned`. Don't treat a payout as irrevocably settled in your ledger until you're comfortable with that window.

## Payouts on hold

You can pay a payee before they've finished onboarding. The payout is created as `awaiting_payee` and its full `debit_amount` is reserved in the wallet, so the funds can't be spent twice.

* **Release.** Infinity releases payouts on hold once a day at 09:00 IST. A payout is released if its payee is `active` and has been for at least 5 minutes. Released payouts are priced again at the current rate; any difference from the reserved amount is taken from, or returned to, the wallet.
* **Insufficient funds at release.** If the wallet's available amount can't cover the repriced payout, it moves to `awaiting_funds` and is retried at every daily release until it's sent or expires. Funding the wallet doesn't release it by itself.
* **Expiry.** `hold_expires_at` is set at creation from your account's `hold_expiry_days`. A payout still on hold at that time moves to `expired` and its reservation is released.
* **Currency.** A payee's first payout on hold fixes their `currency`. Later payouts to that payee must use the same currency.

### Update a payout on hold

```bash theme={null}
curl "$BASE/payouts/payout_9dq3m7xk2wr5hn8t" \
  -H "Authorization: Bearer $INFINITY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "amount": "1350.00" }'
```

You can change `amount`, and `currency` while the payee has no bank account and no other payouts on hold. The payout is priced again and its reservation replaced; an increase is checked against the wallet's available amount. `description`, `reference` and `metadata` can't be changed. Infinity emits `payout.updated`.

### Cancel a payout on hold

```bash theme={null}
curl -X POST "$BASE/payouts/payout_9dq3m7xk2wr5hn8t/cancel" -H "Authorization: Bearer $INFINITY_KEY"
```

The payout moves to `canceled` and its reservation is released. Both update and cancel are allowed only in `awaiting_payee` and `awaiting_funds`; in any other status they fail with `409 payout_not_editable`.

## Failure codes

When a payout is `failed` or `returned`, `failure_code` identifies the cause and `failure_message` carries a fixed description of it.

| `failure_code` | Cause | Recommended action |
| - | - | - |
| `below_minimum` | The amount is below what the destination accepts. | Send a larger amount. |
| `insufficient_funds` | The wallet couldn't cover the payout when it was sent. | Fund the wallet and create a new payout. |
| `bank_account_missing` | The payee had no active bank account in that currency. | Add an address, then create a new payout. |
| `bank_details_invalid` | The payee's bank rejected the account details. | Confirm the details with the payee and contact your Infinity team to replace the address. |
| `rate_changed` | The rate changed before the payout could be sent. | Create a new payout. |
| `returned_by_bank` | The payee's bank returned the funds. | Confirm the account details with the payee. |
| `undeliverable` | The network couldn't deliver to the payee's bank. | Check the details or use another account. |
| `refunded` | The payout was refunded to your wallet. | Create a new payout if needed. |
| `refund_failed` | The payout failed and the refund is delayed. | None; our operations team follows up with you. |
| `canceled` | The payout was canceled before delivery. | Create a new payout if needed. |
| `processing_error` | An error on Infinity's side. | Retry with a new payout, or contact support with the payout ID. |

New failure codes may be added. Treat an unknown code as a generic failure and route it for review.

## Retrieve and list payouts

```bash theme={null}
curl "$BASE/payouts?status=failed&created[gte]=2026-10-01T00:00:00Z&limit=100" \
  -H "Authorization: Bearer $INFINITY_KEY"
```

`GET /payouts` filters by `status`, `payee_id`, `batch_id`, `created[gte]` and `created[lte]`, returns results newest first and pages with `limit` (up to 100) and `starting_after`. `GET /payouts/{id}` returns one payout as it is now.

## Events

Each payout emits `payout.created` when it's created, then one event per status change: `payout.pending`, `payout.awaiting_funds`, `payout.processing`, `payout.paid`, `payout.failed`, `payout.returned`, `payout.canceled` and `payout.expired`. An update emits `payout.updated`. Every event carries the full payout object as it was at that moment. See [Webhooks](https://docs.infinityapp.in/guides/webhooks.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.