Stablecoin virtual accounts explained: from bank transfer to wallet balance

A stablecoin virtual account is a bank account in your customer's name whose deposits convert to USDC or USDT. How approval, deposits, and fees work.

A stablecoin virtual account is a real bank account issued in your customer's name, with its own routing and account number, that converts every incoming deposit into USDC or USDT and sends it to a linked wallet. The payer sends a normal ACH, wire, or SWIFT transfer. Your customer ends up with a stablecoin balance. Nobody builds a checkout.

The account number is the integration. That's the whole idea.

What is a stablecoin virtual account, and what isn't it?

Three things get confused here, and they solve different problems.

Virtual accountOne-time payment instructionBlockchain wallet
What it receivesFiat over bank railsFiat over bank railsStablecoins on-chain
Reusable?Yes, same details every timeNo, one instruction per paymentYes
Whose name is on itYour customer'sUsually the provider's pooled accountNobody's (it's an address)
How a deposit is matchedBy the account number itselfBy a reference or memo code the payer must typeBy the address
What goes wrongApproval takes timePayer forgets the memo, deposit sits unmatchedWrong network, wrong token

A virtual account is not a customer-controlled bank account either. Your customer can't write checks from it or log into a bank portal. It exists to receive money and turn it into stablecoin.

In BlindPay's API the difference is visible on the payin itself. Without a virtual account, an ACH or wire payin returns a memo_code and BlindPay's shared bank details. With an approved virtual account, the payer sees the customer's own dedicated account details and the memo code is ignored (payins).

What details does the payer use?

The same ones they'd use for any US bank account: routing number, account number, and for international senders, SWIFT details and the receiving bank's name and address. BlindPay returns ACH and wire numbers once the account is approved, plus SWIFT and receiving-bank details. Before approval, the rail numbers are empty.

So the payer doesn't need to know anything about stablecoins. They're paying a bank account. A foreign client paying a Brazilian freelancer sends a SWIFT wire to a US account number. The freelancer ends up holding USDC.

One detail matters for B2B: when a virtual account is issued to an end user, payouts from it go out under that end user's name, not a pooled account name. The recipient sees who actually paid them.

What happens from account request to wallet balance?

Walk through one account. Steps marked BlindPay follow our documented API; the rest is the generic pattern most providers share.

  1. Verify the customer. KYC for individuals, KYB for businesses. BlindPay: kyc_status must be approved before you can request an account.
  2. Fill in the compliance profile. Banks review the account holder, not just the identity. BlindPay: businesses need account_purpose, business_type, business_description, a NAICS business_industry code, estimated_annual_revenue, source_of_wealth, publicly_traded, and at least one owner with ownership_percentage and title. Leave a field blank and the request fails with missing_required_fields naming it.
  3. Link a wallet. Every deposit settles somewhere. BlindPay: the account points to one blockchain_wallet_id belonging to the same customer, and you pick the token, USDC or USDT.
  4. Request the account. BlindPay: one POST to /customers/{customer_id}/virtual-accounts with a banking_partner, token, and wallet (create a virtual account).
  5. Wait for review. BlindPay: the account starts in pending_review (compliance), moves to verifying (bank), and ends approved or rejected. The virtualAccount.complete webhook fires on approval, with the rail numbers in the payload.
  6. Share the details. Put the account number in your UI, on invoices, wherever payers look.
  7. A deposit arrives. BlindPay: each deposit creates a payin and fires payin.new. When it's converted and the stablecoin lands, payin.complete fires.

What should the product show at each state?

Verify the exact status names against your provider's docs before you build this. These are BlindPay's.

StateWhat the user should see
Account pending_review"Your account is being reviewed." No account number yet.
Account verifying"Almost ready, the bank is confirming your account." Still no number.
Account approvedThe routing and account number, with copy buttons.
Account rejectedA clear message and the next step, not a spinner that never ends.
Deposit payin processing"Deposit on the way." Show amount and payment method.
Deposit payin on_hold"Under review." Don't imply the money is lost.
Deposit payin completedStablecoin balance updated, with the amount actually delivered.
Deposit payin failed or refundedThe deposit didn't go through or went back to the sender. Explain which.

Show the delivered amount, not the deposited amount. Fees come off in between.

How do fees and micro-deposits work?

BlindPay charges $1.50 per month per account. Each deposit is its own payin, and where the fee lands depends on size:

DepositWhere the BlindPay fee landsField on the payin
Below $100.00Accrued to your invoice at the end of the billing cyclebilling_fee_amount
$100.00 or moreDeducted from the delivered stablecoin at transaction timetransaction_fee_amount

Every deposit is processed, including the $0.01 micro-deposits some platforms send to verify an account, and always delivers at least $0.01 of stablecoin. That's worth knowing when a customer connects the account to a payroll provider or marketplace that tests with pennies. Those tests will show up as payins. Reconcile them, don't flag them as fraud. Full details in virtual accounts.

How should you handle rejection, delays, and exceptions?

Plan for these before launch, not after the first support ticket.

  • Rejected account request. Either review stage can reject. At BlindPay, a customer can't hold two non-deleted, non-rejected accounts on the same banking partner (the jpmorgan partner is the exception, since each account is a separate sub-account). After a rejection, fix the underlying issue and request again.
  • Slow approval. Bank review varies by partner and account type. If the bank asks for more documents, the SLA clock restarts when you submit them. Source of funds and source of wealth documents are the usual ask; the list is in the virtual account requirements.
  • Delayed funds. ACH and wire deposits can take up to 5 business days to arrive. Cut-offs push late transfers to the next business day.
  • Deposits under review. A deposit can land on_hold for compliance review. It resumes when cleared.
  • Eligibility. Some banking partners serve only US customers, others only non-US businesses. Check which partner fits your customer base before you design onboarding around one account type.

What should you check before choosing a provider?

Five questions that separate a real virtual account from a marketing page:

  1. Whose name is on the account? Named accounts in your customer's name beat pooled accounts with memo codes.
  2. Which rails does it receive? ACH only, or wire and SWIFT too? Foreign senders need SWIFT.
  3. How long is approval, in writing? Get the SLA per account type and ask what restarts the clock.
  4. What does the stablecoin leg look like? Which tokens, which chains, and can you change the destination wallet later? At BlindPay you can update token and blockchain_wallet_id on an existing account.
  5. How are fees itemized per deposit? You want the fee as a field on every deposit, not a surprise on the invoice.

Not every provider supports the same rails or issues accounts at the same speed. Ask for the account types table, not the headline.

If you're deciding whether to run this yourself, build vs buy covers the bank relationships a virtual account quietly depends on. For the flow a virtual account feeds into, see how a stablecoin payment moves. Merchants collecting from customers can compare this with the options in how merchants accept stablecoin payments.

Where does BlindPay fit?

BlindPay virtual accounts give each customer a US bank account in their own name that receives ACH, wire, and SWIFT and settles to USDC or USDT in a linked wallet. The same API pays out over Pix, SPEI, ACH, RTP, SEPA, and SWIFT (POBO/COBO) to 100+ countries with no pre-funding, and runs KYC, KYB, and sanctions screening inside the flow.

What to do next

Create a virtual account on a free development instance today. It's approved instantly, with routing number 110000000, so you can wire up virtualAccount.complete and payin.complete handling in an afternoon. Start with create a virtual account, then check the account requirements so production review doesn't bounce your first real customer.

This article is for general information only and is not legal, tax, or financial advice.

FAQ