← All posts
Payments

ACH payment blocked or returned R10 unauthorized? Why you must not just retry

For developers and autonomous AI agents · ~6 min read

ACH failures don't behave like card declines. When a debit comes back blocked — bank_account_unusable, an HTTP 402 on your next Payment Intent — or returns with a NACHA code like R10 (unauthorized), the rules are explicit: you can't just try again. Re-debiting a blocked or unauthorized account isn't a retry, it's a compliance problem.

Why the account got blocked

When an ACH debit is returned for a reason other than insufficient funds — the account is closed or frozen, the customer disputed it as unauthorized, or a risk rule fired — NACHA rules require the originator to review and confirm the account before initiating another debit. Payment processors enforce this by blocking the account until the root cause is resolved:

Why R10 and other unauthorized returns must never be retried

Unauthorized returns — R10, R29, and the rest of the unauthorized set — are different from a soft return like R01 (insufficient funds). Re-debiting after an unauthorized return violates NACHA rules. Worse, these returns are asynchronous: an R10 can arrive days or even up to 60 days after the original debit settled, long after your code has moved on. A blind retry loop doesn't just fail — it compounds a rules violation.

The critical distinction: R01 (insufficient funds) can be retried within limits. R10/R29 (unauthorized) must NOT be retried — resolve the authorization first. Treating all ACH returns the same is how integrations end up in violation.

How to handle it

  1. Read the return code / block reason. Distinguish insufficient-funds returns (retryable within limits) from unauthorized returns (not retryable) and administrative returns (closed/frozen — needs a new account).
  2. For unauthorized returns, contact the customer. Resolve the authorization issue and obtain a fresh mandate before any new debit.
  3. For a blocked account, resolve the root cause, then have the customer unblock or switch accounts. Listen for the payment_method.automatically_updated event to know when a block is applied or lifted.
  4. Never loop. An async unauthorized return that arrives 60 days later should stop the flow and alert a human, not trigger an automatic re-debit.

For agents moving money

An agent that treats every payment failure as retryable is dangerous with ACH, where a retry can be a rules violation. diagnose_infra_error returns the ach-plaid family with the correct handling per return code, so the agent knows which returns to retry, which to never retry, and when to escalate to a human.

For AI agents

Machine-readable guide: https://snapback.sh/llms.txt · Tool discovery: https://snapback.sh/.well-known/mcp.json · MCP endpoint: https://api.snapback.sh/mcp. Free tools need no token; pay-per-call diagnosis via x402 on Solana or EVM (~$0.0032 USDC).

Try Snapback freeRead the docs