Kolos Hetyéssy Software developer

Free tools / SEPA & NACHA Payment File API

Convert pain.001.001.03 to pain.001.001.09

Turn 2009 SEPA files into the 2019 versions, with nothing guessed. Drop your pain.001.001.03 or pain.008.001.02 file below to see what the validator says about it; the conversion itself is an API call.

  • Free, no sign-up
  • Your file is never stored
  • Deterministic: no AI guesswork

Try it now

The demo validates the file you drop and shows whether it is the old version, not the converted file; converting is an API call. Your file is read in memory and discarded right after.

The live demo needs JavaScript, which seems to be switched off. The sample tabs show the engine's real output without it.

A pain.001.001.09 credit transfer generated by the API: structured addresses, one invoice reference and one RF creditor reference. Every check passes.

pain001-v09-valid.xml 1469 bytes · pain.001.001.09

Input file

<?xml version="1.0" ?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09">
  <CstmrCdtTrfInitn>
    <GrpHdr>
      <MsgId>PAYRUN-2026-10-23</MsgId>
      <CreDtTm>2026-10-21T09:00:00</CreDtTm>
      <NbOfTxs>2</NbOfTxs>
      <CtrlSum>1284.06</CtrlSum>
      <InitgPty>
        <Nm>Acme GmbH</Nm>
      </InitgPty>
    </GrpHdr>
    <PmtInf>
      <PmtInfId>PAYRUN-2026-10-23-1</PmtInfId>
      <PmtMtd>TRF</PmtMtd>
      <NbOfTxs>2</NbOfTxs>
      <CtrlSum>1284.06</CtrlSum>
      <PmtTpInf>
        <SvcLvl>
          <Cd>SEPA</Cd>
        </SvcLvl>
      </PmtTpInf>
      <ReqdExctnDt>
        <Dt>2026-10-23</Dt>
      </ReqdExctnDt>
      <Dbtr>
        <Nm>Acme GmbH</Nm>
        <PstlAdr>
          <TwnNm>Berlin</TwnNm>
          <Ctry>DE</Ctry>
        </PstlAdr>
      </Dbtr>
      <DbtrAcct>
        <Id>
          <IBAN>DE89370400440532013000</IBAN>
        </Id>
      </DbtrAcct>
      <DbtrAgt>
        <FinInstnId>
          <BICFI>COBADEFFXXX</BICFI>
        </FinInstnId>
      </DbtrAgt>
      <ChrgBr>SLEV</ChrgBr>
      <CdtTrfTxInf>
        <PmtId>
          <EndToEndId>INV-2026-17</EndToEndId>
        </PmtId>
        <Amt>
          <InstdAmt Ccy="EUR">1234.56</InstdAmt>
        </Amt>
        <Cdtr>
          <Nm>Supplier BV</Nm>
          <PstlAdr>
            <TwnNm>Amsterdam</TwnNm>
            <Ctry>NL</Ctry>
          </PstlAdr>
        </Cdtr>
        <CdtrAcct>
          <Id>
            <IBAN>NL91ABNA0417164300</IBAN>
          </Id>
        </CdtrAcct>
        <RmtInf>
          <Ustrd>Invoice 2026-17</Ustrd>
        </RmtInf>
      </CdtTrfTxInf>
      <CdtTrfTxInf>
        <PmtId>
          <EndToEndId>NOTPROVIDED</EndToEndId>
        </PmtId>
        <Amt>
          <InstdAmt Ccy="EUR">49.50</InstdAmt>
        </Amt>
        <Cdtr>
          <Nm>Office Supplies KG</Nm>
        </Cdtr>
        <CdtrAcct>
          <Id>
            <IBAN>DE02120300000000202051</IBAN>
          </Id>
        </CdtrAcct>
        <RmtInf>
          <Strd>
            <CdtrRefInf>
              <Tp>
                <CdOrPrtry>
                  <Cd>SCOR</Cd>
                </CdOrPrtry>
              </Tp>
              <Ref>RF18539007547034</Ref>
            </CdtrRefInf>
          </Strd>
        </RmtInf>
      </CdtTrfTxInf>
    </PmtInf>
  </CstmrCdtTrfInitn>
