---
title: "How to execute a payout quote on EVM, Solana, and Stellar: approve, delegate, or sign"
seoTitle: "Execute a payout quote on EVM, Solana, and Stellar"
description: "Funding a payout from your own wallet needs one on-chain authorization. What EVM approve, Solana delegation, and Stellar signing look like, step by step."
date: "2026-10-10"
updated: "2026-10-10"
category: "payments"
author: "BlindPay Team"
howto:
  name: "How to execute a payout quote from an external wallet"
  steps:
    - name: "Create the payout quote"
      text: "Call POST /v1/instances/{instance_id}/quotes with the bank_account_id, currency_type, cover_fees, request_amount in minor units, and the network and token your wallet sends from. Save the qu_ id and read expires_at, which is in epoch milliseconds."
    - name: "Authorize the exact amount for your chain"
      text: "On EVM, call approve on the token contract using the contract payload in the quote. On Solana, call prepare-delegate-solana, then sign and submit the delegation. On Stellar, call payouts/stellar/authorize, then sign and submit the returned transaction."
    - name: "Wait for the authorization to confirm"
      text: "Wait until the approve, delegation, or Stellar payment confirms on-chain. All of this has to fit inside the quote's 5-minute window, so request the quote only when the wallet is ready to sign."
    - name: "Create the payout"
      text: "For EVM and Solana, call POST /v1/instances/{instance_id}/payouts/evm with quote_id and sender_wallet_address. For Stellar, call POST /v1/instances/{instance_id}/payouts/stellar with quote_id, signed_transaction, and sender_wallet_address."
faq:
  - q: "Why does a stablecoin payout need an approve transaction first?"
    a: "Because the funds sit in a wallet you control, and BlindPay can only move what you authorize. On EVM chains, approve lets BlindPay's address pull the exact quoted amount of the ERC-20 token. BlindPay then executes that single transaction. Payouts from a BlindPay managed wallet skip this step entirely."
  - q: "What is the difference between approve, delegate, and sign?"
    a: "They are three chain-native ways to authorize one payment. EVM uses an ERC-20 allowance through approve. Solana uses a token delegation that lets BlindPay transfer up to the delegated amount. Stellar has no allowance mechanism, so you sign a real payment transaction to BlindPay's treasury address and pass it to the payout call."
  - q: "Can I reuse an approval or delegation for the next payout?"
    a: "No. BlindPay's docs treat the quote and the approval as single-use on EVM, a Solana delegation only authorizes the amount tied to that specific quote, and a Stellar signed transaction is single-use too. Create a new quote and authorize again for every payout, even to the same recipient."
  - q: "What happens if the quote expires while I wait for the approval to confirm?"
    a: "The payout can't execute against an expired quote. Create a new quote and authorize the new amount, since the old authorization was sized for the old quote. To avoid this, request the quote only when the wallet is ready to sign, and keep the sign-and-confirm step well inside the 5-minute window."
  - q: "Which endpoint do Solana payouts use?"
    a: "Solana payouts are created at /payouts/evm, the same endpoint as EVM, with the quote_id and the Solana sender_wallet_address. The path name is historical. Stellar is the exception, with its own /payouts/stellar/authorize and /payouts/stellar endpoints because the signed transaction travels with the request."
---

To execute a payout quote from your own wallet, authorize the exact quoted amount on-chain, then create the payout before the quote expires. On EVM chains you call `approve` on the token contract, on Solana you sign a token delegation, and on Stellar you sign a payment transaction. A BlindPay managed wallet skips the authorization.

Same quote, three chain-native ways to say yes. This guide puts them side by side, with the endpoints, the fields, and the timing traps inside a 5-minute quote window.

**Key takeaways**

- Every payout quote expires 5 minutes after creation. The authorization has to confirm inside that window.
- EVM: call `approve` with the `contract` payload from the quote, then `POST /payouts/evm`.
- Solana: `POST /prepare-delegate-solana`, sign and submit, then `POST /payouts/evm`.
- Stellar: `POST /payouts/stellar/authorize`, sign and submit, then `POST /payouts/stellar` with the signed transaction.
- Quotes and authorizations are single-use. Authorize again for every payout.

## Why does a payout from your own wallet need an authorization?

Because BlindPay never holds keys to your wallet. For payout flows from customer-controlled wallets, BlindPay operates as a non-custodial payment processor: you authorize the exact amount and BlindPay executes that single transaction. If a payout can't be delivered after the stablecoins are collected, BlindPay refunds them to the quote's refund wallet, or to the sending wallet when none is set. On Pix and other non-USD local rails that refund is automatic, while USD payouts and payouts whose review times out are refunded after an operator review.

The authorization is how you grant "this amount, this once." Each chain has its own primitive for it. [What happens on-chain in a stablecoin payment](/resources/more/what-happens-on-chain-in-a-stablecoin-payment) shows where that step sits in the full flow.

If the funds sit in a BlindPay managed wallet instead, there's nothing to sign. You create the quote and call `POST /payouts/evm` with the managed wallet's address, for every supported chain, Solana included ([payout with managed wallet](/docs/payout-managed-wallet)). Managed wallets are in beta and custodial.

## How do the three chains compare?

