Why crypto on-ramp deposits fail: missing references, late transfers, holds, and refunds

Most failed on-ramps fail on the fiat side: a missing reference, the wrong payer, a late transfer, a hold. What happens to the money in each case.

Most crypto on-ramp deposits that fail don't fail on-chain. They fail on the fiat side: a bank transfer sent without its reference, a payment from the wrong person, an amount that doesn't match the quote, a transfer that arrives after the window closed, or a compliance hold nobody answered. Where the money ends up depends on how far it got.

This is the support playbook for those cases. The payout side has its own version in stablecoin payout mistakes.

Key takeaways

  • An on-ramp has to match each incoming bank transfer to one quote. Anything that breaks the match (no reference, wrong payer, wrong amount) breaks the deposit.
  • Deposits have a waiting window per rail. Minutes for Pix and SPEI, days for ACH. Late money can fail even though it arrived.
  • Holds are reviews, not failures. Answer the request for information fast.
  • "Refunded" and "failed" are different outcomes for your ledger and for the customer.
  • A stablecoin delivered to the wrong address is the one failure nobody can fix after the fact.

Where does the money go when an on-ramp fails?

Locate the money first. Every failure sits at one of three points.

Where it stoppedWhat happened to the fiatWhat happened to the stablecoinsWhat to tell the customer
Before the deposit arrivedNever left the payer's bank, or never reached the providerNone were sentNothing was charged; start over with a new quote
After the deposit, before conversionHeld by the provider, then returned to the sender if it can't settleNone were sentThe money is coming back; bank timing applies
After deliveryConvertedIn the destination walletCheck the wallet and the network before anything else

On BlindPay, a payin ends as completed, failed, or refunded. refunded means the deposit went back to the sender. Fiat refunds are credited once the bank network returns the funds, which depends on each bank's processing time, and fees may apply. How a non-custodial model handles this matters here: the provider never holds a balance it could lose.

Failure 1: the transfer has no reference

When many customers pay into one shared bank account, the on-ramp tells them apart by a reference code. On BlindPay that's the memo_code shown with the bank details for ACH and wire payins. A transfer without it lands in the right account with nothing to tie it to a quote.

What goes wrong in practice:

  • The payer's bank app has a short memo field and truncates the code.
  • A finance team pastes the bank details into a payment template and reuses an old code.
  • The payer types the code into the "beneficiary name" field instead of the reference field.

The fix is structural: give recurring payers a dedicated account number. With a virtual account, every deposit to that account number belongs to that customer, so there's no code to forget. BlindPay ignores the memo code for ACH and wire when the customer has an approved virtual account. RTP is the exception and always uses the memo-code path.

Failure 2: the wrong person paid

Instant rails let an on-ramp check who is paying, and good ones do. On BlindPay a Pix payin quote can list the CPF or CNPJ tax IDs allowed to pay. Transfers 3.0 in Argentina requires the payer's CUIT or CUIL, and PSE in Colombia requires the payer's name, document, email, phone, and bank. The tax IDs are validated when the quote is created, so a malformed CPF fails before anyone sends money.

The failure comes later, when someone else pays. A company quoted under its own CNPJ, and an employee paid from a personal account. A parent paid for a child. The deposit arrives from a payer the quote didn't allow, so it doesn't match the payin it was meant for.

This rule exists for a reason. Regulators expect an on-ramp to know who is really funding each payment, a principle that runs through FATF's virtual asset guidance. Tell payers up front, in your UI, that the transfer must come from their own account. Pix keys, CPF, and CLABE covers the identifiers on the payout side.

Failure 3: the amount doesn't match

The quote fixes a fiat amount. The bank transfer has to match it.

  • Rounded or partial amounts. The payer sends R$1,000 against a quote for R$1,000.50, or splits it into two transfers.
  • Bank fees taken in transit. A wire arrives short because an intermediary bank deducted its charge.
  • Fractions on whole-unit rails. On BlindPay, MXN, COP, and ARS payins settle in whole currency units. A sender-side quote with centavos is rejected with request_amount_must_be_a_whole_currency_unit, because a fractional amount would be truncated on arrival and could come back as an invalid payment.
  • Out of range. Payin quotes enforce a minimum and maximum per currency, and the customer's own per-transaction limit applies on top. Deposits into a virtual account skip the per-currency minimums.

Show the exact amount, with every decimal, next to the instructions. If your users pay from banking apps that round, quote whole amounts.

Failure 4: the money arrived late

An on-ramp can't wait forever for a deposit, because the quote's rate was locked against a market that kept moving. Each rail gets a waiting window.

