How to read a pain.002#
When your bank answers a pain.001 or pain.008, the pain.002 Customer Payment Status Report carries a status at up to three levels — group (GrpSts), payment information block (PmtInfSts), and individual transaction (TxSts) — plus zero or more status reason codes explaining any non-acceptance. The codes come from the ISO 20022 External Code Sets (ExternalStatusReason1Code), which is the canonical registry; this page covers the codes payment-operations teams actually meet, with the usual cause and the practical fix.
01. Status codes: how bad is it?#
| Status | Meaning | What to do |
|---|---|---|
RCVD |
Received — arrived, not yet checked | Nothing yet. |
ACTC |
Accepted, technical validation passed | Nothing — syntax and schema are fine. |
ACCP |
Accepted, customer profile checks passed | Nothing. |
ACSP |
Accepted, settlement in process | Nothing. |
ACSC |
Accepted, settlement completed | Done — reconcile against camt.053. |
ACWC |
Accepted with change — the bank altered something | Read the changes; fix your source data so the bank stops "helping". |
PART |
Partially accepted — some transactions rejected | Check per-transaction TxSts; resubmit only the rejected ones. |
PDNG |
Pending — further checks ongoing | Wait; investigate only if it persists past the bank's stated window. |
RJCT |
Rejected | Read the reason codes below; repair; resubmit. |
02. Format and schema failures#
The rejections Pain001 exists to make impossible — every one of these is caught by the validation gate before submission:
| Code | Name | Typical cause | Fix |
|---|---|---|---|
FF01 |
Invalid file format | Wrong schema version, malformed XML, wrong namespace | Validate against the exact XSD your bank profiles (pain001 --dry-run). |
AM10 |
Invalid control sum | CtrlSum doesn't match the sum of amounts |
Never hand-compute totals — Pain001 recomputes NbOfTxs/CtrlSum from the records. |
AM01 |
Zero amount | An amount of 0 slipped through | Filter zero rows at source. |
AM02 |
Amount not allowed | Above a scheme or account limit | Check scheme ceilings and account mandates. |
AM03 |
Currency not allowed | Currency not supported on the account/scheme | SEPA schemes are EUR-only; use the cross-border rulebook otherwise. |
AM09 |
Wrong amount | Amount disagrees with a referenced mandate/agreement | Reconcile against the mandate. |
DT01 |
Invalid date | Execution date malformed, in the past, or a non-banking day | ISO 8601, forward-dated, banking-day adjusted. |
CH03 |
Execution date too far in future | Beyond the bank's forward window (often 1 year) | Shorten the horizon. |
TM01 |
Cut-off time | File arrived after the bank's processing cut-off | Automate submission earlier; know each bank's cut-offs. |
DU01–DU03 |
Duplicate message / payment info / transaction ID | Re-used MsgId, PmtInfId, or EndToEndId |
Generate unique IDs per submission; never resubmit a file unchanged. |
03. Account and identifier failures#
| Code | Name | Typical cause | Fix |
|---|---|---|---|
AC01 |
Incorrect account number | IBAN fails validation or doesn't exist | Mod-97 check before submission — the demo shows this live. |
AC03 |
Invalid creditor account | Creditor IBAN wrong or closed | Verify against the invoice/master data. |
AC04 |
Closed account | Account has been closed | Contact the counterparty for current details. |
AC06 |
Blocked account | Account blocked for this transaction type | Counterparty must resolve with their bank. |
RC01 |
Bank identifier incorrect | Malformed or unknown BIC | ISO 9362 structure check + directory lookup. |
AG01 |
Transaction forbidden | Payment type not allowed on this account | Wrong account or missing product agreement. |
AG02 |
Invalid bank operation code | Wrong local instrument / service level combination | Match your bank's implementation guide. |
04. Party, mandate, and regulatory failures#
| Code | Name | Typical cause | Fix |
|---|---|---|---|
BE01 |
Inconsistent with end customer | Name doesn't match the account | Fix creditor master data; this is what Verification of Payee checks pre-submission. |
BE04 |
Missing creditor address | Address absent where required | From 14 Nov 2026, CBPR+ requires structured or hybrid addresses — see the roadmap. |
BE05 |
Unrecognised initiating party | Initiating party not authorised on the account | Check the bank mandate for the submitting entity. |
MD01 |
No mandate | Direct debit without a valid mandate | Collect/register the mandate before collecting funds. |
MD02 |
Missing mandate information | Mandate data incomplete in the pain.008 | Populate all mandate-related fields. |
MD07 |
End customer deceased | — | Close the mandate. |
RR01–RR04 |
Regulatory reasons | Missing debtor/creditor identification, name, address, or other regulatory data | Populate the party data your corridor requires; structured addresses solve most of these. |
AM04 |
Insufficient funds | Not a format problem | Treasury, not toolchain. |
MS02 / MS03 |
Reason not specified (customer / bank generated) | The bank chose not to say | Call the bank; often accompanies sanctions or internal-policy holds. |
NARR |
Narrative | Free-text explanation in AddtlInf |
Read the narrative field. |
05. Close the loop automatically#
Pain001 parses pain.002 responses into structured data, so your pipeline can route rejections without a human reading XML:
pip install pain001
from pain001.pain002 import parse_pain002
report = parse_pain002("bank-response.xml")
for tx in report.transactions:
if tx.status == "RJCT":
print(tx.end_to_end_id, tx.reason_code, tx.additional_info)
The MCP server exposes the same parser to AI agents as parse_pain002, and the payment-lifecycle guide shows where status handling sits in the full pipeline.
Canonical source. Code definitions live in the ISO 20022 External Code Sets, maintained at iso20022.org/catalogue-messages/additional-content-messages/external-code-sets and revised quarterly. Bank implementation guides may narrow — but not contradict — these meanings. Spot an inaccuracy? Report it.