| Step | EVM (Ethereum, Base, Polygon, Arbitrum) | Solana | Stellar |
| --- | --- | --- | --- |
| Primitive | ERC-20 allowance (`approve`) | Token delegation | Signed payment transaction (XDR) |
| What BlindPay returns | `contract` object inside the quote | Serialized transaction from `prepare-delegate-solana` | Unsigned transaction from `payouts/stellar/authorize` |
| Who submits on-chain | You | You | You |
| Payout endpoint | `POST /payouts/evm` | `POST /payouts/evm` | `POST /payouts/stellar` |
| Extra field on the payout call | None | None | `signed_transaction` |
| Reusable? | No, single-use | No, one delegation per quote | No, single-use |

The quote request is the same everywhere: `bank_account_id`, `currency_type`, `cover_fees`, `request_amount` in minor units, plus the `network` and `token` you send from ([payout quotes](/docs/payout-quotes)). The chain only changes what happens between the quote and the payout. If you're still choosing the chain, [which network to off-ramp from](/resources/more/best-network-to-off-ramp-stablecoins) compares finality and fees.

## How do you execute a quote on an EVM chain?

Approve, wait, pay. The quote response for an EVM network carries a `contract` object with everything the approval needs ([payout with EVM](/docs/payout-evm)):

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

With ethers.js, the call looks like this:

```js
const contract = new ethers.Contract(quote.contract.address, quote.contract.abi, wallet)
await contract.approve(quote.contract.blindpayContractAddress, quote.contract.amount)
```

The ERC-20 standard defines `approve` as allowing a spender to withdraw from your account up to the approved value ([EIP-20](https://eips.ethereum.org/EIPS/eip-20)). Once the approval confirms, create the payout with `quote_id` and `sender_wallet_address`. You pay gas on the approval, which [who pays gas fees](/resources/more/who-pays-gas-fees-stablecoin-payments) covers in detail.

## How do you execute a quote on Solana?

Delegate, sign, pay. Solana payouts need a token delegation before the payout executes ([payout with Solana](/docs/payout-solana)):

1. `POST /v1/instances/{instance_id}/prepare-delegate-solana` with `owner_address`, `token_address`, and `amount`. It returns `{ "success": true, "transaction": "..." }`, a base64 serialized transaction.
2. Deserialize it as a `VersionedTransaction`, sign it with the sender's wallet (a browser wallet or a server-side keypair), send it, and wait for confirmation.
3. `POST /v1/instances/{instance_id}/payouts/evm` with `quote_id` and the Solana `sender_wallet_address`. Yes, the EVM path. The name is historical.

Solana's token program says account owners can delegate authority over some or all of their balance with the `Approve` instruction, and delegates may transfer or burn up to the amount delegated ([Solana Program Library](https://www.solana-program.com/docs/token)). Each BlindPay delegation covers only the amount tied to that quote, so repeat all three steps for every payout.

## How do you execute a quote on Stellar?

Authorize, sign, pay with the signature. Stellar has no allowance mechanism, so you sign a real payment to BlindPay's treasury address ([payout with Stellar](/docs/payout-stellar)):

1. `POST /v1/instances/{instance_id}/payouts/stellar/authorize` with `quote_id` and `sender_wallet_address`. It returns an unsigned transaction in `transaction_hash`. This call does not consume the quote or create any record.
2. Rebuild it with `TransactionBuilder.fromXDR`, sign with the sender's key, and submit it to the network.
3. `POST /v1/instances/{instance_id}/payouts/stellar` with `quote_id`, `signed_transaction`, and `sender_wallet_address`. BlindPay re-validates the signed transaction against the quote, destination and amount, before dispatching the payout.

Stellar encodes transactions in XDR, a compact binary format that SDKs convert to and from base64 ([Stellar docs](https://developers.stellar.org/docs/learn/fundamentals/data-format/xdr)). BlindPay's Stellar mainnet treasury address is `GCOSSQDM2SWMHRP7CDBOLL2V45NHCRLUWUCEHPPBA2ABCOOLPOLZKIHE`, useful when you reconcile on an explorer.

## Illustrative example: does the authorization fit in a 5-minute quote?

A treasury script pays 1,250.00 USDC from an external wallet. `request_amount` is `125000` in minor units. The approval amount is decimal-adjusted on-chain: BlindPay's own Solana example delegates `"50000000"` for a 50-dollar quote, which is 50 x 1,000,000, so a token with six decimals needs 1,250 x 1,000,000 = 1,250,000,000 base units here. Read `contract.amount` from the quote instead of computing it.

Now the clock. The step timings below are illustrative.

| Step | Illustrative time | Clock used |
| --- | --- | --- |
| Create quote | 1 s | 1 s |
| Build and sign the authorization | 3 s | 4 s |
| Wait for on-chain confirmation | 30 s | 34 s |
| Create the payout | 1 s | 35 s |
| Quote window | 300 s | 265 s to spare |

Plenty of room when it's a script. The real risk is a human: a wallet pop-up left open while someone gets coffee. If 300 seconds pass before the payout call, the quote is dead and the old authorization was sized for it. Re-quote and authorize again. [Handling expired quotes in TypeScript and Python](/resources/more/handle-expired-quotes-typescript-python) has the retry loop, and [stablecoin API idempotency keys](/resources/more/stablecoin-api-idempotency-keys) covers safe retries on the payout call. For reading the quote's two rates, see [how to read an FX quote](/resources/more/how-to-read-an-fx-quote).

## What to do next

Pick the chain your treasury already uses, open the matching tutorial in the BlindPay docs, and run one 50-dollar payout end to end on a development instance with USDB. Start with [payout with EVM](/docs/payout-evm) if you're unsure.