</Document>

Validation result

VALID 0 errors · 0 warnings

PAYRUN-2026-10-23
pain.001.001.09
Payment blocks
1
Transactions
2
Total
1284.06 EUR

No problems found. Schema, SEPA character set, totals, IBANs, addresses and references all pass.

JSON response POST /v1/validate
{
  "message_type": "pain.001.001.09",
  "kind": "credit_transfer",
  "profile": "epc",
  "valid": true,
  "error_count": 0,
  "warning_count": 0,
  "summary": {
    "message_id": "PAYRUN-2026-10-23",
    "payment_blocks": 1,
    "transactions": 2,
    "total_amount": "1284.06",
    "currency": "EUR"
  },
  "issues": []
}

A 2009 pain.001.001.03 file whose header control sum has two digits swapped. A German bank may reject the whole file for this.

pain001-v03-wrong-total.xml 1815 bytes · pain.001.001.03

Input file

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
  <CstmrCdtTrfInitn>
    <GrpHdr>
      <MsgId>OLD-2026-10-20-1</MsgId>
      <CreDtTm>2026-10-20T10:00:00</CreDtTm>
      <NbOfTxs>2</NbOfTxs>
      <CtrlSum>1248.06</CtrlSum>
      <InitgPty>
        <Nm>Acme GmbH</Nm>
        <Id><OrgId><BICOrBEI>COBADEFFXXX</BICOrBEI></OrgId></Id>
      </InitgPty>
    </GrpHdr>
    <PmtInf>
      <PmtInfId>OLD-2026-10-20-1-P1</PmtInfId>
      <PmtMtd>TRF</PmtMtd>
      <BtchBookg>true</BtchBookg>
      <NbOfTxs>2</NbOfTxs>
      <CtrlSum>1284.06</CtrlSum>
      <PmtTpInf><SvcLvl><Cd>SEPA</Cd></SvcLvl></PmtTpInf>
      <ReqdExctnDt>2026-10-23</ReqdExctnDt>
      <Dbtr>
        <Nm>Acme GmbH</Nm>
        <PstlAdr><Ctry>DE</Ctry><AdrLine>Hauptstr. 1</AdrLine><AdrLine>10115 Berlin</AdrLine></PstlAdr>
      </Dbtr>
      <DbtrAcct><Id><IBAN>DE89370400440532013000</IBAN></Id></DbtrAcct>
      <DbtrAgt><FinInstnId><BIC>COBADEFFXXX</BIC></FinInstnId></DbtrAgt>
      <ChrgBr>SLEV</ChrgBr>
      <CdtTrfTxInf>
        <PmtId><EndToEndId>INV-2026-17</EndToEndId></PmtId>
        <Amt><InstdAmt Ccy="EUR">1234.56</InstdAmt></Amt>
        <CdtrAgt><FinInstnId><BIC>INGBNL2A</BIC></FinInstnId></CdtrAgt>
        <Cdtr><Nm>Supplier BV</Nm></Cdtr>
        <CdtrAcct><Id><IBAN>NL91ABNA0417164300</IBAN></Id></CdtrAcct>
        <RmtInf><Ustrd>Invoice 2026-17</Ustrd></RmtInf>
      </CdtTrfTxInf>
      <CdtTrfTxInf>
        <PmtId><EndToEndId>NOTPROVIDED</EndToEndId></PmtId>
        <Amt><InstdAmt Ccy="EUR">49.50</InstdAmt></Amt>
        <Cdtr><Nm>Office Supplies KG</Nm></Cdtr>
        <CdtrAcct><Id><IBAN>DE02120300000000202051</IBAN></Id></CdtrAcct>
        <RmtInf><Ustrd>Order 5521</Ustrd></RmtInf>
      </CdtTrfTxInf>
    </PmtInf>
  </CstmrCdtTrfInitn>
</Document>

Validation result

INVALID 1 error · 1 warning

OLD-2026-10-20-1
pain.001.001.03
Payment blocks
1
Transactions
2
Total
1284.06 EUR