RailHow long BlindPay waits for the deposit
Pix (Brazil)Up to 30 minutes, with a reconciliation check before failing
SPEI (Mexico)Up to 30 minutes
Transfers 3.0 (Argentina)Up to 30 minutes
PSE (Colombia)Up to 30 minutes, since the bank redirect and two-factor step can lag
ACH, wire (US)Up to 5 business days

Pix and SPEI run around the clock under Banco Central do Brasil and Banxico, so a 30-minute window is generous when the payer acts right away. The usual problem is a payer who copies the Pix code and pays the next morning. One exception helps: if a Transfers 3.0 deposit arrives after the payin was marked failed and no stablecoins were sent yet, BlindPay revives it and completes it once the sender's tax ID and amount match.

OTC Pix quotes work differently. They wait until a fixed daily cutoff, and a deposit that never arrives adds a $100.00 penalty to the billing fee. Only quote OTC when the payer is ready to pay.

Failure 5: the payment went on hold

A hold isn't a failure. It's a review. BlindPay's transaction monitoring flags payins that look unusual, and the compliance team reviews each one. Common triggers, per the cut-off times reference:

  • A first deposit, or a pattern that doesn't fit the customer's history
  • A large amount relative to past activity
  • A sanctions or watchlist screening match
  • An open request for information on the customer

If the flag can't be cleared internally, BlindPay sends a request for information asking for the relationship between the payer and the customer, the purpose of the payment, and the expected outcome. If it isn't answered within 24 hours, the payment may be refunded to the sender. Route these requests to someone who can answer the same day. Real-time transaction monitoring explains what the system is looking for.

Failure 6: the wallet was wrong

This is the expensive one. The on-ramp did everything right and delivered stablecoins to the address on file. The address was wrong.

  • A typo in a pasted address. On Solana, Stellar, and Tron the address is submitted directly, with no signature to prove ownership.
  • The right address on the wrong network. EVM addresses look the same on Ethereum, Polygon, Base, and Arbitrum.
  • The wrong token for the network. USDC isn't deployed on Tron, and USDT isn't on Base, Arbitrum, or Stellar. Quote creation rejects these pairs, so this one is caught early.

A non-custodial on-ramp has no key to the destination wallet. BlindPay can't access, freeze, or recover funds in an external wallet, and an on-chain transfer can't be reversed. On EVM networks, have the customer register the wallet by signing a message so the address is recovered from the signature instead of typed. What happens on-chain shows why there's no undo.

Failure 7: the customer wasn't ready

Some payins never get a quote at all:

  • KYC isn't approved. The customer is still verifying, or has an open request for information.
  • Terms of service changed. When BlindPay updates its terms, quotes for customers who accepted an older version return please_accept_terms_of_service until they accept again.
  • Limits. KYC Standard customers have a $10,000 per-transaction payin limit by default, KYB Standard $30,000, and KYC Enhanced $50,000. Larger deposits need a limit increase first.

These show up as quote errors, not failed payins, which makes them the easiest to handle: catch the error and tell the customer what to do.

How do you tell a failure from a refund in code?

Handle every final status explicitly.

StatusMeaningYour action
completedStablecoins deliveredCredit the customer, show the transaction hash
refundedDeposit returned to the senderMark as returned; tell the customer the bank will credit it back
failedDidn't go throughCheck whether money arrived before you say anything; open a support case if it did
on_hold (not final)Under reviewShow "in review"; watch for a request for information

Payin events arrive as payin.new, payin.update, and payin.complete, and payin.complete covers all three final outcomes, so read the status field instead of assuming success. Stablecoin API webhooks covers signature checks and ordering, and integrating a crypto on-ramp API shows the full flow these statuses come from.

How do you test failure paths before launch?

On a BlindPay development instance, set a payin's request_amount to 66600 ($666.00) to force failed and 77700 ($777.00) to force refunded. Every other amount completes about 30 seconds after creation. Run both outcomes through your webhook handler, your ledger, and your customer emails. Then check that a refunded payin doesn't show as a balance anywhere.

What to do next

Pull last month's failed and refunded on-ramp payments and tag each one with a failure number from this list. Most teams find two causes account for most of them, usually missing references and late payers. Fix those with virtual accounts and a countdown next to the Pix code, and the support queue shrinks.

Some failures are really pricing surprises, like a wire that arrived short. Crypto on-ramp fees explained covers what the quote includes. For the wider picture of how business on-ramps differ from consumer ones, start with business vs consumer crypto on-ramps.

This article is general information, not legal, tax, or financial advice. Waiting windows, limits, and statuses can change; check the payins docs for current behavior.

FAQ