Skip to content

ISO 20022 message

pain.002 format: customer payment status report

pain.002 is the bank’s answer to a payment file (a pain.001 or pain.008): received, accepted, pending or rejected, for the whole file, each payment block and each transaction, with reason codes for anything refused. It is the first place a rejected payment shows up.

pain.002 at a glance
Messagepain.002, root element <CstmrPmtStsRpt>
NameCustomer payment status report
SentBank → account owner
Read byPayment File Viewer

Who sends it, and when

The bank sends it to the company that sent the file, usually soon after the upload (technical checks) and again as processing goes on. Banks differ in how many reports they send and which statuses they use; some report only rejections.

The structure of a pain.002

pain.002 · structure
Document
└─ CstmrPmtStsRpt
   ├─ GrpHdr               MsgId, CreDtTm, DbtrAgt
   ├─ OrgnlGrpInfAndSts    the file: OrgnlMsgId, OrgnlMsgNmId, GrpSts, StsRsnInf, NbOfTxsPerSts
   └─ OrgnlPmtInfAndSts    a block: OrgnlPmtInfId, PmtInfSts
      └─ TxInfAndSts       a payment: OrgnlInstrId, OrgnlEndToEndId, TxSts,
                           StsRsnInf (Rsn/Cd, AddtlInf), OrgnlTxRef

Versions in use

Version .001.03 (2009) and .001.10 (2019) are the most common, paired with pain.001.001.03 and .001.09. From .001.08 the statuses come from the ISO 20022 external code lists instead of fixed lists, and a transaction can carry more values, such as ACPD (accepted by the clearing system) and PATC (awaiting further signatures). The viewer reads .001.02 to .001.13.

An annotated pain.002

An excerpt of the sample the viewer opens (fictitious companies, published test account numbers):

pain002-rejections.xml
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.002.001.10">
  <CstmrPmtStsRpt>
    …
    <OrgnlGrpInfAndSts>
      <OrgnlMsgId>NWT-PAY-20261028-03</OrgnlMsgId>
      <OrgnlMsgNmId>pain.001.001.09</OrgnlMsgNmId>
      …
      <GrpSts>PART</GrpSts>
      …
    </OrgnlGrpInfAndSts>
    <OrgnlPmtInfAndSts>
      <OrgnlPmtInfId>PMT-20261028-03</OrgnlPmtInfId>
      <PmtInfSts>PART</PmtInfSts>
      …
      <TxInfAndSts>
        <StsId>STS-412-3</StsId>
        <OrgnlInstrId>PMT-03-003</OrgnlInstrId>
        <OrgnlEndToEndId>NW-2026-403</OrgnlEndToEndId>
        <TxSts>RJCT</TxSts>
        <StsRsnInf>
          …
          <Rsn>
            <Cd>AC01</Cd>
          </Rsn>
          <AddtlInf>Account number does not exist at the creditor bank</AddtlInf>
        </StsRsnInf>
        …

“…” marks lines left out.

pain.002 sample, explained
In the fileWhat it says
<OrgnlMsgId> / <OrgnlMsgNmId>Which file this answers: its MsgId and message version.
<GrpSts>PARTPartly accepted: look at each transaction.
<OrgnlEndToEndId>NW-2026-403The payment, by the end-to-end id you set in the pain.001.
<TxSts>RJCTThis payment is rejected …
<Cd>AC01… because the account number is wrong (AC01).

Open this sample in the Payment File Viewer

Common validation errors

What most often goes wrong in a pain.002, and the rule that reports it in the viewer and the API:

  • pain.status.reason (Rejection without a reason): A rejection (RJCT) without a reason code.
  • pain.status.mix (Group status does not match transactions): The group status contradicts the transaction statuses (ACCP for a file whose payments are all rejected, for example).
  • pain.status.counts (Status counts differ): NbOfTxsPerSts counts that do not add up to the original number of transactions.

Check a pain.002 from a script or an AI agent

Scripts and AI agents can do the same without a browser: POST /api/v1/validate or the MCP tool validate_payment_file returns every issue with its rule id, severity, line and path, and whether the file is valid. No key is needed, and the file is processed in memory and never stored (API and MCP docs).

REST · curl
curl -s --data-binary @pain002-rejections.xml https://iso20022-navigator.com/api/v1/validate
MCP · tools/call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "validate_payment_file",
    "arguments": {
      "content": "<the file text>"
    }
  }
}