ACH Dishonored Returns — Interbank Operational Disputes
Two banks enter, one return leaves 🐭 How to handle R61, R62, and other dishonored return codes in your payment system

For: Payments engineers, fintech developers, ACH operations teams
Reading Time: 12 minutes
Prerequisites: Familiarity with ACH file formats, NACHA rules, and standard return codes (R01–R33)
Why now: While dishonored returns are rare (<0.1% of all returns), they represent critical operational failures that require immediate   attention. Systems without proper handling risk frozen settlements and banking partner escalations.
TL;DR:
- Dishonored returns are when the ODFI formally disputes the validity of a return sent by the RDFI.
 - These are bank-to-bank operational disputes, not customer complaints.
 - Primary codes: R61 (misrouted), R62 (erroneous return), R67–R69 (timing/format errors).
 - Requires escalation to banking operations team and investigation workflow.
 - Separate from consumer dispute processes (Reg E).
 
⚠️ Critical Distinction: Dishonored returns are interbank operational disputes. They are not the same as consumer disputes under Regulation E.
⚠️ Disclaimer: All scenarios, accounts, names, and data used in examples are fictional and for educational purposes only.
Problem Definition
The challenge: When your ODFI (bank partner) identifies that a return received from an RDFI is invalid, improperly formatted, or misrouted, they must formally dispute it through a dishonored return. Your system needs to recognize these scenarios and trigger appropriate operational workflows.
Who faces this: Fintechs and payment platforms that process high ACH volumes (>10,000 transactions/month) and have direct ACH sponsorship relationships.
Cost of inaction:
- Unreconciled ledger entries (funds in limbo)
 - Banking partner escalations and potential fee assessments
 - NACHA rule violations if a pattern emerges
 - Delayed settlement for your customers
 
Why standard solutions fail: Most ACH integrations only handle the “happy path” return flow (debit → return → done). They don’t model the recursive case where the return itself is disputed.
Understanding Dishonored Returns
The Actual Flow
flowchart TD
  A["Originator sends ACH debit"] --> B["ODFI processes debit"]
  B --> C["ACH Network routes to RDFI"]
  C --> D["RDFI returns transaction (R01, R03, etc.)"]
  D --> E["ODFI receives return"]
  E --> F{"Is return valid?"}
  F -->|"Yes"| G["ODFI processes return normally"]
  F -->|"No - Invalid reason or misrouted"| H["ODFI creates dishonored return entry"]
  H --> I["ODFI sends dishonored return to RDFI (R61, R62, R67–R69)"]
  I --> J["Banks negotiate resolution"]
  J --> K["Final settlement determined"]
💡 Key Point: The ODFI is the one who dishonors (disputes) the RDFI’s return, not the other way around.
Dishonored Return Codes Explained
| Code | Official Name | What It Means | Example Scenario | Who Initiates | 
|---|---|---|---|---|
| R61 | Misrouted Return | Return was sent to wrong ODFI | RDFI used old routing number; correct ODFI returns it | Correct ODFI | 
| R62 | Return of Erroneous or Reversing Debit | Return itself is erroneous or reverses properly authorized debit | RDFI returned an authorized payroll debit as “unauthorized” | Original ODFI | 
| R67 | Duplicate Return | Same return already processed | RDFI accidentally submitted return twice | ODFI | 
| R68 | Untimely Return | Return outside allowed timeframe | Insufficient funds return sent 5 days late | ODFI | 
| R69 | Field Error | Return has data format errors | Trace number missing or malformed | Either bank | 
| R70 | Permissible Return Entry Not Accepted / Return Not a Duplicate | RDFI contests a dishonor | Complex dispute scenarios | RDFI | 
Real-World Scenarios
Scenario 1: Misrouted Return (R61)
Situation: Acme Payroll sends a debit via ODFI Bank A (routing: 123456789). The employee changes banks, and the old RDFI returns it for “Account Closed” (R02) — but sends it to the wrong ODFI.
What happens:
- Bank A receives a return it doesn’t recognize.
 - ODFI issues R61 dishonored return: “This wasn’t our transaction.”
 - RDFI must reroute to the correct ODFI.
 
Your system’s job:
- Receive ODFI notification for R61.
 - Do not adjust customer balances.
 - Log for audit.
 - Await correct routing.
 
# R61 - Misrouted Return Example
require 'date'
class ACHReturn
  attr_reader :trace_number, :code, :amount_cents, :received_date
  def initialize(trace_number:, code:, amount_cents:, received_date: Date.today)
    @trace_number = trace_number
    @code = code
    @amount_cents = amount_cents
    @received_date = received_date
  end
