Table of Contents
Marketplace, payroll, and remittance teams often settle in stablecoins under the hood while the recipient only sees a bank credit. The named object here is a BlindPay stablecoin payout: stablecoins leave a funding wallet, BlindPay converts against a locked quote, and fiat lands in a recipient bank account across ACH, wire, RTP, SWIFT, Pix, SPEI, SEPA, and related rails.
BlindPay's own docs split the same flow across Payouts, Payout quotes, managed wallet, EVM, Stellar, and Solana tutorials. This Stablecoin Insider operator guide stitches those pages into one path: bank account, quote, authorize (or skip if managed), execute before the 5-minute expiry, then reconcile on webhooks.
Facts below come from BlindPay's live payout docs linked above, plus Bank accounts, Managed wallets, Webhooks, Webhooks events, Supported chains, and the Stablecoins to bank transfer quickstart. Field names, rails, minima, quote expiry, test sentinels, and status values are taken from those pages. No invented fees, country lists, or settlement SLAs beyond what those docs state.
Key Takeaways
- Every BlindPay stablecoin payout follows bank account, then payout quote (locks rate and fees for 5 minutes), then execute against that single-use quote.
- request_amount is an integer in minor units (10000 equals one hundred dollars); floats are rejected.
- Funding path picks the authorize step: managed wallet needs none; EVM needs ERC-20 approve; Stellar needs authorize then sign XDR; Solana needs token delegation.
- Development instances use testnets and USDB; production uses mainnet USDC or USDT per BlindPay's network and token matrix.
- Track payout.new, payout.update, and payout.complete webhooks; failed or stuck reviews do not auto-refund.
Who this is for
Use this path if the team is a marketplace, neobank, payroll, remittance, or PSP integrator that already (or plans to) settle vendor or end-user payouts in stablecoins and needs BlindPay to deliver fiat to bank accounts on rails documented in the Payouts overview.
Skip it if the job is wallet-to-wallet stablecoin delivery inside Modern Treasury Payment Orders (see the Modern Treasury stablecoin payout guide), or if Circle or zerohash owns the payout control plane. Skip issuer primary mint and redeem flows such as Circle Mint when the recipient still needs a bank credit, not a mint.
What a BlindPay stablecoin payout is
Per BlindPay's Payouts docs, every payout follows the same three-step pattern: add a bank account for the recipient (once per recipient), create a payout quote that locks the exchange rate and fees for 5 minutes, then execute the payout so stablecoins leave the funding source and fiat lands in the bank account.
The funding source is either a BlindPay-managed wallet (custodied balance, no client-side signing) or an external wallet the customer controls. External wallets require an on-chain authorization step first: ERC-20 approve on EVM, authorize-and-sign on Stellar, or token delegation on Solana, as summarized in the same payouts overview and the per-path tutorials.
Here's why that matters for operators: the create-payout HTTP call looks similar across funding sources. The failure mode that burns engineering time is authorizing after the quote expires, or reusing a quote_id that already backed a payout.
Supported payout rails and minima
The Payouts page lists supported payout type values and countries:
| type | Country / zone |
|---|---|
| international_swift | Global |
| ach | United States |
| wire | United States |
| rtp | United States |
| pix | Brazil |
| spei_bitso | Mexico |
| ach_cop_bitso | Colombia |
| transfers_bitso | Argentina |
| sepa | Europe (SEPA zone) |
BlindPay also documents third-party bank accounts: a customer named John can receive a payout into a bank account belonging to Jack, per the same overview. Documented minima include international_swift at 100 USD requested amount (error swift_minimum_is_100_usd) and sepa at 11 USDC when quoting by sender amount or 10 EUR when quoting by receiver amount (sepa_minimum_is_11_usdc, sepa_minimum_is_10_eur). Other rails have no minimum beyond the fee itself, according to that page.
Networks, tokens, and USDB on development
The Payout quotes docs and the payouts overview state that development instances use test networks (base_sepolia, stellar_testnet, solana_devnet, plus other listed sepolia/amoy variants) and the USDB test token. Production instances use matching mainnets and USDC or USDT. The quote page's network/token table also lists tron as a production-only beta network with no development testnet.
Stablecoin Insider's take: treat USDB on a development instance as the only safe rehearsal token. Do not hardcode USDC into sandbox scripts and expect BlindPay to accept it on development; the docs say development uses USDB only.
Prerequisites checklist
- BlindPay instance API key (Bearer auth) for a development or production instance.
- Customer with kyc_status: "approved".
- Approved bank account (ba_...) as the payout destination.
- Funding source with enough balance: managed wallet (bl_...) or external wallet on the quoted network.
- Webhook endpoint configured for the instance (see BlindPay Webhooks docs).
On a development instance, the managed wallet payout tutorial says you can fund the wallet with a payin that auto-completes about 30 seconds after creation and delivers USDB into the wallet.
Step 1: Add the recipient bank account
Create (or reuse) a bank account for the recipient through BlindPay's Bank accounts flow before quoting. The payouts overview treats bank account creation as a once-per-recipient step. Persist the returned ba_... id; every quote and payout references it (or a payable_id when paying a registered bill instead of a bank account).
Stablecoin Insider's take: gate product UX on bank account status: "approved". Quoting against a pending account creates false "amount bug" support tickets that are really lifecycle bugs.
Step 2: Create a payout quote (5-minute lock)
POST to the instance quotes endpoint as shown in Payout quotes and the managed-wallet tutorial. A quote locks conversion rate and fees for 5 minutes and returns a qu_... id plus fee breakdown fields such as sender_amount, receiver_amount, flat_fee, and (for EVM) a contract approve payload.
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": 5000,
"network": "solana_devnet",
"token": "USDB"
}'
Per the Payout quotes docs, request_amount is an integer in minor units and does not accept floats: to send $100.00 (or 100 USDC on production), pass 10000. currency_type of sender means the amount is denominated in the stablecoin the funding source sends; receiver means the fiat the bank account receives. cover_fees: false deducts fees from the fiat the recipient receives; true adds fees on top so the recipient gets the full quoted amount (common for payroll), as documented on both the quotes and payouts pages.
Save expires_at (epoch milliseconds) and treat anything past that timestamp as dead. If the quote expires before execute, create a new quote. BlindPay states that a quote_id can only back one payout; a second call with the same quote returns an error.
Step 3a: Managed wallet path (no signing)
This is the simplest funding path in Payout with managed wallet: BlindPay already custodies the balance, so there is no approve call, no signed transaction, and no delegation. Pass the managed wallet's address as sender_wallet_address and call the payout endpoint.
curl --request POST \
--url https://api.blindpay.com/v1/instances/in_000000000000/payouts/evm \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"quote_id": "qu_000000000000",
"sender_wallet_address": "YOUR_MANAGED_WALLET_ADDRESS"
}'
The managed-wallet tutorial notes that the endpoint is /payouts/evm regardless of the managed wallet's network, including Solana. The response returns the payout with status: "processing". On a development instance it completes automatically a few seconds later and fires a payout.complete webhook, per that page.
Note from the Stellar tutorial's related links: Stellar is not yet supported for managed wallets in that doc's related section. Prefer EVM or Solana managed wallets, or use the external Stellar path below, until BlindPay updates that support matrix.
Step 3b: External EVM path (approve then payout)
For Ethereum, Base, Polygon, or Arbitrum external wallets, Payout with EVM says authorization means calling approve on the ERC-20 token contract so BlindPay can pull the quoted amount. The quote response's contract object supplies address, ABI, BlindPay spender address, decimal-adjusted amount, and network chainId.
Operator spine from that tutorial: create the quote, submit the approve transaction with ethers.js (or equivalent) using contract.blindpayContractAddress and contract.amount, wait for confirmation, then POST /payouts/evm with the same quote_id and the sender wallet address. Development examples use base_sepolia and USDB; production swaps in mainnet and USDC or USDT.
Stablecoin Insider's take: never approve a stale quote. If expires_at is close, create a fresh quote and approve the new contract.amount rather than racing the clock with an old allowance.
Step 3c: External Stellar path (authorize, sign, create)
Stellar has no allowance mechanism. Per Payout with Stellar, the client calls /payouts/stellar/authorize with quote_id and sender wallet address to receive an unsigned transaction (XDR / transaction_hash), signs it with the Stellar SDK against testnet or mainnet, submits to Horizon, then creates the payout at /payouts/stellar with quote_id, signed_transaction, and sender_wallet_address.
BlindPay independently re-validates the signed transaction against the quote (destination and amount) before dispatching. The Stellar tutorial documents BlindPay's Stellar mainnet treasury address as GCOSSQDM2SWMHRP7CDBOLL2V45NHCRLUWUCEHPPBA2ABCOOLPOLZKIHE for operators who need to recognize the counterparty on explorers. Development uses stellar_testnet and USDB; production uses Stellar mainnet and USDC as stated there.
Step 3d: External Solana path (delegate then payout)
Payout with Solana requires a token delegation before execute: POST /prepare-delegate-solana with owner address, token address, and amount; sign and submit the returned serialized transaction; then create the payout at /payouts/evm with quote_id and the Solana wallet address (same create endpoint naming as EVM for this path). Repeat the delegation for every Solana payout; each delegation only authorizes the amount tied to that specific quote.
Development examples use solana_devnet and USDB. Production uses Solana mainnet and USDC or USDT per the tutorial.
Step 4: Status lifecycle and cover_fees
From the Payouts reference, top-level statuses include:
- processing: default on creation; stablecoins are being pulled and fiat is in flight.
- on_hold: held for review. All SWIFT payouts start here. ACH, wire, and RTP also pass through on_hold as a standard compliance step after crypto is collected.
- completed: fiat landed in the recipient bank account (terminal).
- failed: payout did not complete (terminal).
- refunded: stablecoins returned to the funding source instead of converting to fiat (terminal).
Tracking sub-objects (tracking_complete, tracking_payment, tracking_transaction, tracking_partner_fee, tracking_liquidity) expose steps such as processing, on_hold, pending_review, or completed. SWIFT compliance documents are collected after payout creation when the recipient relationship is not first_party; first-party SWIFT to your own account never requires documents, per the quotes docs.
cover_fees is locked on the quote before authorization. Changing fee payer after approve means creating a new quote and re-authorizing.
Step 5: Webhooks and testing sentinels
Configure a webhook endpoint once per instance using BlindPay's Webhooks setup and signature verification. The payouts page lists payout events:
- payout.new: payout created.
- payout.update: status change (for example processing to on_hold).
- payout.complete: reached completed, failed, or refunded.
- payout.partnerFee: partner fee owed when a partner_fee_id was on the quote.
Development instances complete payouts automatically. Force outcomes with quote request_amount sentinels documented on BlindPay's Payouts testing section: 66600 ($666.00) yields failed; 77700 ($777.00) yields refunded (EVM also fires a real on-chain refund); any other amount yields completed. Use those only in development, never as production amounts.
Stablecoin Insider's take: subscribe to payout.update and payout.complete before the first production send. Polling status alone misses the on_hold to completed transition during SWIFT document review.
Worked example: $50 USDB managed-wallet payout on solana_devnet
Suppose a marketplace stages a BlindPay stablecoin payout on a development instance to a previously approved US bank account.
- Confirm customer kyc_status approved and bank account ba_... approved.
- Confirm managed wallet bl_... holds enough USDB (fund via auto-completing payin if needed).
- POST quotes with bank_account_id, currency_type sender, cover_fees false, request_amount 5000 ($50.00), network solana_devnet, token USDB (minor units per BlindPay payout quotes).
- Within 5 minutes, POST /payouts/evm with quote_id and the managed wallet address (no approve).
- Persist payout id po_... and wait for payout.complete with status completed (automatic on development for non-sentinel amounts).
- In production, swap network/token to a supported mainnet pair (for example solana + USDC) and keep the same quote-then-execute spine.
That amount encoding (5000 for $50.00) follows BlindPay's minor-units rule in the quotes docs. Do not pass 50.00 as a float.
Funding path comparison
| Funding source | Authorization | Create endpoint |
|---|---|---|
| Managed wallet (bl_...) | None | /payouts/evm |
| External EVM | ERC-20 approve | /payouts/evm |
| External Stellar | Authorize + sign XDR | /payouts/stellar |
| External Solana | Token delegation | /payouts/evm |
That matrix is the spine of BlindPay's payouts overview. Pick the funding path before writing product copy; the UX for "sign this transaction" differs completely between managed and external wallets.
BlindPay vs Modern Treasury vs Circle: pick a lane
| Question | BlindPay | Modern Treasury | Circle payout |
|---|---|---|---|
| Primary job in this post | Stablecoin to bank fiat offramp | type:stablecoin wallet credit | Circle-native payout APIs |
| Quote lock | 5-minute payout quote | Payment Order amount | Circle payout product rules |
| SCI operator guide | This post | Modern Treasury how-to | Circle payout how-to |
On the flip side, do not assume every BlindPay instance automatically has every rail or chain enabled. Confirm instance type, supported networks, and bank rails with BlindPay before promising Pix, SEPA, or Tron beta in production UX. See also the Supported chains knowledge base page for the full matrix.
Who it is not for
Skip this stack when:
- The team lacks a BlindPay instance or approved KYC customers.
- The job is on-chain wallet delivery without a bank offramp (use Modern Treasury, Circle, or zerohash payout shapes instead).
- Compliance cannot complete KYC/KYB and SWIFT document flows for third-party recipients.
- Product needs quote windows longer than BlindPay's documented 5-minute expiry without a re-quote UX.
- Managed-wallet Stellar funding is required today; BlindPay's Stellar tutorial still points operators to the external-wallet path for that chain.
Building BlindPay stablecoin payouts? Map one development customer, one approved bank account, one funded managed wallet with USDB, and one payout.complete listener before any production float.
Need the Modern Treasury parallel for wallet credits? Use that how-to next.
How to Send a zerohash Stablecoin Payout: Sibling guide when zerohash owns the payout API.
How to Send a Circle Stablecoin Payout: Sibling guide when Circle is the payout provider.
FAQ
What is a BlindPay stablecoin payout?
A quote-locked transfer that pulls stablecoins from a managed or external funding wallet and delivers fiat to a recipient bank account on BlindPay's documented rails (ACH, wire, RTP, SWIFT, Pix, SPEI, SEPA, and related types).
How long does a payout quote last?
5 minutes from creation, per BlindPay's payout quotes and payouts docs. Create a new quote if it expires or if it already backed a payout.
How are amounts encoded?
As integers in minor units. BlindPay's payout quotes docs state that 10000 equals $100.00 (or 100 USDC on production) and that floats are not accepted.
What token do development instances use?
USDB on documented testnets such as base_sepolia, stellar_testnet, and solana_devnet. Production uses USDC or USDT on matching mainnets.
Do managed wallets need on-chain approve?
No. BlindPay's managed-wallet payout tutorial says there is no approve, signed transaction, or delegation; two REST calls (quote + execute) move the funds.
Which create endpoint does Stellar use?
/payouts/stellar, with a signed_transaction field. EVM, Solana external, and managed-wallet payouts use /payouts/evm per BlindPay's tutorials.
What webhook marks a terminal outcome?
payout.complete fires when status reaches completed, failed, or refunded. Also listen for payout.new and payout.update for earlier lifecycle steps.
How do you force failed or refunded in development?
Set the quote request_amount to 66600 for failed or 77700 for refunded, as documented on BlindPay's payouts testing section. Other amounts complete automatically on development instances.
This content is provided for informational and educational purposes only and does not constitute financial, investment, legal, or tax advice; no material herein should be interpreted as a recommendation, endorsement, or solicitation to buy or sell any financial instrument, and readers should conduct their own independent research or consult a qualified professional.