Virtual accounts vs one-time deposit instructions: how to collect bank transfers as stablecoins

One-time deposit instructions suit occasional payers and local rails. Virtual accounts suit repeat US payers. How each matches deposits and when to switch.

Use one-time deposit instructions when a payer sends money occasionally, for a specific amount, or over a local rail like Pix or SPEI. Use a virtual account when the same payer sends US bank transfers again and again. Instructions need no setup but depend on a reference code. A virtual account's number identifies the customer by itself.

Key takeaways

  • Both models turn a bank transfer into stablecoins in a wallet. They differ in how the deposit gets matched to a customer.
  • One-time instructions are created per payment: bank details plus a reference code, a Pix code, a CLABE, or a payment link.
  • A virtual account is a standing account number per customer. No reference to forget, but it needs KYC, review, and a monthly fee.
  • The most common failure in the one-time model is a missing or mangled reference. An ACH addenda field holds 80 characters, and payers lose codes far shorter than that.
  • Outside the US, per-payment instructions are often the only option, because Pix, SPEI, and similar rails already carry their own unique payment identifiers.

What are one-time deposit instructions?

One-time deposit instructions are payment details generated for a single pay-in, used once, for one amount.

The flow on a typical stablecoin on-ramp looks like this:

  1. You request a quote for the amount, the payment method, and the destination wallet.
  2. You create the pay-in from that quote.
  3. The provider returns instructions for that pay-in.
  4. You show them to the payer, who sends the transfer.
  5. The provider spots the deposit, matches it to the pay-in, converts it, and sends stablecoins to the wallet.

What "instructions" means depends on the rail. For a US transfer into a shared collection account, it's the account details plus a reference code the payer must include. For Pix, it's a payment code. For SPEI, it's a CLABE. For bank redirect rails such as PSE in Colombia, it's a payment link.

The crypto on-ramp API integration guide walks through the quote and pay-in calls in detail.

What is a virtual account?

A virtual account is a bank account number assigned to one customer that receives every deposit for that customer, with no reference needed.

The payer sends money to it like any other bank account. Each deposit creates its own pay-in record, gets converted, and lands in the wallet linked to the account. The account number is the matching key, so the payer can leave the memo blank, pay from a parent company, or send an unexpected amount, and the money still reaches the right customer.

The trade-off is setup. A virtual account belongs to a verified customer, goes through compliance and bank review, and usually carries a monthly fee. The full lifecycle is in stablecoin virtual accounts explained.

How do the two models compare?

One-time instructions win on setup and flexibility. Virtual accounts win on matching and repeat payments.

One-time deposit instructionsVirtual account
ReusableNo, one pay-in eachYes, every deposit
Matching keyReference code or rail payment codeThe receiving account number
Setup before first paymentA quote and a pay-in, secondsKYC or KYB, then compliance and bank review
Ongoing costPer-transaction fees onlyPer-transaction fees plus a monthly account fee
AmountFixed by the quoteAny amount the payer sends
Payer experienceNew details each timeSame details forever, saved as a payee
Main failure modeMissing or wrong referencePayer sends to an old or closed account
RailsUS transfers and local rails (Pix, SPEI, and others)Usually one country's rails
Best forOccasional payers, quoted amounts, local railsRepeat payers, B2B invoices, foreign senders

Read the "Main failure mode" row twice. It's the reason most teams start with instructions and move their busiest payers to accounts.

Why do references go missing?

Reference codes travel through fields that were never built to carry them reliably.

On ACH, free text rides in the addenda record's Payment Related Information field. Nacha's ACH file details describe it as an optional freeform field of 80 characters. Optional is the problem. Many bank apps hide it, shorten it, or put it on a second screen.

Wires got better structure when the Fedwire Funds Service moved to ISO 20022 on July 14, 2025. Better message formats don't help when a person types the code into the beneficiary name field.

The patterns repeat:

  • An accounts payable team saves your bank details as a template and reuses last month's code.
  • The payer's bank truncates the memo.
  • Someone pays two invoices in one transfer with one code.
  • A parent company pays on behalf of a subsidiary and uses its own reference.

A deposit without its code lands in the right bank account with nothing tying it to a pay-in. Someone then has to work out who paid. Why crypto on-ramp deposits fail covers that failure and six others.

Why do local rails work well with one-time instructions?

Instant rails like Pix and SPEI are built around unique payment identifiers, so the reference problem mostly disappears.

Pix is the clearest case. The Central Bank of Brazil's Pix initiation standards manual defines a transaction identifier, the txid, of 26 to 35 characters for dynamic QR codes. It exists so the receiver can reconcile each payment against the charge it belongs to. The payer scans or pastes the code. Nobody types a reference.

That's why per-payment instructions are the default for collections in Latin America. The payer's bank carries the identifier for you. How to on-ramp BRL, MXN, ARS, and COP covers the four local rails.

When should you use each model?

Pick by payer behavior first, then by rail.

Use one-time deposit instructions when:

  • The payer pays once or rarely, like a consumer topping up a wallet.
  • The amount is tied to a specific quote or invoice and should not vary.
  • The rail is Pix, SPEI, or another local system with built-in payment codes.
  • You need to accept money today, before a customer finishes account review.

Use a virtual account when:

  • The same payer sends transfers every week or month.
  • Payers pay from accounting systems that reuse saved bank details.
  • Amounts vary, like B2B invoices, marketplace seller funding, or payroll funding.
  • Foreign senders need to pay over SWIFT.
  • Finance wants the account number itself to be the customer ID in the ledger.

Many products run both. New customers start on instructions on day one, then get a virtual account once review clears.

What should you check before choosing?

Run this checklist against your payers and your provider before you commit to either model. It's what decides how much manual matching you'll do.

CheckOne-time instructionsVirtual account
How does the payer see the matching key?Shown with every payment. Is it hard to miss?Saved once as a payee
What happens to a deposit with no reference?Ask the provider for the exact path: hold, manual match, or returnNot applicable, the account number matches it
How long does a pay-in wait for money?Minutes on instant rails, days on ACH and wireNo quote window, deposits create pay-ins as they arrive
Is there a per-transaction cap?Ask. Shared collection accounts can carry their own cap on top of customer limitsCustomer limits from the verification tier apply
Which rails are covered?Check each local rail separatelyUsually domestic rails plus wire and SWIFT
What's the setup time?None beyond the quoteHours to business days for review
What's the monthly cost?NoneA fixed fee per account
Which webhook confirms the deposit?The pay-in completion eventThe same event, one per deposit

The ledger side, from webhooks to partial payments, is in how virtual accounts automate reconciliation.

How does BlindPay handle both models?

BlindPay supports both, and picks automatically for US transfers. A pay-in quote locks the method, amount, fee split, and destination for 5 minutes, and the pay-in created from it returns the instructions for that rail: a memo_code with bank details for ACH and wire, a pix_code for Pix, a CLABE for SPEI, an account number for Transfers 3.0, or a payment link for PSE.

When a customer has an approved virtual account, BlindPay shows that account's own details for ACH and wire and ignores the memo code. Two exceptions: RTP pay-ins always use the memo-code path, and SWIFT pay-ins require an approved virtual account. Pay-ins without a virtual account on ACH or wire are also capped at $500,000 per transaction. BlindPay's US virtual accounts cost $1.50 per month per account. The payins docs and cut-off times have the details.

For how pay-in APIs sit next to issuer, wallet, and payout APIs, see the types of stablecoin APIs.

What to do next

Pull last quarter's deposits and count how many arrived without a usable reference, by payer. Move the top repeat payers to virtual accounts first, and keep one-time instructions for everyone else and for every local rail.

FAQ