ERROR · CONTROL_SUM GrpHdr/CtrlSum The message control sum is 1248.06; the amounts add up to 1284.06.

WARNING · OLD_VERSION pain.001.001.03 is the 2009 version. Banks are moving to the 2019 versions (pain.001.001.09 / pain.008.001.08); German banks' specification limited the old version to November 2025. Use /v1/convert to migrate the file.

JSON response POST /v1/validate
{
  "message_type": "pain.001.001.03",
  "kind": "credit_transfer",
  "profile": "epc",
  "valid": false,
  "error_count": 1,
  "warning_count": 1,
  "summary": {
    "message_id": "OLD-2026-10-20-1",
    "payment_blocks": 1,
    "transactions": 2,
    "total_amount": "1284.06",
    "currency": "EUR"
  },
  "issues": [
    {
      "severity": "error",
      "rule": "CONTROL_SUM",
      "path": "GrpHdr/CtrlSum",
      "message": "The message control sum is 1248.06; the amounts add up to 1284.06."
    },
    {
      "severity": "warning",
      "rule": "OLD_VERSION",
      "path": "",
      "message": "pain.001.001.03 is the 2009 version. Banks are moving to the 2019 versions (pain.001.001.09 / pain.008.001.08); German banks' specification limited the old version to November 2025. Use /v1/convert to migrate the file."
    }
  ]
}

A pain.008.001.02 direct debit with a mistyped creditor identifier and a mandate dated in the future.

pain008-v02-errors.xml 1663 bytes · pain.008.001.02

Input file

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02">
  <CstmrDrctDbtInitn>
    <GrpHdr>
      <MsgId>DD-2026-10-20-1</MsgId>
      <CreDtTm>2026-10-20T10:00:00</CreDtTm>
      <NbOfTxs>1</NbOfTxs>
      <CtrlSum>25.00</CtrlSum>
      <InitgPty><Nm>Sportverein Musterstadt e.V.</Nm></InitgPty>
    </GrpHdr>
    <PmtInf>
      <PmtInfId>DD-2026-10-20-1-RCUR</PmtInfId>
      <PmtMtd>DD</PmtMtd>
      <NbOfTxs>1</NbOfTxs>
      <CtrlSum>25.00</CtrlSum>
      <PmtTpInf>
        <SvcLvl><Cd>SEPA</Cd></SvcLvl>
        <LclInstrm><Cd>CORE</Cd></LclInstrm>
        <SeqTp>RCUR</SeqTp>
      </PmtTpInf>
      <ReqdColltnDt>2026-11-02</ReqdColltnDt>
      <Cdtr><Nm>Sportverein Musterstadt e.V.</Nm></Cdtr>
      <CdtrAcct><Id><IBAN>DE89370400440532013000</IBAN></Id></CdtrAcct>
      <CdtrAgt><FinInstnId><BIC>COBADEFFXXX</BIC></FinInstnId></CdtrAgt>
      <ChrgBr>SLEV</ChrgBr>
      <CdtrSchmeId>
        <Id><PrvtId><Othr><Id>DE98ZZZ09999999990</Id><SchmeNm><Prtry>SEPA</Prtry></SchmeNm></Othr></PrvtId></Id>
      </CdtrSchmeId>
      <DrctDbtTxInf>
        <PmtId><EndToEndId>MEMBER-0001-2026-11</EndToEndId></PmtId>
        <InstdAmt Ccy="EUR">25.00</InstdAmt>
        <DrctDbtTx><MndtRltdInf><MndtId>M-001</MndtId><DtOfSgntr>2026-12-01</DtOfSgntr></MndtRltdInf></DrctDbtTx>
        <DbtrAgt><FinInstnId><Othr><Id>NOTPROVIDED</Id></Othr></FinInstnId></DbtrAgt>
        <Dbtr><Nm>Anna Schmidt</Nm></Dbtr>
        <DbtrAcct><Id><IBAN>DE02120300000000202051</IBAN></Id></DbtrAcct>
        <RmtInf><Ustrd>Membership November</Ustrd></RmtInf>
      </DrctDbtTxInf>
    </PmtInf>
  </CstmrDrctDbtInitn>
