Build an ISO 20022 pain.001 Credit Transfer XML
Skill: Convert a payment batch into a pain.001.001.09 customer credit transfer initiation XML
Region: Global (cross-border ISO 20022 standard)
Category: Payments — ISO 20022 pain.001 Customer Credit Transfer Initiation
Does: Takes a batch of outgoing payments (CSV / JSON / pasted rows) and produces an ISO 20022 pain.001.001.09 CustomerCreditTransferInitiation XML for upload to a bank, covering the Group Header → Payment Information → Credit Transfer Transaction hierarchy, IBAN/BIC, SEPA vs cross-border usage, charge bearer, and control-sum rules.
Schema version: ISO 20022 pain.001.001.09 (also the basis of the SEPA SCT 2023 rulebook / pain.001.001.09 CGI-MP profile)
The AI assembles the message from your data; it does not connect to a bank. The exact version (
.03for legacy SEPA,.09for the 2023 ISO 20022 migration / CBPR+ flows) and any bank-specific usage rules differ per channel — confirm the schema variant and your bank's implementation guidelines (EBA CLEARING, Swift CBPR+, or the CGI-MP profile) before upload.
When this applies
- SEPA Credit Transfer (SCT) — euro payments inside SEPA, BIC optional (IBAN-only),
ChargeBearer=SLEV. - Cross-border / high-value payments over correspondent banking (CBPR+),
ChargeBearer=SHAR/DEBT/CRED. - Bulk supplier / payroll runs uploaded to a corporate banking portal or host-to-host channel.
Conversion procedure
- Read the source — accept CSV/TSV (one row per payment), a JSON array, or pasted key–value rows. Each payment needs: creditor name, creditor IBAN, (optional) creditor BIC, amount, currency, remittance info, and an end-to-end reference.
- Extract the debtor (payer) once — name, IBAN, BIC/financing institution, and the requested execution date for the whole batch.
- Group into Payment Information blocks — one
<PmtInf>per (debtor account + requested execution date + payment method + service level). Most batches need a single<PmtInf>. - Normalize — IBANs uppercased and stripped of spaces; amounts to 2 decimals with a
.separator; dates toYYYY-MM-DD; currency to ISO 4217; BICs 8 or 11 chars uppercase. - Compute control sums —
CtrlSumat group level = Σ all transaction amounts;CtrlSumat each<PmtInf>= Σ its own transactions;NbOfTxs= transaction counts. Recompute; never copy a printed total. - Emit the output — one
<CstmrCdtTrfInitn>document, using the worked example as the template. - Validate — work through the checklist.
Source → pain.001 field map
| From the source | → Target element |
|---|---|
| Message ID (you assign, unique) | GrpHdr/MsgId |
| Creation timestamp | GrpHdr/CreDtTm |
| Total transaction count | GrpHdr/NbOfTxs |
| Sum of all amounts | GrpHdr/CtrlSum |
| Initiating party name | GrpHdr/InitgPty/Nm |
| Batch reference | PmtInf/PmtInfId |
Payment method (always TRF) |
PmtInf/PmtMtd |
Service level (SEPA for SCT) |
PmtInf/PmtTpInf/SvcLvl/Cd |
| Requested execution date | PmtInf/ReqdExctnDt/Dt |
| Debtor name / IBAN / BIC | Dbtr/Nm, DbtrAcct/Id/IBAN, DbtrAgt/FinInstnId/BICFI |
| Charge bearer | PmtInf/ChrgBr |
| Per-payment reference | CdtTrfTxInf/PmtId/EndToEndId |
| Amount + currency | Amt/InstdAmt (Ccy attribute) |
| Creditor BIC (cross-border) | CdtrAgt/FinInstnId/BICFI |
| Creditor name / IBAN | Cdtr/Nm, CdtrAcct/Id/IBAN |
| Remittance information | RmtInf/Ustrd (or Strd/CdtrRefInf for structured) |
Document structure
Document
└── CstmrCdtTrfInitn
├── GrpHdr (MsgId, CreDtTm, NbOfTxs, CtrlSum, InitgPty)
└── PmtInf ... (one per debtor account + exec date)
├── PmtInfId, PmtMtd (TRF), NbOfTxs, CtrlSum
├── PmtTpInf/SvcLvl/Cd (SEPA)
├── ReqdExctnDt/Dt
├── Dbtr / DbtrAcct / DbtrAgt
├── ChrgBr (SLEV | SHAR | DEBT | CRED)
└── CdtTrfTxInf ... (one per payment)
├── PmtId/EndToEndId
├── Amt/InstdAmt
├── CdtrAgt (BIC — cross-border)
├── Cdtr / CdtrAcct/Id/IBAN
└── RmtInf/Ustrd
GrpHdr/NbOfTxs and GrpHdr/CtrlSum aggregate all <PmtInf> blocks; each <PmtInf> also carries its own NbOfTxs/CtrlSum.
Code tables
Charge bearer (ChrgBr)
| Code | Meaning |
|---|---|
SLEV |
Following service level (SEPA SCT — shared, each pays own bank) |
SHAR |
Shared — debtor pays sending charges, creditor pays receiving |
DEBT |
Borne by debtor (OUR) |
CRED |
Borne by creditor (BEN) |
Service level (SvcLvl/Cd)
| Code | Meaning |
|---|---|
SEPA |
SEPA Credit Transfer scheme |
PRPT |
EBA priority (instant-adjacent) |
NURG |
Non-urgent (cross-border) |
Calculation rules
GrpHdr/CtrlSum= Σ everyInstdAmtacross all<PmtInf>blocks, 2 decimals.- Each
PmtInf/CtrlSum= Σ its own transactions'InstdAmt. NbOfTxsis an exact integer count (group level = total;PmtInflevel = its own).- SEPA amounts must be in
EUR; a single SCT instruction is capped per the scheme (no amount cap in SCT, but instant SCT Inst ≤ €100 000 historically — confirm current limit). - Recompute both control sums from the transactions; flag any mismatch against a source-provided batch total.
Worked example (end-to-end)
Input — CSV payment batch
creditor_name,creditor_iban,amount,currency,reference,remittance
Acme Supplies Ltd,DE89370400440532013000,1500.00,EUR,INV-7781,Invoice INV-7781
Bravo Services SARL,FR1420041010050500013M02606,845.50,EUR,INV-7782,Invoice INV-7782
Debtor: Northwind GmbH, IBAN DE21500500009876543210, BIC MARKDEF1100, execute 2026-06-15.
After extraction + normalization (intermediate)
NbOfTxs = 2, CtrlSum = 1500.00 + 845.50 = 2345.50.
Output — pain.001.001.09 XML
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.09">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>NWND-20260612-0001</MsgId>
<CreDtTm>2026-06-12T09:30:00</CreDtTm>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>2345.50</CtrlSum>
<InitgPty>
<Nm>Northwind GmbH</Nm>
</InitgPty>
</GrpHdr>
<PmtInf>
<PmtInfId>NWND-RUN-20260615</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>2345.50</CtrlSum>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>
<Dt>2026-06-15</Dt>
</ReqdExctnDt>
<Dbtr>
<Nm>Northwind GmbH</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>DE21500500009876543210</IBAN>
</Id>
</DbtrAcct>
<DbtrAgt>
<FinInstnId>
<BICFI>MARKDEF1100</BICFI>
</FinInstnId>
</DbtrAgt>
<ChrgBr>SLEV</ChrgBr>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>INV-7781</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="EUR">1500.00</InstdAmt>
</Amt>
<Cdtr>
<Nm>Acme Supplies Ltd</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE89370400440532013000</IBAN>
</Id>
</CdtrAcct>
<RmtInf>
<Ustrd>Invoice INV-7781</Ustrd>
</RmtInf>
</CdtTrfTxInf>
<CdtTrfTxInf>
<PmtId>
<EndToEndId>INV-7782</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="EUR">845.50</InstdAmt>
</Amt>
<Cdtr>
<Nm>Bravo Services SARL</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>FR1420041010050500013M02606</IBAN>
</Id>
</CdtrAcct>
<RmtInf>
<Ustrd>Invoice INV-7782</Ustrd>
</RmtInf>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>
Normalization notes: de89 3704 0044 0532 0130 00 → DE89370400440532013000; 1500 → 1500.00; execution date 15/06/2026 → 2026-06-15.
Validation checklist
-
xmlnsnamespace matches the exact schema version your bank expects (pain.001.001.09vs.03) -
MsgIdunique;CreDtTmis a valid ISO 8601 dateTime -
GrpHdr/NbOfTxs= total transactions;GrpHdr/CtrlSum= Σ allInstdAmt - Each
PmtInf/NbOfTxsandCtrlSumreconcile with its own transactions - All IBANs uppercase, no spaces, pass the mod-97 check; BICs 8/11 chars
-
ChrgBrcorrect for the rail (SLEVfor SEPA SCT) - Amounts have exactly 2 decimals and a valid
Ccy - Validated against the official ISO 20022 XSD and your bank's usage guidelines
Last updated: 2026-06-12 — confirm the active pain.001 version (e.g. .09), SEPA SCT rulebook year, and your bank's CGI-MP / CBPR+ usage rules before upload.