---
title: "Virtual accounts vs one-time deposit instructions: how to collect bank transfers as stablecoins"
seoTitle: "Virtual account vs one-time deposit instructions"
description: "One-time deposit instructions suit occasional payers and local rails. Virtual accounts suit repeat US payers. How each matches deposits and when to switch."
date: "2026-10-04"
updated: "2026-10-04"
category: "payments"
author: "BlindPay Team"
faq:
  - q: "What are one-time deposit instructions in a stablecoin on-ramp?"
    a: "One-time deposit instructions are payment details generated for a single pay-in: a bank account plus a reference code, a Pix code, a CLABE, or a payment link. The payer uses them once, for one amount, and the provider matches the deposit to that pay-in. They need no account setup, which makes them the quickest way to accept a bank transfer and settle it in stablecoins."
  - q: "What is the difference between a virtual account and deposit instructions?"
    a: "A virtual account is a standing bank account number assigned to one customer, reusable for every deposit. Deposit instructions are created per payment and expire with it. The account number identifies the customer on its own, while instructions rely on a reference code or a unique payment code that the payer has to carry through their bank correctly."
  - q: "When should I switch a customer from deposit instructions to a virtual account?"
    a: "Switch when the same payer sends recurring transfers, when references keep going missing, when payers pay from accounting systems that reuse old details, or when you need foreign senders to pay over SWIFT. Keep one-time instructions for occasional payers, for amounts tied to a specific quote, and for local rails outside the US where virtual accounts are not offered."
  - q: "Why do bank transfers lose their reference codes?"
    a: "Reference fields are short and handled differently by every bank app. An ACH addenda record carries 80 characters of free text, and many consumer apps expose less. Payers type codes into the wrong field, reuse old templates, or drop the code entirely. A deposit without its code lands in the right account but can't be tied to the right pay-in automatically."
  - q: "Can virtual accounts receive Pix or SPEI?"
    a: "Virtual accounts are usually tied to one country's banking system. BlindPay's virtual accounts are US accounts that receive ACH, wire, and SWIFT. Brazilian, Mexican, Argentine, and Colombian collections use per-payment instructions instead: a Pix code, a CLABE, an account number for Transfers 3.0, or a PSE payment link."
  - q: "Do one-time deposit instructions expire?"
    a: "Usually yes, in two layers. The quote behind them expires quickly, often within minutes, so the pay-in must be created in that window. Then the pay-in waits for the money for a set period that depends on the rail: minutes for instant rails like Pix or SPEI, and days for ACH and wire. After that the pay-in is marked failed or cleaned up."
---

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](/resources/more/how-to-integrate-a-crypto-on-ramp-api) 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](/resources/more/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 instructions | Virtual account |
| --- | --- | --- |
| Reusable | No, one pay-in each | Yes, every deposit |
| Matching key | Reference code or rail payment code | The receiving account number |
| Setup before first payment | A quote and a pay-in, seconds | KYC or KYB, then compliance and bank review |
| Ongoing cost | Per-transaction fees only | Per-transaction fees plus a monthly account fee |
| Amount | Fixed by the quote | Any amount the payer sends |
| Payer experience | New details each time | Same details forever, saved as a payee |
| Main failure mode | Missing or wrong reference | Payer sends to an old or closed account |
| Rails | US transfers and local rails (Pix, SPEI, and others) | Usually one country's rails |
| Best for | Occasional payers, quoted amounts, local rails | Repeat 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](https://achdevguide.nacha.org/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](https://www.frbservices.org/news/communications/061825-fedwire-iso-go). 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](/resources/more/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](https://www.bcb.gov.br/content/estabilidadefinanceira/pix/Regulamento_Pix/II_ManualdePadroesparaIniciacaodoPix.pdf) 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](/resources/more/how-to-on-ramp-local-currency-latin-america) 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.

| Check | One-time instructions | Virtual 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 return | Not applicable, the account number matches it |
| How long does a pay-in wait for money? | Minutes on instant rails, days on ACH and wire | No 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 limits | Customer limits from the verification tier apply |
| Which rails are covered? | Check each local rail separately | Usually domestic rails plus wire and SWIFT |
| What's the setup time? | None beyond the quote | Hours to business days for review |
| What's the monthly cost? | None | A fixed fee per account |
| Which webhook confirms the deposit? | The pay-in completion event | The same event, one per deposit |

The ledger side, from webhooks to partial payments, is in [how virtual accounts automate reconciliation](/resources/more/virtual-account-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](/docs/payins) and [cut-off times](/docs/kb/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](/resources/more/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.
