DEV Community

Payout Rail
Payout Rail

Posted on

ACH Return Codes Explained: R01–R85 and How to Handle Them in Production

ACH Return Codes Explained: R01–R85 and How to Handle Them in Production

ACH Return Codes Explained: R01–R85 and How to Handle Them in Production

When an ACH transfer fails, your payout system receives a return code. Understanding what that code means—and how to act on it—is the difference between a graceful retry and a stuck transaction.

The National Automated Clearing House Association (Nacha) defines 85 standardized return codes (R01 through R85). Each one tells you why a debit or credit failed, and each demands a different handling strategy. This guide covers the most common codes you'll encounter in production and how to decode them programmatically.

The Big Three: R01, R03, R10

R01: Insufficient Funds

The account exists, the routing number is correct, but there's not enough money to cover the debit.

  • When it fires: During the settlement window, typically 1–2 business days after initiation.
  • What to do: Flag the transaction as failed. Retry after 3–5 days (account may have been topped up), or route to an alternate rail (Visa Direct, RTP) if speed matters. Don't retry immediately; it will fail again.

R03: No Account / Unable to Locate Account

The routing number is valid, but the account number doesn't exist or has been closed.

  • When it fires: During settlement, sometimes within 24 hours.
  • What to do: This is terminal. Mark the transaction failed permanently. Contact the recipient to verify their account details. No retry will succeed.

R10: Unauthorized / Customer Advises Not Authorized

The account holder claims they didn't authorize this debit.

  • When it fires: Usually 10–60 days after initiation (ACH allows disputes in this window).
  • What to do: Investigate immediately. Check your authorization records. If legitimate, respond with documentation. If not, accept the chargeback and reverse the payout in your system.

Other Critical Codes

Code Meaning Retry? Action
R02 Account Closed No Verify account; request new details
R04 Invalid Routing Number No Correct routing number or request new account
R05 Unauthorized User / Account Type Mismatch No Verify account holder and account type
R07 Authorization Revoked No Account holder revoked permission; get new auth
R08 Payment Stopped No Recipient stopped this specific payment
R09 Uncollected Funds Yes Retry after 3–5 days
R16 Duplicate Entry No Check for duplicate in your system; don't resubmit
R20 Improper Effective Entry Date No Correct date and resubmit (rare in modern systems)
R29 Corporate Customer Advises Not Authorized No Same as R10; investigate

Building a Return Handler

Here's a minimal pattern for handling returns programmatically:

async function handleAchReturn(returnCode, transactionId) {
  const transaction = await db.getTransaction(transactionId);

  // Terminal failures: no retry
  const terminalCodes = ['R03', 'R02', 'R04', 'R05', 'R07', 'R08', 'R16'];
  if (terminalCodes.includes(returnCode)) {
    await transaction.markFailed('permanent');
    await notifyUser(transaction.recipientId, 
      `Payment failed. Please verify account details.`);
    return;
  }

  // Retryable: insufficient funds, uncollected funds
  const retryableCodes = ['R01', 'R09'];
  if (retryableCodes.includes(returnCode)) {
    transaction.retryCount++;
    if (transaction.retryCount < 3) {
      const retryDate = addDays(new Date(), 5);
      await transaction.scheduleRetry(retryDate);
      return;
    }
    // Max retries exceeded
    await transaction.markFailed('retries_exhausted');
    return;
  }

  // Disputes: investigate
  if (['R10', 'R29'].includes(returnCode)) {
    await transaction.markPending('dispute');
    await escalateToCompliance(transaction);
    return;
  }

  // Unknown code
  await transaction.markPending('unknown_return');
}
Enter fullscreen mode Exit fullscreen mode

Timing Matters

ACH returns arrive in batches, typically 1–2 business days after settlement. Your reconciliation must account for this lag. If you're tracking payout status in real time, don't mark a transaction "complete" until you've confirmed no return arrived within the settlement window (usually 5 business days for most codes, up to 60 for disputes).


Decoding ACH return codes programmatically? The ACH Return Codes API returns the full Nacha R01–R85 set with plain-language descriptions and handling guidance.

Top comments (0)