DEV Community

Payout Rail
Payout Rail

Posted on

ACH Return Codes Explained: R01 to R85 and What Each Means for Your Payout

ACH Return Codes Explained: R01 to R85 and What Each Means for Your Payout

Understanding ACH Return Codes: A Developer's Guide

When you're building a payout system, ACH (Automated Clearing House) transfers are reliable—until they aren't. A customer's bank rejects the transfer, and your system receives a return code. Understanding what that code means is critical to handling the failure gracefully and deciding whether to retry, escalate, or switch payment rails.

The National Automated Clearing House Association (NACHA) defines 85 return codes (R01 through R85). Each one tells you exactly why a transfer failed and whether it's recoverable.

The Most Common Return Codes

R01: Insufficient Funds
The account doesn't have enough money. This is temporary—the customer might deposit funds later. Your system should:

  • Log the return with a timestamp
  • Mark the payout as "failed, retry eligible"
  • Implement exponential backoff (retry after 24–72 hours)
  • Notify the customer

R03: No Account / Unable to Locate Account
The account number doesn't exist or the routing number is wrong. This is permanent. Action:

  • Flag for manual review
  • Do not retry on the same account
  • Request corrected account details from the customer
  • Consider switching to an alternate payout method (Visa Direct, RTP)

R10: Customer Advises Not Authorized
The account holder disputes the transaction. This is a fraud signal. Action:

  • Halt all payouts to that account immediately
  • Log the dispute
  • Escalate to your compliance team
  • Do not retry

R29: Corporate Account Closed
The business account was closed. Permanent failure. Request updated banking details.

R31: Permissible Return by ODFI (Originating Depository Financial Institution)
The sending bank rejected it before it left their system. Often a compliance or formatting issue. Action:

  • Review the transaction for data errors
  • Retry after correcting the entry
  • Contact your ACH processor if the issue persists

Less Common But Important Codes

R02: Account Closed
Similar to R29 but for consumer accounts. Permanent; request new details.

R07: Authorization Revoked by Customer
The customer withdrew consent for recurring debits. Respect this and stop future attempts.

R20: Non-Transaction Account
The account type doesn't accept ACH credits (e.g., a loan account). Permanent; request a checking or savings account.

R82: Duplicate Entry
Your system sent the same transaction twice within a short window. Check your deduplication logic.

Building a Return-Code Handler

Here's a pseudocode pattern for handling returns programmatically:

function handleACHReturn(returnCode, payoutRecord) {

  const permanentCodes = ['R03', 'R02', 'R29', 'R20'];
  const retryableCodes = ['R01', 'R09'];
  const fraudCodes = ['R10', 'R07'];

  if (fraudCodes.includes(returnCode)) {
    payoutRecord.status = 'FRAUD_HOLD';
    notifyCompliance(payoutRecord);
    return;
  }

  if (permanentCodes.includes(returnCode)) {
    payoutRecord.status = 'FAILED_PERMANENT';
    requestAccountUpdate(payoutRecord.customerId);
    return;
  }

  if (retryableCodes.includes(returnCode)) {
    payoutRecord.retryCount += 1;
    if (payoutRecord.retryCount < 3) {
      const nextRetry = now() + exponentialBackoff(payoutRecord.retryCount);
      scheduleRetry(payoutRecord, nextRetry);
    } else {
      payoutRecord.status = 'FAILED_MAX_RETRIES';
      notifyCustomer(payoutRecord);
    }
    return;
  }

  // Unknown code: log and escalate
  payoutRecord.status = 'FAILED_UNKNOWN';
  escalateToSupport(payoutRecord);
}
Enter fullscreen mode Exit fullscreen mode

Return Timing and Reconciliation

ACH returns arrive in batches, typically 1–2 business days after the original transfer. Your system must:

  • Reconcile return files daily against your payout ledger
  • Timestamp each return for audit trails
  • Distinguish between "returned" and "settled" states in your database
  • Account for same-day ACH returns (which arrive faster)

When to Switch Rails

If a customer hits R03 or R02, don't retry ACH. Consider:

  • Visa Direct: ~30 min settlement, higher cost (~$0.25 per transaction)
  • RTP (Real-Time Payments): ~5 seconds, still limited bank coverage in the US
  • Check: Slower, but works when bank details are unavailable

Summary

Return codes aren't errors—they're signals. R01 says "try again later


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)