pain.002 Status and Reject Codes: Reading the Bank's Reply
How to read a pain.002 status report: group, payment and transaction level, the ACTC/ACCP/ACSC status codes, and reject reasons like AC01, AC04 and AM04.
Connectivity 11 of 15 see the reading order →
Reviewed by Tan Gravam Fact-checked
On this page
A pain.002 answers your pain.001 at up to three levels — the whole file, each payment batch, each transaction — and every answer is a four-letter status code plus, when the status is RJCT, a reason code that tells you why. The status codes and the reason codes come from two different lists, live at different depths of the message, and are the difference between "the bank said no" and knowing at 9:05 that one supplier IBAN is dead while the other 199 salaries are fine. This is the response-side companion to the pain.001 field walkthrough: that post builds the instruction, this one decodes the reply. As there, I'll keep two sources open side by side — the official ISO 20022 External Code Sets, which own the code meanings, and a real bank's pain.002 implementation guide (Nordea's, again one of the few public ones), which shows how much of the standard a bank actually sends.
Three levels of answer
The message is CustomerPaymentStatusReport — root element <CstmrPmtStsRpt>. Its shape mirrors the pain.001 it answers:
- GroupHeader
<GrpHdr>— the bank's own envelope: its MsgId, its CreationDateTime. Nothing about your payments yet. - OriginalGroupInformationAndStatus
<OrgnlGrpInfAndSts>— the verdict on your message:<OrgnlMsgId>echoes the MsgId of your pain.001,<OrgnlMsgNmId>names the message type it's answering, and<GrpSts>carries the group status. - OriginalPaymentInformationAndStatus
<OrgnlPmtInfAndSts>— the verdict on each batch:<OrgnlPmtInfId>echoes your PmtInfId,<PmtInfSts>carries the payment-level status. Inside it, TransactionInformationAndStatus<TxInfAndSts>answers each payment:<OrgnlInstrId>and<OrgnlEndToEndId>echo your references,<TxSts>carries the transaction status, and<StsRsnInf>carries the reason.
This is the payoff of the identifier discipline from the pain.001 side: MsgId, PmtInfId and EndToEndId each come back at exactly one level of the pain.002 — Nordea's guide maps them index by index — so a status finds its payment without any matching heuristics. If your EndToEndIds are lazy, this is the message where you pay for it.
An illustrative skeleton — real tag names from Nordea's pain.002.001.03 guide, not a bank-ready file — answering the pain.001 from the sibling post, with one transaction bounced:
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.002.001.03">
<CstmrPmtStsRpt>
<GrpHdr>
<MsgId>BANK-STATUS-20260803-42</MsgId>
<CreDtTm>2026-08-03T10:12:00Z</CreDtTm>
</GrpHdr>
<OrgnlGrpInfAndSts>
<OrgnlMsgId>ACME-20260802-0001</OrgnlMsgId>
<OrgnlMsgNmId>pain.001.001.03</OrgnlMsgNmId>
</OrgnlGrpInfAndSts>
<OrgnlPmtInfAndSts>
<OrgnlPmtInfId>ACME-20260802-0001-01</OrgnlPmtInfId>
<PmtInfSts>PART</PmtInfSts>
<TxInfAndSts>
<OrgnlInstrId>INV-4711-P2P</OrgnlInstrId>
<OrgnlEndToEndId>INV-4711</OrgnlEndToEndId>
<TxSts>RJCT</TxSts>
<StsRsnInf>
<Rsn><Cd>AC04</Cd></Rsn>
<AddtlInf>ISO Account number specified has been closed</AddtlInf>
</StsRsnInf>
</TxInfAndSts>
</OrgnlPmtInfAndSts>
</CstmrPmtStsRpt>
</Document>
One rule saves a lot of confused parsing: check the group level first. Nordea's guide states it plainly — a group-level RJCT means the whole file is rejected and will not be processed, while a group-level ACTC means technical validation passed and content validation follows. If the file died at the gate, no payment- or transaction-level statuses are coming, ever, and your monitor shouldn't sit waiting for them.
The status codes: a lifecycle, not a list
The official meanings live in ISO's External Code Sets — ExternalPaymentGroupStatus1Code for the group level (13 codes in the 1Q2026 edition) and ExternalPaymentTransactionStatus1Code for transactions (25 codes). In older message versions like the .03 that Nordea implements, the same codes sit as embedded schema enumerations (typed TransactionGroupStatus3Code and TransactionIndividualStatus3Code in its guide); the external list is where ISO maintains the definitions now. Read in order, the core codes are a pipeline:
| Code | Official meaning (condensed from the ISO external code sets) |
|---|---|
| RCVD | Payment initiation has been received by the receiving agent. |
| ACTC | Authentication and syntactical and semantical validation are successful. |
| ACCP | Preceding check of technical validation was successful; customer profile check was also successful. |
| ACSP | All preceding checks such as technical validation and customer profile were successful; accepted for execution. |
| ACSC | Settlement on the debtor's account has been completed (group set); settlement completed (transaction set). |
| ACCC | Settlement on the creditor's account has been completed. |
| ACWC | Instruction is accepted but a change will be made, such as date or remittance not sent. |
| PART | A number of transactions have been accepted, whereas another number have not yet achieved 'accepted' status. |
| PDNG | Payment instruction is pending; further checks and status update will be performed. |
| RJCT | Payment instruction has been rejected. |
The A-codes are stages, not synonyms: ACTC says the file parsed, ACCP says the bank also recognises you, ACSP says it's going to execute, and only ACSC/ACCC talk about settlement — the ISO set even flags ACSC as usable only under bilateral agreement, because settlement confirmation is what your statement is for. A payment can die after any of them. Treat every A-status short of settlement as "so far, so good", not as "done".
Three codes deserve a closer look than their four letters suggest. ACWC means the bank changed something and processed anyway — date shifted past a cut-off, remittance dropped — and if you file it under "accepted" without reading the change, your books and the bank's diverge silently. PART at payment level is the one that should page someone: some transactions in the batch made it, some didn't, so a blanket retry re-pays the successful ones. PDNG means the story isn't over; another pain.002 follows.
The transaction set has a longer tail — ACFC (funds check passed), ACWP (accepted without posting to the creditor's account yet), BLCK (a previously-ACWP payment is now blocked in both directions), PATC (multi-authorisation flows where some approvals are still outstanding), CANC (cancelled — the set marks it for API contexts), even CPUC for cash physically picked up. The newest additions are the RCVC/RVCM/RVNC family for Verification of Payee outcomes — the code list is a living document, and the quarterly external-set publication is where it lives. You will not meet most of these; Nordea's guide, for instance, sends exactly two codes at group level (ACTC, RJCT) and five at payment level (ACCP, ACWC, PART, PDNG, RJCT). Same pattern as on the pain.001 side: the standard defines the vocabulary, the MIG tells you which words the bank actually speaks.
When it's RJCT: the reason codes
RJCT alone tells you nothing actionable. The why sits in <StsRsnInf> — a <Rsn><Cd> holding a code from ExternalStatusReason1Code, plus optional <AddtlInf> free text. This is the list behind every "sepa reject reason code" search: 302 codes in the 1Q2026 edition, of which a corporate treasury meets perhaps twenty-five. What follows is that curated subset with the official meanings, condensed from the ISO external code sets — for anything rarer, go to the official list rather than a forum thread.
Account codes — the wrong-IBAN family:
| Code | Official meaning |
|---|---|
| AC01 | Account number is invalid or missing. |
| AC02 | Debtor account number invalid or missing. |
| AC03 | Creditor account number invalid or missing. |
| AC04 | Account number specified has been closed on the bank of account's books. |
| AC06 | Account specified is blocked, prohibiting posting of transactions against it. |
AC01 vs AC04 is the distinction worth automating: AC01 is bad master data you can fix today; AC04 means the account existed and is gone — you need a new IBAN from the beneficiary, and retrying is pointless.
Funds and amount codes:
| Code | Official meaning |
|---|---|
| AM01 | Specified message amount is equal to zero. |
| AM02 | Specific transaction/message amount is greater than allowed maximum. |
| AM04 | Amount of funds available to cover specified message amount is insufficient. |
| AM05 | Duplication. |
AM04 is the insufficient-funds code — on the initiation side that's your account short, which makes it a cash positioning failure wearing a format costume. AM02 usually means you tripped a limit in the bank agreement, not the scheme.
Routing and agent codes:
| Code | Official meaning |
|---|---|
| RC01 | Bank identifier code specified in the message has an incorrect format. |
| RC02 | Bank identifier is invalid or missing. |
| AGNT | Agent in the payment workflow is incorrect. |
| CNOR | Creditor bank is not registered under this BIC in the CSM. |
| DNOR | Debtor bank is not registered under this BIC in the CSM. |
File, date and timing codes — the ones test phases are made of:
| Code | Official meaning |
|---|---|
| FF01 | File format incomplete or invalid. |
| DT01 | Invalid date (e.g. wrong or missing settlement date). |
| DT02 | Invalid creation date and time in Group Header (e.g. historic date). |
| CH03 | Value in Requested Execution Date is too far in the future. |
| CH04 | Value in Requested Execution Date is too far in the past. |
| TM01 | Message, payment information block or transaction received after agreed processing cut-off time. |
| DUPL | Payment or charge is a duplicate of another payment or charge. |
| RF01 | Transaction reference is not unique within the message. |
If the pain.001 walkthrough is the instruction manual, this table is its error page: the stale CreationDateTime, the reused MsgId, the execution date outside the window — each has its own code, and each is fixable on your side without calling anyone.
Party and regulatory codes:
| Code | Official meaning |
|---|---|
| BE01 | Identification of end customer is not consistent with associated account number. |
| BE04 | Specification of creditor's address, required for payment, is missing or not correct. |
| MD07 | End customer is deceased. |
| RR01 | Regulatory: debtor account or unique identification insufficient or missing. |
| RR02 | Regulatory: debtor name and/or address insufficient or missing. |
| RR03 | Regulatory: creditor name and/or address insufficient or missing. |
| RR04 | Regulatory reason. |
| AM07 | Amount specified in message has been blocked by regulatory authorities. |
| CURR | Currency of the payment is incorrect. |
BE04 and the RR-family are the structured-address era in code form: address data that used to be tolerated as missing is increasingly a hard reject.
The catch-alls — where the code stops helping:
| Code | Official meaning |
|---|---|
| CUST | Cancellation requested by the Debtor. |
| MS02 | Reason has not been specified by end customer. |
| MS03 | Reason has not been specified by agent. |
| NARR | Reason is provided as narrative information in the additional reason information. |
Two of these are traps. CUST gets glossed in the wild as "customer error" or "customer decision"; the official definition in the status-reason list is narrower — a cancellation the debtor asked for. And MS03 is the bank formally declining to give you a coded reason — often because a sanctions or fraud screen is involved and the bank won't say so. When your reject feed is dominated by MS03 and NARR, the information you need is in <AddtlInf> or on the phone, not in the code — Nordea's guide, for instance, commits to filling AdditionalInformation for every non-ACCP status, prefixing it ISO when the text comes from the external code list and CAP when it's the bank's own commentary. And banks repurpose codes too, documented in plain sight: the same guide uses MS02 with an ACWC status to signal a changed creditor account in Finland — a meaning you would never derive from the official definition. When bank usage and the official list disagree, print the official meaning and read the MIG for the local dialect.
A reject is not a return
One distinction keeps reconciliation honest: pain.002 RJCT happens before your money moves — validation or execution failed and nothing settled. When a payment settles and then comes back (beneficiary account closed at the far end, funds recalled), that's a return, and it reaches you through your statement and reporting flow, carrying reason codes from a sibling list, ExternalReturnReason1Code. The two lists overlap heavily — AC04, AM04, MD07 appear in both with essentially the same meanings — but not perfectly, and the wording is set-specific: AC01 officially means "Account number is invalid or missing" as a status reason but "Format of the account number specified is not correct" as a return reason. Practical consequence: don't build one lookup table for "SEPA reject codes" and feed it both message families; key your code tables by code set, not by four letters.
What usually goes wrong
- Treating pain.002 as optional. The overview post makes this point strategically; here's the operational version: a payment run without status handling means your first reject notification is an angry supplier.
- Waiting for transaction statuses after a group-level RJCT. The file is dead; nothing below the group level will arrive. Check
<GrpSts>first. - Mapping every A-status to "paid". ACTC, ACCP and ACSP are checkpoints. Settlement is ACSC/ACCC at best, and your statement in practice.
- Blanket-retrying a PART batch. Some of those payments went through. Retry the RJCT transactions by EndToEndId, or pay people twice.
- One reason-code table for rejects and returns. Same letters, different code sets, set-specific wording. Key by set.
- Ignoring
<AddtlInf>. For MS03 and NARR it's the only content you get; for bank-specific dialects (Nordea'sCAP-prefixed lines) it's where the real explanation lives.
The reply side of the payment conversation is smaller than the instruction side — three levels, one status vocabulary, one reason-code list — but it's the half that runs at 2 a.m. when nobody's watching. Wire the codes to actions once, against the official list, and a bounced payment becomes a work item instead of an investigation.
See also the pain.001 field walkthrough, the pain.001/pain.002 overview, and the camt.053 statement walkthrough.
Primary sources
Status and reason code usage is version- and bank-specific: the official code meanings below come from the ISO 20022 External Code Sets (1Q2026 edition, which lists 302 status reason codes), and the bank behaviour follows a pain.002.001.03 implementation guide (Nordea, CGI aligned), while the ISO catalogue is at CustomerPaymentStatusReportV15. Verify which statuses and reasons your banks actually send against their own MIGs.
Frequently asked questions
4
What is the difference between ACTC, ACCP and ACSP in pain.002?
They are successive acceptance stages, each defined in the ISO 20022 external status code sets. ACTC means authentication and syntactical and semantical validation succeeded — the file parsed and passed schema-level checks. ACCP adds that the customer profile check also passed — the bank recognises the account and agreement behind the payment. ACSP means all preceding checks succeeded and the instruction has been accepted for execution. A payment can die after any of them, so none of the three means 'paid' — for settlement you're waiting for ACSC or ACCC, or in practice for the account statement.
What does reject reason code AC01 mean?
In the ISO 20022 ExternalStatusReason1Code list — the code set pain.002 reason codes come from — AC01 officially means 'Account number is invalid or missing'. In practice it's the classic wrong-IBAN reject: the account number failed validation. One subtlety: the sibling return-reason code set defines AC01 as 'Format of the account number specified is not correct', so the same four letters carry set-specific wording depending on whether you're reading a reject or a return. Related codes: AC02 and AC03 pin the invalid account to the debtor or creditor side, and AC04 means the account has been closed.
Can a pain.002 reject a whole file?
Yes. The status report can answer at group level via GroupStatus in OriginalGroupInformationAndStatus, and a group-level RJCT kills the entire original message. Nordea's pain.002 implementation guide is explicit: when it sends RJCT as the group status, the whole file is rejected and will not be processed, whereas ACTC at group level means technical validation passed and content validation continues in the back end. That's why status handling has to check the group level first — if the file died there, no payment or transaction level statuses are coming.
What do MS03 and NARR mean in a payment rejection?
Both come from the ISO external status reason code list and both are catch-alls. MS03 officially means 'Reason has not been specified by agent' — the bank rejected the payment and is not telling you why in coded form; its sibling MS02 is the same with the end customer as the silent party. NARR means the reason is provided as narrative information in the additional reason information — free text instead of a code, so your automation has to surface the AdditionalInformation element to a human. If your rejects are dominated by MS03 and NARR, the useful detail is usually in AdditionalInformation or in a phone call, not in the code.