ISO 20022 Reason Codes: AC01 to RR04, the Rejection Codes That Matter
Written by Ahmed at Analyst Engineering, a Senior Technical Business Analyst with 10+ years in banking and payments delivery.
Key takeaways
- ISO 20022 reason codes ride alongside a status (usually RJCT) or a return, and their prefix tells you the family: AC for account, AM for amount, AG for agent-level refusals, RC for routing identifiers, RR for regulatory, MS for unspecified.
- Each code implies a different next action, which is the entire point: AC01 (wrong account number) invites a correction, AC04 (closed account) forbids retrying the same account, AM04 (insufficient funds) is about the debtor, not the beneficiary.
- Codes come from the standard's external code sets, but each scheme permits its own subset and its own usage: the same failure can carry different codes on different rails.
- The reference table is only half the work; mapping each code your system can emit to a correct customer message, and testing the codes it actually produces, is the other half.
An ISO 20022 reason code is the explanation attached to a failure: why the RJCT, why the return. The prefix names the family, the code names the cause, and the cause implies the action, which is why AC01 and AC04 must never share a customer message. Here are the codes a payments analyst actually meets, and what each one demands.
ISO 20022 reason codes explain why a payment was rejected, returned, or recalled, and they travel wherever failures travel: alongside an RJCT in a pacs.002 or pain.002 status report, inside a pacs.004 return, in a camt.056 recall request. The codes are defined centrally in the standard’s external code sets, so the same vocabulary works across rails, but each scheme’s rulebook permits its own subset with its own rules, the same usage-guidelines discipline that governs everything in ISO 20022. What makes the codes worth learning is not completeness, the full list runs to hundreds, but the working set below, because each code implies a different next action, and translating code to action is exactly the reason code mapping work that keeps customers from retrying the unretryable.
The reason code families
The first two letters are the family, and the family alone tells you where to look:
| Prefix | Family | Typical cause lives with |
|---|---|---|
| AC | Account | The account: wrong, closed, blocked |
| AM | Amount | The money: insufficient, duplicate, out of bounds |
| AG | Agent | A bank’s refusal: transaction not allowed |
| RC | Routing | An identifier: bad BIC or clearing code |
| BE | Beneficiary/party data | Missing or inconsistent party details |
| FF | File/format | The message itself: malformed content |
| MS | Missing/unspecified | No specific reason given |
| RR | Regulatory | Compliance and regulatory requirements |
| DT | Date | Invalid or impossible dates |
The codes you will actually meet
| Code | Meaning | The action it implies |
|---|---|---|
| AC01 | Incorrect account number | Correct the account identifier and retry |
| AC04 | Closed account | Do not retry this account; obtain a valid one |
| AC06 | Blocked account | Beneficiary must resolve with their bank |
| AG01 | Transaction forbidden | This account cannot receive this payment type |
| AM04 | Insufficient funds | Debtor-side problem: funds, not data |
| AM05 | Duplication | Suspected duplicate: investigate before resending |
| BE04 | Missing creditor address | Supply the required party data (see structured addresses) |
| DT01 | Invalid date | Correct the execution or value date |
| FF01 | Invalid file format | A message construction defect: fix the producer |
| MS02 | Not specified (customer generated) | The counterparty’s customer refused, no detail |
| MS03 | Not specified (agent generated) | A bank refused without detail: chase if habitual |
| RC01 | Bank identifier incorrect | Correct the BIC or clearing identifier |
| RR04 | Regulatory reason | Compliance-driven: usually deliberately unspecific |
| DUPL | Duplicate payment (return/recall context) | Money moved twice: reconcile and recover |
| TECH | Technical problem (recall context) | Sender-side recall justification |
| FRAD | Fraudulent origin (recall context) | Fraud-driven recall: time-critical handling |
Three reading rules keep the table honest. First, the same failure can carry different codes on different rails, because schemes constrain the set: verify against the rulebook in scope and against what your counterparties actually send. Second, context changes meaning: DUPL as a rejection reason stops a duplicate before settlement, while DUPL on a return or recall means money already moved and must come back, two very different operational days. Third, the unspecific codes are findings: a counterparty that habitually returns MS03 is exporting its ambiguity to your customer service desk, and that pattern is worth escalating, not just mapping.
Why does the code-to-action link matter so much?
Because the reason code becomes the customer’s next move, whether or not anyone designs it. AC01 tells the customer to check the number and try again; AC04 tells them the account is gone and retrying is futile; AM04 tells the debtor something, not the beneficiary; RR04 deliberately tells them very little, because compliance rejections should not explain themselves. A platform that renders all of these as “payment failed” manufactures repeat failures and support calls, and one that renders them precisely prevents both, which is why the mapping from cause to code to message deserves to be a maintained, tested artifact rather than tribal knowledge.
For the QA analyst, every row above is a test case with a specific assertion: submit the closed-account payment, assert RJCT with AC04, not AC01, not MS03, and assert the customer message that AC04 maps to. Systems routinely default to a generic code for every failure, and only testing the rejections reveals it; the elegant mapping in the spec is a hypothesis until the pacs.002 comes back.
The takeaway
ISO 20022 reason codes are the standard’s explanation layer: the prefix names the family, the code names the cause, and the cause implies the action, correct and retry for AC01, never-retry for AC04, investigate for AM05, escalate habitual MS03. The list is shared across rails but constrained per scheme, so the rulebook in scope is the final word, and the code your system actually emits is a claim you verify by testing, not by reading the spec.
About the author
Analyst Engineering is written by Ahmed, a Senior Technical Business Analyst with 10+ years of banking and payments delivery experience: ISO 20022 and SWIFT messaging, payments API integration, Kafka event validation, and production support. Every article comes from real delivery work, and each one is reviewed and updated as tools and standards change.
Related articles
- Reason Code Mapping: From Error to Customer Message How to map payment reason codes to causes and customer messages: ISO 20022 codes like AC04, internal errors, and the mapping that prevents support incidents.
- ISO 20022 Payment Status Codes: What ACSP, ACCP, and RJCT Really Mean The ISO 20022 payment transaction statuses explained: RCVD, ACTC, ACCP, ACSP, ACSC, PDNG, RJCT, and more, with the lifecycle order and what each guarantees.
- Payment Returns, Reversals, and Recalls: pacs.004, pacs.007, and camt.056 When money must come back, ISO 20022 gives three distinct mechanisms: returns, reversals, and recalls. Who initiates each, which message carries it, and how to model them.
- How to Write pacs.008 Test Cases for an ISO 20022 Migration A field-by-field guide to writing pacs.008 test cases: mandatory fields, structured data, validation, reason codes, and the pacs.002 responses that prove each case.
Newsletter
Subscribe
Practical, no-fluff playbooks for technical analysts who analyze, code, test, and support. New articles straight to your inbox.
No spam. Unsubscribe anytime.