---
url: /docs/payout-quotes.md
description: >-
  Lock the exchange rate and fee split before executing a payout, and see the
  exact fee breakdown and recipient amount in the response.
---

A payout quote locks the exchange rate and fee for a payout before you execute it. A payout can only execute against a valid, unexpired quote.

**Abstracted:**

It tells you exactly how much leaves the funding source and how much the recipient's bank account receives.

**Advanced:**

For a stablecoin-funded payout, the quote also returns the on-chain payload you need to authorize the token transfer: the ERC-20 contract address, ABI, and the exact decimal-adjusted amount for EVM chains.

## How it works

**Abstracted:**

A payout quote is created against a specific [bank account](/docs/bank-accounts) and expires 5 minutes after creation. The response includes the exact fee breakdown and the final amount the recipient receives, so you can show the customer a firm number before committing to the payout.

For the fiat lens, treat the stablecoin leg as settlement plumbing: you pass a `network` and `token` to price the quote, but the funding source itself (a managed wallet balance in the common case) is covered on [Payouts](/docs/payouts).

**Advanced:**

A payout quote is created against a specific [bank account](/docs/bank-accounts) and a `network` + `token` pair for the funding leg. It expires 5 minutes after creation. The response includes the fee breakdown, the final fiat amount the recipient receives, and (for EVM networks) the `contract` payload used to authorize the token pull.

### network and token

`network` and `token` select the chain and stablecoin the funding source sends from. Availability depends on your instance type:

| Instance | Networks | Tokens |
| --- | --- | --- |
| Development | `sepolia`, `base_sepolia`, `arbitrum_sepolia`, `polygon_amoy`, `stellar_testnet`, `solana_devnet` | `USDB` only |
| Production | `ethereum`, `base`, `polygon`, `arbitrum`, `stellar`, `solana`, `tron` (beta) | `USDC` or `USDT` |

Token and chain support also differ by token:

| Token | Supported networks |
| --- | --- |
| `USDC` | `polygon`, `base`, `arbitrum`, `ethereum`, `stellar`, `solana` (and their dev equivalents) |
| `USDT` | `polygon`, `ethereum`, `solana`, `tron` (and the dev equivalents, except `tron`) |
| `USDB` | development testnets only: `polygon_amoy`, `base_sepolia`, `arbitrum_sepolia`, `sepolia`, `stellar_testnet`, `solana_devnet` |

`tron` is a production-only network in beta: it has no development testnet, so it can't be exercised on a development instance. See [Supported chains](/docs/kb/supported-chains) for details.

Passing a network and token that are not compatible returns a 400 with a message naming the unsupported pair. See [Supported chains](/docs/kb/supported-chains) for the full matrix.

### currency\_type

`currency_type` tells the API which side of the payout `request_amount` is denominated in. On a payout quote, this is the opposite direction from a payin quote:

| `currency_type` | `request_amount` is denominated in |
| --- | --- |
| `sender` | The stablecoin the funding source sends (the token leg) |
| `receiver` | The fiat currency the bank account receives |

Payin quotes use the same field name with the opposite meaning: on a payin quote, `sender` means the fiat the payer sends. Always check which quote type you're building against.

### cover\_fees

Fees can be paid by either party:

| Payer | Fee basis | API setting | Dashboard option |
| --- | --- | --- | --- |
| Customer | Deducted from the fiat amount the recipient receives | `cover_fees: false` | Keep "Cover all payout fees" off |
| Sender | Added on top of the stablecoin amount sent, so the recipient receives the full amount | `cover_fees: true` | Enable "Cover all payout fees" |

Customer-paid fees are the most common case. Sender-paid fees are typical for payroll, where the company wants the recipient to receive an exact amount.

**Abstracted:**

`request_amount` is an integer in minor units; it does not accept floats. To send `$100.00`, pass `10000`.

**Advanced:**

`request_amount` is an integer in minor units; it does not accept floats. To send `100 USDC`, pass `10000`.

### SWIFT compliance documents

SWIFT payouts need compliance documents, but they are collected **after** the payout is created, not at quote creation time. Once you create the payout it is placed `on_hold` until the required documents are submitted and approved.

Documents are only required when the recipient relationship is not `first_party` (sending to a third party). Sending to your own SWIFT account never requires documents.

### Optional documents on other rails

Payouts on any other rail (wire, ACH, RTP, Pix and so on) never wait for documents, but you can still attach one for our compliance team. Call the same document submission endpoint while the payout is `processing`, `on_hold` or `completed`. The document is stored on the payout and shown to compliance; the payout `status` and `tracking_documents` are not changed, the `description` field is ignored, and submitting again replaces the previous document. Payouts that are `failed` or `refunded` return `payout_not_processing_or_completed`.

## Prerequisites

You also need a [customer](/docs/overview) who has completed KYC and a [bank account](/docs/bank-accounts) with `status: "approved"`.

## Create a payout quote

