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

# Payouts

# External bank payouts

Send **same-currency fiat** from a customer account to an **outside** bank (SEPA / ACH / CAD EFT / SWIFT). Source is always a customer-owned fiat `account_id` (`pcus_*`). Destination is beneficiary + bank details, not another ledger `account_id`.

| Flow                                            | Destination                            |
| ----------------------------------------------- | -------------------------------------- |
| [Book transfers](/customers/book-transfers)     | Another account under the same API key |
| **Payout**                                      | External beneficiary bank              |
| [Stablecoin sends](/customers/stablecoin-sends) | Crypto wallet                          |

Prerequisite: [Customers quickstart](/customers/quickstart). Banking gate: `products.deposit_account.status=ready`.

<Warning>
  **Sandbox:** full payout preview → confirm is often **not** exercisable end-to-end. Deposit rails may not credit usable fiat balance, and there may be no partner-safe sandbox beneficiary for a real bank push. Prefer validating **preview validation** (for example amount above `available` → **422**) and field shapes. Contact Element Pay if you need a sandbox credit or a known-good test beneficiary. **Live:** fund the source account (deposit instructions or corridor quote → accept where applicable), then run preview → confirm only when you intend to send funds.
</Warning>

## Auth and environments

```bash theme={null}
export BASE_SANDBOX="$BASE_SANDBOX"   # sandbox Partner API base
export BASE_LIVE="$BASE_LIVE"         # live Partner API base
export BASE="$BASE_SANDBOX"
export API_KEY="is_test_…"            # or is_live_… on live
```

```http theme={null}
X-API-Key: <API_KEY>
Content-Type: application/json
```

## Gates

| Gate               | Field                                        | Unlocks                                    |
| ------------------ | -------------------------------------------- | ------------------------------------------ |
| **Quote identity** | `status` is `approved` (or `active`)         | `customer_id` on quote                     |
| **Banking**        | `products.deposit_account.status` is `ready` | Fiat payouts from that customer's accounts |

Source `account_id` must belong to `{customer_id}`.

If banking routes are called before `ready`, expect **409** with `data` such as `deposit_account_status` and `reason: banking_profile_incomplete`.

## Happy path

<Steps>
  <Step title="Confirm banking ready">
    Poll `GET /partner/customers/{customer_id}` until `deposit_account.status=ready`
  </Step>

  <Step title="List accounts">
    Resolve source fiat `account_id` via `GET …/accounts`
  </Step>

  <Step title="Preview">
    `POST …/payouts/preview` with `amount`, `beneficiary`, `bank` → `preview_token`
  </Step>

  <Step title="Confirm">
    `POST …/payouts` with `preview_token` + `idempotency_key` (tokens expire quickly; use a fresh preview)
  </Step>

  <Step title="Poll">
    `GET …/payouts/{payout_id}` until terminal status
  </Step>
</Steps>

## 1. Resolve source account

```bash theme={null}
export FROM_CUSTOMER="pcus_…"   # approved/active + deposit_account ready

curl -sS "$BASE/partner/customers/$FROM_CUSTOMER/accounts" \
  -H "X-API-Key: $API_KEY" | jq '.data'

export ACCOUNT_ID="…"   # fiat account in the payout currency
```

## 2. Preview

Preview and confirm must use the **same** source `account_id`. Required bank fields depend on currency / scheme (EUR SEPA: `iban` + `country`; USD ACH: `routing_number` + `account_number`; CAD EFT: institution + transit + account; SWIFT: `scheme=swift` + `swift_bic`).

```bash theme={null}
curl -sS -X POST "$BASE/partner/customers/$FROM_CUSTOMER/accounts/$ACCOUNT_ID/payouts/preview" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "1.00",
    "beneficiary": {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "ada@example.com",
      "address": {
        "line_1": "1 Example Street",
        "city": "Berlin",
        "postal_code": "10115",
        "country": "DE"
      }
    },
    "bank": {
      "iban": "DE89370400440532013000",
      "account_holder_name": "Ada Lovelace",
      "bank_name": "Example Bank",
      "country": "DE"
    }
  }' | jq '.'
```

Typical success includes `preview_token`, amounts, fee fields (often `fee_status=pending_confirm` until confirm), and `customer_id`. Save `preview_token`.

<Note>
  In sandbox, until Element Pay has credited balance and shared a known-good beneficiary, prefer **insufficient-balance** preview checks (below) over confirm.
</Note>

## 3. Confirm

<Warning>
  On **live**, confirm initiates an **external bank payout**. Do not confirm on live unless you intend to send funds. On sandbox, confirm may still fail or be unavailable without funded balance and an approved test beneficiary.
</Warning>

```bash theme={null}
curl -sS -X POST "$BASE/partner/customers/$FROM_CUSTOMER/accounts/$ACCOUNT_ID/payouts" \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "preview_token": "<from preview response>",
    "idempotency_key": "payout-2026-08-23-001"
  }' | jq '.'
```

Reuse the same `idempotency_key` on retries after network errors. Confirm / GET typically surface final fee status.

## 4. Get payout

```bash theme={null}
curl -sS "$BASE/partner/customers/$FROM_CUSTOMER/accounts/$ACCOUNT_ID/payouts/$PAYOUT_ID" \
  -H "X-API-Key: $API_KEY" | jq '.'
```

## Business rules

1. **Same currency fiat → external bank** only (no FX on this rail).
2. **Preview → confirm** on the same source `account_id`; use a fresh preview if the token expired.
3. **Partner-neutral JSON**: error `message` / `data` do not expose upstream PSP names.
4. **Balance:** like [book transfers](/customers/book-transfers), require `available >= amount` (exact balance is allowed). This differs from [stablecoin sends](/customers/stablecoin-sends), which need amount **strictly below** `available` (1 minor-unit headroom). Insufficient balance returns **422** with `data.available`, `data.amount`, and `data.currency` when known.
5. Fees may be `pending_confirm` on preview and final on confirm/GET. **Fees can dominate small principals** (for example a fixed fee larger than a tiny payout). Always read preview / confirm / GET fee fields and do not invent a fee schedule; do not assume net receive equals `amount`.

Practical sandbox check (insufficient only): preview with `amount` above `available` → **422** + balance fields. Do **not** confirm unless you have usable balance and intend a bank push.

## Legacy routes

The same operations exist under `/partner/entities/{entity_id}/accounts/.../payouts`. Those paths are **legacy**. New integrations should use `pcus_*` customer paths only.

## Errors

| Situation                                     | Typical                                     | Action                                                                       |
| --------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------- |
| Banking gate not ready                        | `409` + `banking_profile_incomplete`        | Poll `deposit_account`                                                       |
| Insufficient balance (`amount` > `available`) | `422` + `available` / `amount` / `currency` | Lower amount or fund source account (may require Element Pay sandbox credit) |
| Invalid bank / beneficiary fields             | `422`                                       | Fix scheme-required fields for the currency                                  |
| Preview token expired / wrong account         | `4xx`                                       | Re-preview on the same source `account_id`                                   |

## Next

* [Book transfers](/customers/book-transfers)
* [Deposit instructions](/customers/deposit-instructions)
* [Stablecoin sends](/customers/stablecoin-sends)
* [Route cheat sheet](/customers/route-cheat-sheet)