end
class DishonoredReturnHandler
  def handle_r61(return_item)
    puts "📬 Received R61 - Misrouted return for trace #{return_item.trace_number}"
    puts "⚙️  No customer impact. Logging and alerting ODFI ops."
    {
      status: 'dishonored',
      code: return_item.code,
      action: 'awaiting_correct_routing'
    }
  end
end
r61 = ACHReturn.new(trace_number: '000000001234567', code: 'R61', amount_cents: 150_000)
handler = DishonoredReturnHandler.new
puts handler.handle_r61(r61)
Scenario 2: Erroneous Return (R62)
Situation: Your platform processes an authorized subscription debit, but the RDFI returns it as unauthorized (R05).
What happens:
- ODFI disputes with R62 dishonored return, providing proof of authorization.
 - RDFI and ODFI enter a dispute negotiation.
 
Your system’s job:
- Provide authorization documentation.
 - Mark transaction as 
under_investigation. - Set 30-day review reminder.
 
# R62 - Erroneous Return Example
class ErroneousReturnHandler
  def initialize(odfi_client)
    @odfi_client = odfi_client
  end
  def handle_r62(trace_number, authorization_docs)
    puts "🚨 R62 - Disputing erroneous return for trace #{trace_number}"
    @odfi_client.submit_dishonor_evidence(
      trace_number: trace_number,
      dishonor_code: 'R62',
      documentation: authorization_docs
    )
    puts "📤 Submitted documentation to ODFI. Awaiting RDFI review."
    {
      status: 'under_investigation',
      trace: trace_number,
      action: 'evidence_submitted'
    }
  end
end
class MockODFIClient
  def submit_dishonor_evidence(trace_number:, dishonor_code:, documentation: {})
    puts "Submitting evidence for #{trace_number} with code #{dishonor_code}"
  end
end
auth_docs = {
  authorization_form: 'auth_form_tx001.pdf',
  previous_payments: ['tx_001', 'tx_002'],
  authorization_type: 'recurring_web'
}
handler = ErroneousReturnHandler.new(MockODFIClient.new)
puts handler.handle_r62('000000001234568', auth_docs)
Scenario 3: Duplicate Return (R67)
Situation: RDFI submits a duplicate return for an already processed transaction.
Your system’s job:
- Confirm duplicate caught.
 - Ensure only one ledger posting.
 
# R67 - Duplicate Return Example
class DuplicateReturnHandler
  def handle_r67(trace_number)
    puts "🔁 Duplicate return detected for trace #{trace_number}."
    puts "✅ ODFI rejected duplicate, verified single posting."
    {
      status: 'dishonored',
      code: 'R67',
      trace: trace_number,
      action: 'duplicate_rejected'
    }
  end
end
handler = DuplicateReturnHandler.new
puts handler.handle_r67('000000001234569')
Monitoring & Alerts
# Example Prometheus-compatible metric logging
def record_dishonored_return(code)
  puts "[METRIC] Increment counter ach_dishonored_returns_total{code=\"#{code}\"}"
end
record_dishonored_return('R62')
Prometheus Alert Rules (YAML):
groups:
  - name: ach_dishonored_returns
    rules:
      - alert: HighR62Rate
        expr: rate(ach_dishonored_returns_total{code="R62"}[1h]) > 0.01
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: "High R62 erroneous return rate"
          description: ">1% of returns disputed as erroneous. May indicate authorization problems."
Escalation Guide
Contact your ODFI immediately if:
- R62 received without clear authorization records.
 - Multiple R61s indicate routing errors.
 - Unexpected R67s suggest duplicate processing.
 - Investigation exceeds 10 business days — escalate through NACHA.
 
Validation Checklist
- ✅ System distinguishes dishonored returns (R61–R70) from standard returns.
 - ✅ R61 processing avoids customer balance changes.
 - ✅ R62 triggers authorization workflow.
 - ✅ R67 includes duplicate detection.
 - ✅ SLA tracking and alerting enabled.
 - ✅ Idempotency ensured for notifications.
 - ✅ Ops team escalation documented.
 
Takeaways
- Dishonored returns are rare but critical; handle them as exceptions.
 - R62 is the highest priority — defend authorization validity.
 - Never auto-process dishonored returns; route to investigation.
 - Maintain close ODFI collaboration for resolution.
 
References
- NACHA Operating Rules & Guidelines — 2024 Rulebook
 - NACHA Return Codes Reference — Official Code List, 2024
 - Federal Reserve — FedACH Operating Circular, 2024
 - Accuity — ACH Exception Handling Best Practices, 2023
 
        
Comments & Discussion
Share your thoughts, ask questions, or start a discussion about this article.