Check the required fields in the [BlindPay API Docs](https://api.blindpay.com/reference#tag/quotes/POST/v1/instances/{instance_id}/quotes){target="\_blank"}.

The quote accepts exactly one destination: `bank_account_id` (shown below) or `payable_id` to pay a registered bill. See [Payables](/docs/payables#how-to-pay-one) for that variant, where the amount comes from the bill itself.

**Abstracted:**

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/in_000000000000/quotes \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "bank_account_id": "ba_000000000000",
  "currency_type": "sender",
  "cover_fees": false,
  "request_amount": 10000,
  "network": "sepolia",
  "token": "USDB"
}'
```

```js [index.js]
const response = await fetch(
  'https://api.blindpay.com/v1/instances/in_000000000000/quotes',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      bank_account_id: 'ba_000000000000',
      currency_type: 'sender',
      cover_fees: false,
      request_amount: 10000,
      network: 'sepolia',
      token: 'USDB',
    }),
  }
)

const quote = await response.json()
```

**Advanced:**

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/in_000000000000/quotes \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "bank_account_id": "ba_000000000000",
  "currency_type": "sender",
  "cover_fees": false,
  "request_amount": 10000,
  "network": "sepolia",
  "token": "USDC"
}'
```

```js [index.js]
const response = await fetch(
  'https://api.blindpay.com/v1/instances/in_000000000000/quotes',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      bank_account_id: 'ba_000000000000',
      currency_type: 'sender',
      cover_fees: false,
      request_amount: 10000,
      network: 'sepolia',
      token: 'USDC',
    }),
  }
)

const quote = await response.json()
```

### Response

**Advanced:**

For EVM networks, the response includes a `contract` object: the payload you pass to your Ethereum library to call `approve` on the token contract, authorizing BlindPay to pull the quoted amount.

```json
{
  "id": "qu_000000000000",
  "expires_at": 1712958191000,
  "commercial_quotation": 1,
  "blindpay_quotation": 0.998,
  "sender_amount": 10000,
  "receiver_amount": 9980,
  "partner_fee_amount": 0,
  "flat_fee": 20,
  "billing_fee_amount": null,
  "contract": {
    "address": "0x...",
    "abi": [],
    "functionName": "approve",
    "blindpayContractAddress": "0x...",
    "amount": "100000000",
    "network": {
      "name": "sepolia",
      "chainId": 11155111
    }
  }
}
```

| Field | Type | Notes |
| --- | --- | --- |
| `id` | string | The quote ID (`qu_...`). References the same prefix as payin and transfer quotes. |
| `expires_at` | number | Epoch **milliseconds**. |
| `commercial_quotation` | number | The raw market exchange rate. |
| `blindpay_quotation` | number | The rate net of BlindPay's fee. |
| `sender_amount` | number | The stablecoin amount the funding source sends, in minor units. |
| `receiver_amount` | number | The fiat amount the bank account receives, in minor units. |
| `partner_fee_amount` | number | Nonzero only if `partner_fee_id` was passed. See [partner fees](/docs/learn/partner-fees). |
| `flat_fee` | number | The flat-fee component. |
| `billing_fee_amount` | number, nullable | Only nonzero on instances with billing charges enabled. |

**Abstracted:**

| `contract` | object, nullable | The on-chain ERC-20 `approve` payload for the chosen token and network. Only relevant when funding from a self-custodied wallet; see [Payout with EVM](/docs/payout-evm). |

Save the quote ID (`qu_...`). It expires in 5 minutes; if it expires before you execute the payout, create a new one.

**Advanced:**

| `contract` | object, nullable | Present for EVM networks. The on-chain `approve` payload; see below. |

`contract` fields:

| Field | Type | Notes |
| --- | --- | --- |
| `contract.address` | string | The ERC-20 token contract address for the chosen token and network. |
| `contract.abi` | array | The ERC-20 ABI, ready to pass to your Ethereum library. |
| `contract.functionName` | string | Always `approve`. |
| `contract.blindpayContractAddress` | string | The address to approve as spender: BlindPay's receiving address on that network. |
| `contract.amount` | string | The decimal-adjusted amount to approve, as a string. |
| `contract.network` | object | `{ name, chainId }` for the quoted network. |

Stellar and Solana don't use the allowance pattern, so `contract` is not meaningful there: Stellar payouts sign an XDR transaction directly, and Solana payouts sign a token delegation. See [Payout with Stellar](/docs/payout-stellar) and [Payout with Solana](/docs/payout-solana) for the full authorization flows.

Save the quote ID (`qu_...`). It expires in 5 minutes; if it expires before you execute the payout, create a new one.

## Related

**Abstracted:**

* [Payouts](/docs/payouts): execute the payout against this quote
* [Bank accounts](/docs/bank-accounts): add and manage recipient bank accounts
* [Partner fees](/docs/learn/partner-fees): pass a `partner_fee_id` to earn a cut of the payout
* [Cut-off times](/docs/kb/cut-off-times): settlement windows by payment rail

**Advanced:**

- [Payouts](/docs/payouts): the payout reference, status lifecycle, and links to every funding-path tutorial
- [Bank accounts](/docs/bank-accounts): add and manage recipient bank accounts
- [Supported chains](/docs/kb/supported-chains): the full chain and token matrix
- [Partner fees](/docs/learn/partner-fees): pass a `partner_fee_id` to earn a cut of the payout