</Document>

Validation result

INVALID 2 errors · 1 warning

DD-2026-10-20-1
pain.008.001.02
Payment blocks
1
Transactions
1
Total
25.00 EUR

ERROR · CREDITOR_ID PmtInf[1]/CdtrSchmeId/Id/PrvtId/Othr/Id 'DE98ZZZ09999999990' is not a valid SEPA creditor identifier.

ERROR · MANDATE_DATE PmtInf[1]/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/DtOfSgntr The mandate signature date is in the future.

WARNING · OLD_VERSION pain.008.001.02 is the 2009 version. Banks are moving to the 2019 versions (pain.001.001.09 / pain.008.001.08); German banks' specification limited the old version to November 2025. Use /v1/convert to migrate the file.

JSON response POST /v1/validate
{
  "message_type": "pain.008.001.02",
  "kind": "direct_debit",
  "profile": "epc",
  "valid": false,
  "error_count": 2,
  "warning_count": 1,
  "summary": {
    "message_id": "DD-2026-10-20-1",
    "payment_blocks": 1,
    "transactions": 1,
    "total_amount": "25.00",
    "currency": "EUR"
  },
  "issues": [
    {
      "severity": "error",
      "rule": "CREDITOR_ID",
      "path": "PmtInf[1]/CdtrSchmeId/Id/PrvtId/Othr/Id",
      "message": "'DE98ZZZ09999999990' is not a valid SEPA creditor identifier."
    },
    {
      "severity": "error",
      "rule": "MANDATE_DATE",
      "path": "PmtInf[1]/DrctDbtTxInf[1]/DrctDbtTx/MndtRltdInf/DtOfSgntr",
      "message": "The mandate signature date is in the future."
    },
    {
      "severity": "warning",
      "rule": "OLD_VERSION",
      "path": "",
      "message": "pain.008.001.02 is the 2009 version. Banks are moving to the 2019 versions (pain.001.001.09 / pain.008.001.08); German banks' specification limited the old version to November 2025. Use /v1/convert to migrate the file."
    }
  ]
}

How it works

  1. Drop your pain.001.001.03 or pain.008.001.02 file into the box above to check it first.
  2. Send it to the API’s POST /v1/convert. The response is the pain.001.001.09 or pain.008.001.08 file.
  3. With return_report=true, you get JSON instead: the converted XML, the list of changes and the validation report.

How the conversion works

curl -X POST "https://<host>/v1/convert?profile=de" -H "Content-Type: application/xml" --data-binary @old.xml -o new.xml

The converted file is returned only after it has passed the 2019 schema and the SEPA rules. return_report=true returns JSON instead, with the list of changes and the validation report. Files go in the raw body, as base64 (Content-Transfer-Encoding: base64) or as a multipart field file, up to 10 MB.

Questions

Which conversions are supported?

pain.001.001.03 → pain.001.001.09 (credit transfers) and pain.008.001.02 → pain.008.001.08 (direct debits).

What if something cannot be converted?

Nothing is guessed. The result must pass the 2019 schema and the SEPA rules; if it cannot, you get a CONVERSION_NOT_POSSIBLE error instead of a file.

Can the result follow the German banks' rules?

Yes. Pass profile=de to check the converted file against DFÜ-Abkommen Anlage 3 v3.7 as well.

Need it in your own software?

The same engine is available as an API: whole files instead of a preview, every export format, automation.

SEPA & NACHA Payment File API →

Related tools

Free toolSEPA & NACHA Payment File API

pain.001 validator

Check a pain.001 or pain.008 file against the ISO 20022 schema and the EPC rules, with every problem explained.

Free toolSEPA & NACHA Payment File API

NACHA file validator

Check a NACHA ACH file record by record, with each problem's line, column and a plain explanation.

Free toolSEPA & NACHA Payment File API

CSV to NACHA

Turn a payroll or vendor CSV into a NACHA file that passes every check before it goes to the bank.