Bank Statement Formats & Reconciliation Research
Research for Phase 6 (bank reconciliation): parsing bank statements (camt.053, MT940) and matching statement lines against ledger cash movements. All findings below are sourced from web research performed on 2026-08-05; nothing is from memory.
1. ISO 20022 camt.053 — BankToCustomerStatement
camt.053 is the ISO 20022 XML end-of-day bank account statement (the "MX" successor to MT940). It is part of the Bank-to-Customer Cash Management message set maintained by the ISO 20022 Registration Authority (iso20022.org).
1.1 Document root and namespace
- Root element:
<Document>with a version-specific default namespace:urn:iso:std:iso:20022:tech:xsd:camt.053.001.NN(e.g.camt.053.001.02,camt.053.001.08). The version is identified via the XML namespace, so the parser must read the namespace, not assume one. - Inside:
<BkToCstmrStmt>(BankToCustomerStatement), containing one<GrpHdr>and one or more<Stmt>blocks (one per account/period).
1.2 Structure (elements the AIR parser must handle)
Document @xmlns = urn:iso:std:iso:20022:tech:xsd:camt.053.001.NN
└── BkToCstmrStmt
├── GrpHdr
│ ├── MsgId unique message id
│ └── CreDtTm file creation timestamp (ISO 8601)
└── Stmt [1..n] one per account statement
├── Id statement id
├── ElctrncSeqNb electronic sequence number (optional)
├── CreDtTm statement creation timestamp
├── Acct
│ ├── Id/IBAN or Id/Othr/Id account identifier (IBAN or domestic)
│ └── Ccy account currency (ISO 4217)
├── Bal [1..n] balances
│ ├── Tp/CdOrPrtry/Cd OPBD=opening booked, CLBD=closing booked,
│ │ CLAV=closing available, OIBD/CIBD=interim (multi-page)
│ ├── Amt @Ccy decimal amount, currency as XML attribute
│ ├── CdtDbtInd CRDT | DBIT (sign of the balance)
│ └── Dt/Dt balance date
└── Ntry [0..n] statement entries (transactions)
├── NtryRef entry reference (optional)
├── Amt @Ccy ALWAYS positive decimal; currency attribute mandatory
├── CdtDbtInd CRDT (money in) | DBIT (money out) — gives the sign
├── RvslInd true if this entry reverses a previous one (optional)
├── Sts BOOK (booked) | PDNG (pending) | INFO
├── BookgDt/Dt (or /DtTm) booking (posting) date
├── ValDt/Dt (or /DtTm) value date
├── AcctSvcrRef bank's own reference (optional)
├── BkTxCd bank transaction code (Domn/Fmly/SubFmlyCd or Prtry/Cd)
├── NtryDtls [0..n]
│ ├── Btch batch info (NbOfTxs, TtlAmt) when 1 entry = n transactions
│ └── TxDtls [0..n] underlying transactions
│ ├── Refs/EndToEndId payer-assigned end-to-end reference (invoice/PO ref)
│ ├── Refs/TxId, InstrId, MndtId
│ ├── AmtDtls InstdAmt / TxAmt (useful for FX)
│ ├── RltdPties Dbtr / Cdtr names and accounts
│ └── RmtInf/Ustrd unstructured remittance info (free text)
│ RmtInf/Strd structured remittance (creditor reference etc.)
└── AddtlNtryInf free-text description of the entryKey semantics:
Amtcarries no sign; direction comes exclusively fromCdtDbtInd(CRDT= credit to the account = money received;DBIT= money out).- The currency is the mandatory
Ccyattribute onAmt. - One
Ntrymay aggregate many underlying transactions (batch/lump-sum entries):NtryDtls/Btch+ repeatedTxDtls. This is the structural basis for one-to-many reconciliation matching. EndToEndId(max 35 chars) travels unaltered from the payment initiation (pain.001) to the statement — it is the best deterministic matching key.
1.3 Version differences (brief)
- Common versions in the wild:
.02(2009 base, still the most widely delivered by banks, e.g. Nordea, Dutch banks),.06,.08(2019 — the CBPR+/SEPA-aligned version banks are converging on),.10/.11/.13(latest, Feb 2025). - Newer versions mostly add optional fields without removing existing ones;
the structural core (
GrpHdr/Stmt/Bal/Ntry) is stable across versions. Notable mechanical difference: in.02Stsis a simple code (<Sts>BOOK</Sts>); in.08+it becomes a complex element (<Sts><Cd>BOOK</Cd></Sts>). Party identification blocks also gain structure in.08+. - Practical parser strategy (used by open-source parsers): parse
namespace-tolerantly, target the common core, handle the
Stsshape difference.
Sources: iso20022.org Message Definition Report Part 2 (Bank-to-Customer Cash Management), Payments Canada camt.053.001.08 usage guideline, Nordea camt.053.001.02 standard, ValidateFin structural guide, darko-mijic camt.053 parser spec (URLs in §7).
2. MT940 — SWIFT Customer Statement Message
MT940 is the legacy SWIFT FIN "MT" end-of-day customer statement: a line/tag-based text format. Still extremely widespread in bank connectivity (EBICS, host-to-host, e-banking exports) even though it is deprecated by SWIFT (see §3).
2.1 Tag structure
| Tag | Name | Format | Notes |
|---|---|---|---|
:20: |
Transaction Reference Number | 16x | Sender's reference for the message |
:25: |
Account Identification | 35x | Account number (option P adds BIC) |
:28C: |
Statement Number/Sequence | 5n[/5n] | e.g. 151/1 |
:60F: |
Opening Balance (First) | 1!a6!n3!a15d | D/C mark + date YYMMDD + currency + amount |
:61: |
Statement Line | see §2.2 | Repeats per transaction |
:86: |
Information to Account Owner | 6*65x | Optional; up to 6 lines × 65 chars; must follow its :61: |
:62F: |
Closing Balance (Final) | 1!a6!n3!a15d | Same layout as :60F: |
:60M:/:62M: |
Intermediate opening/closing balances | same | Used when a statement spans multiple messages |
:64:/:65: |
Closing available / forward available balance | same layout | Optional |
Constraint: a :86: must be preceded by a :61: and belongs to it; when a
period spans several messages, all but the last carry :62M: and the last
carries :62F:.
2.2 The :61: statement line — full format specification
:61: 6!n [4!n] 2a [1!a] 15d 1!a3!c 16x [//16x] [34x]
│ │ │ │ │ │ │ │ └─ supplementary details (optional, new line)
│ │ │ │ │ │ │ └─ bank reference (optional, after //)
│ │ │ │ │ │ └─ customer reference (16x; NONREF if none)
│ │ │ │ │ └─ transaction type code: 1 letter + 3 chars
│ │ │ │ │ S103 = via SWIFT MT103, NTRF = non-SWIFT transfer,
│ │ │ │ │ NMSC = misc, NCHK = cheque, NDDT = direct debit...
│ │ │ │ └─ amount: max 15 digits, COMMA as decimal separator,
│ │ │ │ no thousands separators, ALWAYS UNSIGNED
│ │ │ └─ funds code (optional, 3rd char of currency)
│ │ └─ debit/credit mark: D | C | RD (reversal of debit) | RC (reversal of credit)
│ └─ entry (booking) date MMDD (optional; year inferred from value date)
└─ value date YYMMDDKey semantics:
- Amount is unsigned; the D/C mark gives direction (D = debit = money out,
C = credit = money in;
RD/RCmark reversals). - Decimal separator is a comma (
1150,00), never a dot; the currency is NOT on the:61:line — it comes from the:60F:/:62F:balance lines. - Value date is
YYMMDD(2-digit year → pivot logic needed); entry date isMMDDwith the year inferred from the value date (beware year boundaries). - The customer reference (
16x) is the counterpart of camt'sEndToEndId, but is oftenNONREF; the free-text:86:line then carries the useful description (bank-proprietary sub-formats exist inside:86:, e.g. German/GVC/and?20-style subtags — treat:86:as opaque text in v1). - Integrity check available to the parser:
:60F: balance ± Σ(:61: lines) = :62F: balance— AIR should verify this.
Sources: Paiementor MT940 detailed analysis, National Bank of Canada MT940 user guide, Citi MT940 export guide, Huntington developer portal (URLs in §7).
3. Adoption status: camt.053 vs MT940 (MT→MX migration)
- 22 November 2025: SWIFT ended MT/ISO 20022 coexistence for cross-border payment instruction messages (MT103/MT202 retired for FI-to-FI traffic).
- Cash-management / reporting messages (MT9xx) got an extended timeline: MT940/MT942/MT950/MT900/MT910 are deprecated and no longer maintained by SWIFT but not yet withdrawn; their removal in favour of camt.052/camt.053/camt.054 is being phased in roughly 2027–2028, and major banks tell clients they must be able to receive camt messages by November 2027.
- Practical consequence (2026): both formats are current reality. camt.053 is the strategic/current standard; MT940 remains the most widely deployed corporate statement format worldwide (bank portals, ERP integrations, EBICS). → AIR must parse both, normalizing into one internal model (§6).
Sources: SWIFT ISO 20022 programme pages, J.P. Morgan and Citi migration FAQs, RedCompass Labs 2026 deadline analysis, PaymentExpert on the Nov-2025 cutover (URLs in §7).
4. Bank reconciliation matching practice
How mainstream systems match statement lines to ledger (book) cash entries:
- Exact match first: same amount, same currency, same/near date. This is the universal baseline (QuickBooks Online "matches", Xero "suggested matches").
- Date tolerance windows: book date and bank date rarely coincide (cheques clear days later; card settlements lag 1–3 days). Treasury/ERP tools (e.g. Oracle Fusion reconciliation) expose configurable date tolerance rules; date tolerances exist mainly for instruments with clearing lag.
- Amount tolerance: used for FX rounding differences or bank fees embedded in the statement line. QuickBooks does not natively do tolerance-based matching; Oracle-class treasury tools do (with a write-off/adjustment posting for the difference). Xero handles the fee case via "adjustments" during reconciliation.
- Reference matching: strongest deterministic signal — cheque number,
invoice number in remittance text, and in camt.053 the
EndToEndId/AcctSvcrRef. Xero bank rules can condition on bank text fields, direction ("Received"/"Spent") and amount; a rule sets contact/account/tax code. - One-to-many / many-to-one (batch) matching: one bank deposit = many
customer receipts (or one payroll debit = many payslips). Xero supports
"Match > multiple items"; QuickBooks Online is weak here natively; camt.053
expresses it structurally (
NtryDtls/Btch+ severalTxDtls). Treasury reconciliation engines support 1:1, 1:n, n:1 and n:m rule tiers, applied in priority order (exact reference → exact amount+date → amount+date window → aggregate/batch), each with confidence scoring. - Output convention: after matching, both sides' residues are reported — unmatched statement lines (bank has it, books don't: missing entry / fee / fraud) and unmatched ledger entries (books have it, bank doesn't: outstanding cheque / deposit in transit). This two-sided exception report is the classical bank reconciliation statement.
Sources: Oracle Fusion tolerance-rule docs, Xero reconciliation guides, QuickBooks Online reconciliation guides (URLs in §7).
5. Aggregator APIs (future ingestion frontends)
5.1 Plaid (/transactions/sync, /transactions/get)
JSON transaction objects; key fields:
amount— decimal number. Sign convention (Plaid docs): "Positive values when money moves out of the account; negative values when money moves in." I.e. a debit-card purchase is positive, a deposit/refund is negative — the inverse of a naive signed-bank-balance convention. Two decimal places.iso_currency_code(ISO 4217; null whenunofficial_currency_codeis used).date(YYYY-MM-DD; posting date for posted transactions, occurrence date for pending), plusauthorized_date/datetime/authorized_datetime.name(raw description) andmerchant_name(Plaid-enriched, cleaner).pending(bool — details may change at settlement; the posted transaction arrives with a newtransaction_idand apending_transaction_idlink).transaction_id(unique, case-sensitive),payment_channel(online/in store/other),personal_finance_category.
⚠ Plaid delivers amount as a JSON number → the AIR parser must decode it
via decimal-preserving parsing (e.g. json.loads(..., parse_float=Decimal)),
never through binary floats.
5.2 Flinks (Canadian aggregator, /GetAccountsDetail)
Transactions array per account; each item:
{
"Date": "2025-01-31",
"Code": null,
"Description": "PAYROLL - Stripe Paycheck",
"Debit": 1000.4,
"Credit": 1500.25,
"Balance": 5105.6,
"Id": "94584aed-7c98-42a4-9836-9f8557db63f5"
}- Direction is expressed by separate
Debit/Creditfields (one populated, the other null in real responses), not a signed amount — a third sign convention to normalize.Balanceis the running balance after the transaction;Idis Flinks' unique transaction id. - Same JSON-number caveat as Plaid: parse into Decimal, never float.
Sources: Plaid Transactions API reference, Flinks GetAccountsDetail docs (URLs in §7).
6. Example fixtures (small, structurally correct)
Both fixtures describe the same statement: CAD account, opening balance 25,000.00, one outgoing supplier payment of 1,150.00 on 2026-08-01, one incoming customer payment of 3,449.93 on 2026-08-04, closing balance 27,299.93 (25,000.00 − 1,150.00 + 3,449.93 = 27,299.93 ✓).
6.1 camt.053 (version 053.001.02)
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">
<BkToCstmrStmt>
<GrpHdr>
<MsgId>AIR-STMT-20260805-001</MsgId>
<CreDtTm>2026-08-05T06:00:00</CreDtTm>
</GrpHdr>
<Stmt>
<Id>STMT-2026-0151</Id>
<ElctrncSeqNb>151</ElctrncSeqNb>
<CreDtTm>2026-08-05T06:00:00</CreDtTm>
<Acct>
<Id><Othr><Id>00112233445</Id></Othr></Id>
<Ccy>CAD</Ccy>
</Acct>
<Bal>
<Tp><CdOrPrtry><Cd>OPBD</Cd></CdOrPrtry></Tp>
<Amt Ccy="CAD">25000.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt><Dt>2026-07-31</Dt></Dt>
</Bal>
<Bal>
<Tp><CdOrPrtry><Cd>CLBD</Cd></CdOrPrtry></Tp>
<Amt Ccy="CAD">27299.93</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt><Dt>2026-08-04</Dt></Dt>
</Bal>
<Ntry>
<NtryRef>BKREF001</NtryRef>
<Amt Ccy="CAD">1150.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt><Dt>2026-08-01</Dt></BookgDt>
<ValDt><Dt>2026-08-01</Dt></ValDt>
<BkTxCd><Prtry><Cd>NTRF</Cd></Prtry></BkTxCd>
<NtryDtls>
<TxDtls>
<Refs><EndToEndId>INV-2026-0042</EndToEndId></Refs>
<RmtInf><Ustrd>PAYMENT ACME INC INVOICE INV-2026-0042</Ustrd></RmtInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Supplier payment Acme Inc.</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>BKREF002</NtryRef>
<Amt Ccy="CAD">3449.93</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt><Dt>2026-08-04</Dt></BookgDt>
<ValDt><Dt>2026-08-04</Dt></ValDt>
<BkTxCd><Prtry><Cd>NTRF</Cd></Prtry></BkTxCd>
<NtryDtls>
<TxDtls>
<Refs><EndToEndId>E2E-SALE-7781</EndToEndId></Refs>
<RmtInf><Ustrd>CUSTOMER CUST 123 SALE 7781</Ustrd></RmtInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Customer payment, sale 7781</AddtlNtryInf>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>(For .08+ fixtures the only mechanical change in these fields is
<Sts><Cd>BOOK</Cd></Sts> and the namespace suffix.)
6.2 MT940
:20:AIR-STMT-0805
:25:BOFCCAM2/00112233445
:28C:151/1
:60F:C260731CAD25000,00
:61:2608010801D1150,00NTRFINV-2026-0042//BKREF001
:86:PAYMENT ACME INC INVOICE INV-2026-0042
:61:2608040804C3449,93NTRFE2E-SALE-7781//BKREF002
:86:CUSTOMER CUST 123 SALE 7781
:62F:C260804CAD27299,93Reading :61:2608010801D1150,00NTRFINV-2026-0042//BKREF001:
value date 260801 (2026-08-01), entry date 0801, D = debit, amount
1150,00 (comma decimal), transaction type NTRF, customer reference
INV-2026-0042, bank reference BKREF001.
7. Design decisions for AIR
- Common internal model. Both parsers (and future Plaid/Flinks ingesters)
produce the same
BankTransaction:date(booking date, ISO date; value date kept separately if present)amount— signed decimal serialized as a string (positive = money in to the account, negative = money out; AIR convention, normalized from CdtDbtInd / D-C mark / Plaid inverse sign / Flinks Debit-Credit columns)currency(ISO 4217; fromAmt@Ccyin camt, from:60F:in MT940)description(fromAddtlNtryInf/RmtInf/Ustrdor:86:)reference(fromEndToEndId/NtryRef/:61:customer+bank refs;NONREFnormalized to null)- plus provenance: source format, statement id, raw line/entry.
- Amounts are never floats. camt/MT940 amounts are parsed from text into
Decimal; MT940 comma decimals converted textually (1150,00→1150.00); aggregator JSON parsed withparse_float=Decimal. - Statement integrity check at parse time: opening balance + Σ signed
entries must equal closing balance (
:60F:/:62F:,OPBD/CLBD); mismatch is a compiler-grade diagnostic, not a warning. - Matching algorithm (v1): match = amount + currency exact, with a
configurable date tolerance window (default e.g. ±3 days, policy-driven
via ALSL, never hard-coded); reference/
EndToEndIdequality is used first as a higher-priority deterministic tier and as a tie-breaker when several candidates share amount+date. One-to-many (batch) matching deferred to a later iteration but the model keepsTxDtlsmultiplicity so it stays possible. - Two-sided residue reporting: the reconciliation result lists matched pairs and unmatched items on both sides (unmatched bank lines, unmatched ledger entries), mirroring standard reconciliation-statement practice.
- Version-tolerant camt parser: read the namespace to detect the version,
target the stable core (§1.2), handle the
.02vs.08Stsshape. - Both formats are required (§3): camt.053 is strategic, MT940 remains ubiquitous until at least 2027-2028.
8. Sources (all consulted 2026-08-05)
camt.053 / ISO 20022
- ISO 20022 MDR Part 2 — Bank-to-Customer Cash Management (iso20022.org): https://www.iso20022.org/sites/default/files/2020-12/ISO20022_MDRPart2_BankToCustomerCashManagement_2020_2021_v1_ForSEGReview.pdf
- Payments Canada — Usage Guideline camt.053.001.08: https://www.payments.ca/sites/default/files/Bank to customer statement V08 (camt.053.001.08)(pdf).pdf
- Nordea — camt.053.001.02 Account Statement Standard: https://www.nordea.com/en/doc/caar-camt-053-001-02-account-statement-standard.pdf
- Betaalvereniging Nederland — IG Bank-to-Customer Statement camt.053: https://www.betaalvereniging.nl/wp-content/uploads/2026/03/IG-Bank-to-Customer-Statement-CAMT-053-v1-1.pdf
- ValidateFin — Reading a camt.053 bank statement: https://validatefin.com/en/blog/camt053-bank-statement
- darko-mijic — iso-20022-camt-053-parser spec: https://github.com/darko-mijic/iso-20022-camt-053-parser/blob/main/docs/iso20022-camt-053-spec.md
- Huntington Developer Portal — CAMT.053: https://developer.huntington.com/enterprisepayments/docs/camt053
MT940
- Paiementor — SWIFT MT940 Customer Statement detailed analysis: https://www.paiementor.com/swift-mt940-customer-statement-detailed-analysis/
- National Bank of Canada — MT940/MT101 user guide: https://www.nbc.ca/content/dam/bnc/outils-apps/entreprises/guides/user-guide-mt940-mt101.pdf
- Citi Handlowy — SWIFT MT940 Export User Guide: https://www.citibank.pl/poland/files/SWIFT_MT940_Export_User_Guide_EN.pdf
- Huntington Developer Portal — SWIFT MT940: https://developer.huntington.com/enterprisepayments/docs/swift-mt-940
- Danske Bank — MT940 with structured :86: https://danskeci.com/-/media/pdf/danskeci-com/swift-mt/reconciliation/mt940_structured.pdf
MT → MX migration
- SWIFT — ISO 20022 for Financial Institutions: https://www.swift.com/standards/iso-20022/iso-20022-financial-institutions-focus-payments-instructions
- J.P. Morgan — ISO 20022 Migration guidance: https://www.jpmorgan.com/insights/payments/fx-cross-border/iso-20022-migration
- Citi — ISO 20022 Migration FAQ: https://www.citibank.com/tts/sa/iso-20022-migration/assets/docs/ISO-20022-FAQs.pdf
- RedCompass Labs — ISO 20022 deadlines in 2026 onward: https://www.redcompasslabs.com/insights/what-now-iso-20022-deadlines-in-2026-onwards/
- PaymentExpert — Swift's ISO 20022 cutover (Nov 2025): https://paymentexpert.com/2025/11/21/swifts-iso-20022-cutover-the-end-of-mt-and-a-20-year-promise/
- ING — FAQ Swift ISO 20022: https://www.ingwb.com/en/service/payments-and-collections/swift-iso20022/faq-swift-iso-20022
Reconciliation practice
- Oracle Fusion Cloud Financials — Overview of Tolerance Rules: https://docs.oracle.com/en/cloud/saas/financials/25d/fairp/overview-of-tolerance-rules.html
- FHP Accounting — Xero bank reconciliation rules & cash coding: https://fhpaccounting.co.uk/xero-bank-reconciliation-like-a-pro-master-rules-cash-coding-and-error-prevention-techniques/
- The IQ Suite — Bank reconciliation in QuickBooks Online / Xero guides: https://bankreconciler.app/blogQuickBooksReconciliation , https://bankreconciler.app/blogXeroReconciliation
Aggregator APIs
- Plaid — Transactions API reference: https://plaid.com/docs/api/products/transactions/
- Flinks — /GetAccountsDetail: https://docs.flinks.com/api/connect/endpoints/account-linking/get-accounts-detail
- Flinks — Data types in GetAccountsDetail: https://help.flinks.com/support/solutions/articles/43000705311-data-types-in-getaccountsdetail
End of research note — AIR project — Simon-Pierre Boucher — contact@spboucher.ai