ACH pull vs ACH push: two ways to fund a USD to USDC on-ramp

Push means the payer sends an ACH transfer. Pull means you debit a connected account. How each funds a USD to USDC on-ramp, the fees, and the return risk.

ACH push and ACH pull are the two ways US dollars enter a stablecoin on-ramp. With push, the payer sends an ACH transfer from their own bank to details you show them. With pull, the payer connects their account once and each payment is a debit you start. On BlindPay, push is ach, and pull is ach_pull, in private beta.

Both end the same way: dollars land, BlindPay converts them, and USDC or USDT arrives in the customer's wallet. What changes is who starts the money moving, what can go wrong, and what the payer has to do.

Key takeaways

  • Push (payment_method: "ach"): the payer sends a transfer using a memo code and BlindPay's bank details, or their own virtual account details.
  • Pull (payment_method: "ach_pull"): BlindPay debits a Plaid-connected account. Private beta since September 18, 2026.
  • Pull adds a flat 1.00 USD fee, already included in the quote's sender_amount.
  • Connected accounts for pull are always first party, checked with Plaid Identity Match.
  • Pulled debits can be returned: two banking days for most returns, up to 60 calendar days for unauthorized consumer debits.

How does ACH push fund an on-ramp?

The payer does the work. You create a payin quote with payment_method: "ach", create the payin, and the response gives the payer what to send (payins).

If the customer has no approved virtual account, the payer sees a memo_code plus BlindPay's shared bank details, and the memo is how the deposit gets matched to the payin. If the customer has an approved virtual account, the payer sees that account's own routing and account numbers, and the memo is ignored. Virtual account vs one-time deposit instructions covers which one to use.

Then you wait. BlindPay documents a typical arrival window of up to 5 business days for an ach payin, because the payer decides when to send and the ACH network runs in batches. Payers who forget the memo are the classic failure, and why on-ramp deposits fail walks through the fixes.

How does ACH pull fund an on-ramp?

You do the work, once the payer authorizes it. The flow has two parts: connect the account, then pull per payment.

Connect. POST /v1/instances/{instance_id}/customers/{customer_id}/bank-accounts/plaid returns a url to a BlindPay-hosted page that renders Plaid Link. Show it in an iframe or a new tab. The link is single use and expires after at most 4 hours. When the customer finishes, BlindPay creates a bank account of type: "ach" with plaid_connected_at set and fires bankAccount.new (bank accounts).

Pull. Create a payin quote with payment_method: "ach_pull" and funding_bank_account_id set to that connected account. Create the payin and the pull starts on its own. No memo, no bank details, no waiting on the payer.

ACH pull is in private beta since September 18, 2026 (changelog). The instance needs the Plaid feature, so ask your BlindPay contact to turn it on.

How do push and pull compare side by side?

FactorACH push (ach)ACH pull (ach_pull)
Who starts the paymentThe payer, from their bankYou, through BlindPay
One-time setupNone, or a virtual accountCustomer connects the account through Plaid
What the payer sees per paymentMemo code and bank details, or virtual account detailsNothing to act on
Matching riskMissing or wrong memo, wrong amountLow: the amount comes from the quote
Extra feeNoneFlat 1.00 USD per pull, inside sender_amount
Account ownershipAny account the payer controlsFirst party only, name-matched
Availability on BlindPayGenerally availablePrivate beta since 2026-09-18
Main riskThe payer never sendsThe debit gets returned later

Pick push when payers are businesses that pay by their own AP process, or when amounts vary and the payer wants control. Pick pull for recurring top-ups by the same customer, where a forgotten memo costs you a support ticket every month.

Illustrative example: what does the payer pay on a $1,000.00 pull?

A customer wants 1,000.00 USDC delivered, and the sender pays the fees (cover_fees: true). Assume an illustrative BlindPay fee of 5.00 USD on this payin.

LineACH pushACH pull
USDC to deliver1,000.001,000.00
Illustrative BlindPay fee5.005.00
Pull provider fee0.001.00
sender_amount debited or sent1,005.001,006.00
Amount the pull actually movesn/a1,006.00 - 1.00 = 1,005.00

The arithmetic: 1,000.00 + 5.00 = 1,005.00 for push. For pull, 1,005.00 + 1.00 = 1,006.00 debited, and the pull itself moves 1,006.00 - 1.00 = 1,005.00 because the provider keeps its dollar.

Show the payer sender_amount as returned. It already includes the pull fee, so don't add it again on your screen. Real fees come from your live quote. For USD in and USDC out there's no currency conversion to read, but the quote fields work the same way as in how to read an FX quote. On-ramp fees explained breaks down the rest.

What errors does an ACH pull quote return?

Three validation errors cover most mistakes, all returned at quote time (payin quotes):

  1. funding_bank_account_id_required: you sent ach_pull without a connected account.
  2. funding_account_not_plaid_connected: the account exists but was never connected through Plaid, or belongs to a different customer.
  3. funding_account_invalid: you passed funding_bank_account_id with a method other than ach_pull.

On an instance without the Plaid feature, the quote fails earlier with BANK_ACCOUNTS_PLAID_NOT_ENABLED. And if the pull can't be initiated after you create the payin, it fails immediately with PAYINS_FUNDING_PULL_FAILED instead of sitting in processing. That's a real improvement over push, where a payin with no deposit just waits.

Why are pulled accounts always first party?

Because a debit you start needs a clear owner. BlindPay only accepts a connected account that belongs to the customer it is connected for. Before creating the bank account, it runs Plaid Identity Match between the account holder on file at the bank and the customer record, starting with the legal name.

Plaid describes Identity Match as returning match scores for how well your user data matches the account owner's information at their bank (Plaid). A mismatch fails the connection and no bank account is created. The identity fields on the resulting account come from the customer record, and recipient_relationship is always first_party. Paying yourself vs paying someone else explains why that field matters elsewhere in BlindPay.

What happens if a pulled payment is returned?

A pull is an ACH debit, and debits can come back. That's the trade you make for a payer who never has to remember a memo code.

The timing is set by the network, not by BlindPay. Most ACH returns, including insufficient funds and closed accounts, must go back within two banking days of settlement, while consumer entries have an extended window of up to 60 calendar days (Plaid). Nacha's own rules material confirms the 60-day timeframe for the unauthorized return reason R11 (Nacha).

Push transfers carry far less of this risk, because the payer sent the money themselves. So treat pull like a credit decision: cap first pulls for new customers, raise limits as accounts age, and keep the bank account id with every payin so you can trace a return. How long a stablecoin on-ramp takes has the timing for each rail.

What to do next

Create a Plaid link for a test customer on a development instance, connect with Plaid's user_good / pass_good sandbox credentials, and request one ach_pull payin quote. The bank accounts docs have the request body.

FAQ