---
title: Payouts
description: Convert stablecoins to fiat by moving funds from a sender wallet to a customer's bank account across EVM, Stellar, and Solana.
---

## What it is

A payout moves funds from the sender's wallet to a customer's bank account. Stablecoins stored in a [BlindPay-managed wallet](/docs/essentials/wallets#send-fiat) can also be used as the source of funds.

A payout can only execute after a quote is created, and the quote expires 5 minutes after creation. Review how BlindPay manages stablecoins in the [flow of funds explanation](/docs/getting-started/overview#payout-flow-of-funds).

## How it works

BlindPay supports payouts on EVM chains, Stellar, and Solana. On `development` instances, the test token is always USDB — a BlindPay-powered ERC20 stablecoin used to simulate payouts. See [Supported Chains](/knowledge-base/guides/supported-chains) for the full chain and token matrix across all features.

Each network uses a distinct authorization mechanism before the payout executes:

| Network | Test network        | Authorization mechanism                          |
| ------- | ------------------- | ------------------------------------------------ |
| EVM     | Base Sepolia Testnet | ERC20 `approve` on the token contract           |
| Stellar | Stellar Testnet     | Authorize endpoint + signed XDR transaction      |
| Solana  | Solana Devnet       | Token delegation (prepare + signed transaction)  |

Payout lifecycle: create a quote, authorize the tokens for the chosen network, then create the payout before the quote expires.

### How to mint USDB

USDB is a fake ERC20 stablecoin powered by BlindPay to simulate payouts on `development` instances. You can mint infinite USDB on EVM chains, but the wallet needs Ether to pay gas — get some from the [Base Sepolia faucet](https://www.alchemy.com/faucets/base-sepolia){target="\_blank"}.

Put your `instance_id` on the following url [https://app.blindpay.com/instances/<instance_id>/utilities/mint](https://app.blindpay.com/instances/<instance_id>/utilities/mint){target="\_blank"} and mint USDB on `Base Sepolia Testnet`.

::c-alert{icon="circle-info"}
**Remember**: we're using `Base Sepolia Testnet` in all the examples below, so please double check you're doing everything on the correct network.
::

### Mint on Stellar

USDB can also be minted on `Stellar Testnet`.

::c-alert{icon="circle-info"}
**Stellar Testnet USDB issuer**: `GCQSSIMOW5OCGULZATDXKU5MOJBOMFX6G65X6CXZDQ7AIB3SKFUZ67NX`
::

**Step 1: Create Asset Trustline (Only required once)**

Before you can receive USDB tokens, you need to create a trustline to the USDB asset. This is a one-time setup that you only need to do once per wallet.

```bash
curl --request POST \
  --url https://api.blindpay.com/v1/instances/{instance_id}/create-asset-trustline \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "YOUR_ADDRESS"
  }'
```

This will return an unsigned XDR transaction:

```json
{
  "success": true,
  "xdr": "AAAAA..."
}
```

**Step 2: Sign and Submit the Trustline Transaction**

You have **two options** to complete the trustline setup. **Choose only one**:

**Option A: Sign and submit manually**

1. Sign the XDR using your Stellar wallet (or use [Stellar Lab](https://lab.stellar.org/transaction/sign){target="\_blank"})
2. Submit the signed transaction to the Stellar network yourself

**Option B: Let BlindPay submit it for you**

1. Sign the XDR using your Stellar wallet
2. Pass the `signedXdr` to the mint endpoint in the next step - BlindPay will submit the trustline transaction for you

**Step 3: Mint USDB Tokens**

After your trustline is established, you can mint USDB tokens:

Put your wallet `address`, the `amount`, and optionally the `signedXdr` (if you chose Option B above) on the following url [https://api.blindpay.com/v1/instances/{instance_id}/mint-usdb-stellar](https://api.blindpay.com/v1/instances/{instance_id}/mint-usdb-stellar){target="\_blank"}.

```bash
curl --request POST \
  --url https://api.blindpay.com/v1/instances/{instance_id}/mint-usdb-stellar \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "YOUR_WALLET_ADDRESS",
    "amount": "1000000000000000000",
    "signedXdr": "YOUR_SIGNED_XDR"
  }'
```

::c-alert{icon="circle-info"}
**Important**: Use the same wallet address that you used when creating your blockchain wallet in the [blockchain wallets section](/docs/essentials/blockchain-wallets#add-a-blockchain-wallet-secure). The trustline setup is only required once per wallet.
::

### Mint on Solana

USDB can also be minted on `Solana Devnet`. Put your wallet `address` and the `amount` on the following endpoint:

```bash
curl --request POST \
  --url https://api.blindpay.com/v1/instances/{instance_id}/mint-usdb-solana \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "address": "YOUR_WALLET_ADDRESS",
    "amount": "100"
  }'
```

This will return:

```json
{
  "success": true,
  "signature": "5xY..."
}
```

## Prerequisites

::c-prerequisites{:steps='["mint-usdb"]'}
::

## Create a payout

The EVM flow is the primary path. All stablecoins supported by BlindPay are ERC20 tokens, so you call the `approve` method on the token contract to allow BlindPay to move funds from a blockchain wallet.

::c-alert{icon="circle-info"}
If you're using Stellar or Solana, you'll use a different delegation process instead of ERC20 approvals. See the [Stellar](#creating-a-payout-on-stellar) and [Solana](#creating-a-payout-on-solana) sections below for blockchain-specific instructions.
::

### Approving tokens

Before approving the tokens, you need to have:

1. [A RPC provider URL from Base Sepolia Testnet](https://chainlist.org/?search=base&testnets=true){target="\_blank"}
2. [A blockchain wallet with enough funds to execute the transaction](https://www.alchemy.com/faucets/base-sepolia){target="\_blank"}
3. [The private key or any way to instantiate the blockchain wallet using ethers.js](https://docs.ethers.org/v6/api/wallet/#BaseWallet_new){target="\_blank"}
4. ERC20 token contract address (Provided by BlindPay on Quote API response)
5. ERC20 ABI (Provided by BlindPay on Quote API response)
6. BlindPay smart contract address (Provided by BlindPay on Quote API response)

This example uses an [express.js](https://expressjs.com/en/starter/hello-world.html){target="\_blank"} server and the [ethers.js](https://docs.ethers.org/v6/){target="\_blank"} library to simulate an approval. Ensure [Node.js](https://nodejs.org/en/download/){target="\_blank"} is installed.

Create a folder called `approve-erc20`. Inside the folder, run:

```bash
npm init
```

Install the dependencies:

```bash
npm install express ethers
```

Create a file called `index.js` inside it, paste the code below and replace the values with your own.

::c-code-group

```js [index.js]
import express from 'express'
import { ethers } from 'ethers'

const app = express()

app.get('/', async (req, res) => {
  // Before start
  const rpcProviderUrl = '<Replace this>' // You can get this from https://chainlist.org/?search=base&testnets=true
  const walletPrivateKey = '<Replace this>' // This wallet must have ethers (which you can get here: https://www.alchemy.com/faucets/base-sepolia) and USDB (which you can get here https://app.blindpay.com/instances/<instance_id>/utilities/mint) to execute the transaction on step 2
  const instanceId = '<Replace this>'
  const blindpayApiKey = '<Replace this>'
  const bankAccountId = '<Replace this>'

  // BlindPay Api Configs
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${blindpayApiKey}`,
  }

  // 1 Step: Create a quote
  const fiftyDollars = 5000
  const quoteBody = {
    bank_account_id: bankAccountId,
    currency_type: 'sender',
    cover_fees: false,
    request_amount: fiftyDollars,
    network: 'base_sepolia', // "sepolia", "base_sepolia", "arbitrum_sepolia", "polygon_amoy"
    token: 'USDB', // on development instance is always "USDB"
  }
  const createQuote = await fetch(
    `https://api.blindpay.com/v1/instances/${instanceId}/quotes`,
    { headers, method: 'POST', body: JSON.stringify(quoteBody) }
  )
  const quoteResponse = await createQuote.json()

  // 2 Step: Approve tokens
  const provider = new ethers.JsonRpcProvider(
    rpcProviderUrl,
    quoteResponse.contract.network
  )
  const yourWallet = new ethers.Wallet(walletPrivateKey, provider)
  const contract = new ethers.Contract(
    quoteResponse.contract.address,
    quoteResponse.contract.abi,
    provider
  )
  const contractSigner = contract.connect(yourWallet)

  const result = await contractSigner.approve(
    quoteResponse.contract.blindpayContractAddress,
    quoteResponse.contract.amount
  )

  res.send({
    hash: result?.hash,
    quoteId: quoteResponse.id,
  })
})

/* istanbul ignore next */
app.listen(3000)
console.log('Express started on port 3000')
```

::

Run the code:

```bash
node index.js
```

Access [http://localhost:3000](http://localhost:3000){target="\_blank"} and after a few seconds you should see a result like this in your browser:

```json
{
  "hash": "0x1ab66830a4804d80251f01b9d31c054a42068f5783c80d165507cddce0ac78ca",
  "quoteId": "qu_lxrCXUOOyrem"
}
```

### Creating a payout on EVM chains

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

Before creating a payout, complete the [prerequisites](#prerequisites), then [generate a quote](/docs/essentials/payout-quotes#create-a-payout-quote) and [approve the tokens](#approving-tokens).

::c-auth-note
::

::c-code-group

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/in_000000000000/payouts/evm \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "quote_id": "qu_000000000000",
  "sender_wallet_address": "<Replace this>"
}'
```

::

## Creating a payout on Stellar

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

::c-alert{icon="circle-info"}
**BlindPay Stellar mainnet wallet**: `GCOSSQDM2SWMHRP7CDBOLL2V45NHCRLUWUCEHPPBA2ABCOOLPOLZKIHE`. This is the treasury wallet that receives payout crypto and sends payin crypto on Stellar mainnet.
::

::c-auth-note
::

### Authorizing a token on Stellar

::c-code-group

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/{instance_id}/payouts/stellar/authorize \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "quote_id": "qu_000000000000",
  "sender_wallet_address": "<Replace this>"
}'
```

::

This endpoint will return a transaction hash that you can use to execute the payout.

```json
{
  "transaction_hash": "AAA...AAA"
}
```

With this hash we can create the transaction on Stellar.

First, install the dependencies:

```bash
npm install @stellar/stellar-sdk
```

Create a file called `index.js` inside it, paste the code below and replace the values with your own.

```javascript
import {
  AuthRequiredFlag,
  AuthRevocableFlag,
  BASE_FEE,
  Horizon,
  Keypair,
  Networks,
  Operation,
  TransactionBuilder,
  Asset,
} from '@stellar/stellar-sdk'

const stellar = new Stellar({
  server: 'https://horizon-testnet.stellar.org',
  network: 'testnet',
})

const stellarWallet = stellar.wallet(
  Keypair.fromSecret(process.env.STELLAR_SECRET_KEY)
)

// Create a transaction from the hash that we got from the authorize endpoint
const transaction = TransactionBuilder.fromXDR(
  transactionHash,
  Networks.TESTNET
)

// Sign the transaction
const signedTransaction = stellarWallet.sign(transaction)

// Submit the transaction
const result = await stellar.submitTransaction(signedTransaction)

console.log(result)

// You need to save the hash from the result (result.hash) to create the payout on BlindPay
```

::

Run the code:

```bash
node index.js
```

Create the payout on BlindPay using the hash that you got from the result.

::c-code-group

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/in_000000000000/payouts/stellar \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "quote_id": "qu_000000000000",
  "signed_transaction": "<Replace this>", // This is the signed transaction that we got from the authorize endpoint
  "sender_wallet_address": "<Replace this>" // This is the wallet address that we used to approve the tokens
}'
```

::

::c-alert{type="success" icon="circle-check"}
Congratulations! You've completed your first payout using BlindPay. If you want to execute more payouts you need to create a new quote and approve the tokens again.
::

## Creating a payout on Solana

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

::c-auth-note
::

Solana payouts require a token delegation before executing the payout. Sign and submit a delegation transaction before calling the payout API.

### Step 1: Prepare the Delegation Transaction

First, call the BlindPay API to prepare a delegation transaction:

```bash
curl --request POST \
  --url https://api.blindpay.com/v1/instances/{instance_id}/prepare-delegate-solana \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "owner_address": "YOUR_SOLANA_WALLET_ADDRESS",
    "token_address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "amount": "50000000"
  }'
```

This will return a serialized transaction that you need to sign:

```json
{
  "success": true,
  "transaction": "AQAAA..."
}
```

### Step 2: Sign and Submit the Delegation

Install the Solana dependencies:

```bash
npm install @solana/web3.js bs58
```

Create a file called `solana-delegate.js`:

```javascript
import { Connection, VersionedTransaction } from '@solana/web3.js'
import { Buffer } from 'node:buffer'

// Configuration
const RPC_URL = 'https://api.devnet.solana.com' // Use mainnet for production
const connection = new Connection(RPC_URL, 'confirmed')

// Serialized transaction from Step 1
const serializedTransaction = 'AQAAA...' // From step 1

// Your wallet provider (Phantom, Solflare, etc.) - this example uses browser wallet
async function signAndSubmitDelegation() {
  // Deserialize the transaction
  const transactionBuffer = Buffer.from(serializedTransaction, 'base64')
  const transaction = VersionedTransaction.deserialize(transactionBuffer)

  // Sign using browser wallet (e.g., window.solana for Phantom)
  const signedTransaction = await window.solana.signTransaction(transaction)

  // Send the transaction
  const signature = await connection.sendTransaction(signedTransaction)

  // Wait for confirmation
  await connection.confirmTransaction(signature, 'confirmed')

  console.log('Delegation signature:', signature)
  return signature
}

signAndSubmitDelegation()
```

Run the delegation:

```bash
node solana-delegate.js
```

### Step 3: Create the Payout on BlindPay

After the delegation is confirmed, you can create the payout using the `/payouts/evm` endpoint (same as EVM and Stellar):

::c-code-group

```bash [cURL]
curl --request POST \
  --url https://api.blindpay.com/v1/instances/in_000000000000/payouts/evm \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
  "quote_id": "qu_000000000000",
  "sender_wallet_address": "YOUR_SOLANA_WALLET_ADDRESS"
}'
```

::

::c-alert{type="success" icon="circle-check"}
Congratulations! You've completed your first Solana payout using BlindPay. The `/payouts/evm` endpoint supports EVM chains, Stellar, and Solana networks.
::

::c-alert{icon="circle-info"}
**Note**: For each Solana payout, you need to complete the delegation process (Steps 1-2) before creating the payout. The delegation authorizes BlindPay to pull the specified amount of tokens from your wallet.
::

### Testing scenarios

By default all payouts are automatically completed in `development` instances. Force `refund` and `failed` scenarios by setting specific values for the payout amount.

| Amount | Result Status |
| ------ | ------------- |
| 666.00 | Failed        |
| 777.00 | Refunded      |

## Related

- [Payout Quotes](/docs/essentials/payout-quotes) · [Bank Accounts](/docs/essentials/bank-accounts) · [Blockchain Wallets](/docs/essentials/blockchain-wallets)
- [Wallets](/docs/essentials/wallets) · [Supported Chains](/knowledge-base/guides/supported-chains)
