A SEPA payment carries a 35-character end-to-end reference. The MT940 statement line that reports it has room for 16. Most reconciliation bugs I have chased on bank statements come from that gap, or from what each bank decided to do about it.
The pages that rank for "MT940 vs camt.053" mostly list the tags, say XML is richer, and repeat the claim that Swift killed MT940 in November 2025. It didn't. This guide covers what you hit when you actually parse both: the exact :61: grammar, the :86: dialects, the schema change between camt.053 versions that breaks naive parsers, batch bookings, and which open-source parsers are still maintained.
What Is the Difference Between MT940 and camt.053?
Both are end-of-day bank statements. MT940 is a Swift FIN message: tagged lines of text with fixed length limits. camt.053 is the ISO 20022 XML equivalent, BankToCustomerStatement. Each has an intraday sibling and a notification sibling:
| Purpose | Swift MT | ISO 20022 | US equivalent |
|---|---|---|---|
| End-of-day statement | MT940 | camt.053 | BAI2 (prior day) |
| Intraday report | MT942 | camt.052 | BAI2 (current day) |
| Debit/credit advice | MT900 / MT910 | camt.054 | none standard |
| Bank-to-bank (nostro) statement | MT950 | camt.053 | none standard |
The practical difference is granularity. An MT940 statement line describes a booking. A camt.053 entry describes a booking and can list every underlying transaction inside it, each with its own references, parties and remittance text. If your bank books 312 direct debit collections as one credit, MT940 gives you one line. camt.053 can give you one entry with 312 transaction details.
Is MT940 Being Discontinued? The Swift Timeline in 2026
Here is what is true as of October 2026, based on J.P. Morgan's ISO 20022 FAQ and RedCompass Labs' deadline summary (Swift's own roadmap documents sit behind a login):
- November 2025: coexistence ended for cross-border payment instructions in CBPR+ (MT103, MT202). Statements were not part of that cut-off.
- November 2026: J.P. Morgan lists end of coexistence for MT101 on FIN. Multi-instruction MT101s are rejected; single ones are converted to pain.001.
- November 2027: Swift users must be able to receive camt.052, camt.053 and camt.054.
- November 2028 (SR 2028): planned end of coexistence for MT9xx statements on FIN. Swift will not translate MT9xx into camt for you.
MT940 Format: How to Read the :61: Statement Line
An MT940 message is a sequence of tags:
| Tag | Content | Format |
|---|---|---|
:20: | Transaction reference | 16x |
:25: | Account identification | 35x |
:28C: | Statement number / sequence | 5n[/5n] |
:60F: or :60M: | Opening balance (first / intermediate) | 1!a6!n3!a15d |
:61: | Statement line, repeating | see below |
:86: | Information to account owner | 6*65x |
:62F: or :62M: | Closing balance (final / intermediate) | 1!a6!n3!a15d |
:64: | Closing available balance | 1!a6!n3!a15d |
:65: | Forward available balance | 1!a6!n3!a15d |
The :61: line is where people write bad regexes. Its grammar is 6!n[4!n]2a[1!a]15d1!a3!c16x[//16x][34x], which unpacks to:
1. Value date, YYMMDD.
2. Entry date, MMDD, optional. If absent, assume the value date. Watch the year boundary: a value date of 261231 with entry date 0102 booked in January.
3. Debit/credit mark: C, D, RC (reversal of credit) or RD (reversal of debit). Some banks also send EC/ED for expected items.
4. Funds code, one letter, optional. ING defines it as the third letter of the currency code, so a USD account can produce a D straight after a C. A regex that treats [CD]{1,2} greedily will eat it.
5. Amount, up to 15 characters including a comma as the decimal separator. No sign; the sign is the mark.
6. Transaction type: N or F plus three characters, e.g. NTRF, NMSC, NCHG.
7. Customer reference, 16x, mandatory. NONREF when there is none.
8. Bank reference, // plus up to 16x.
9. Supplementary details, up to 34x on the next line.
Bank specifications commonly cite a 2,000-character limit per FIN MT940. Long statements are split across messages: the first opens with :60F:, the middle ones use :60M:/:62M:, and only the last closes with :62F:. Each :60M: must equal the previous message's :62M:. If you only check :60F: against yesterday's :62F:, a missing middle page goes unnoticed.
The :86: Field: German, Dutch and Other Dialects
:86: is six lines of 65 characters, 390 in total, and its content is whatever the bank decides. Two dialects cover most of Europe.
Dutch style (ING, Rabobank, ABN AMRO): slash-delimited codes. ING puts the literal text EREF in the :61: customer reference and moves the real 35-character end-to-end ID into :86::
/EREF/INV-2026-0418-ACME/IREF/.../CNTP/NL91ABNA0417164300/ABNANL2A/ACME BV//REMI/USTD//Invoice 2026-0418/
Returns arrive as /RTRN/AC04/.
?-numbered subfields of 27 characters: ?00 booking text, ?20 to ?29 and ?60 to ?63 for purpose text, ?30 BIC, ?31 IBAN, ?32/?33 name, ?34 text key. Inside the purpose text sit SEPA keywords: EREF+, KREF+, MREF+, SVWZ+ (the remittance line), ABWA+.
The 27-character chunks break words and references mid-string, so you must concatenate ?20 to ?29 before searching for EREF+. I have seen invoice numbers split across ?21 and ?22 fail a matcher that looked at subfields one at a time.
camt.053 XML Structure: Entries and Transaction Details
The tree, trimmed to what reconciliation uses:
BkToCstmrStmt
GrpHdr/MsgId
Stmt
Id, ElctrncSeqNb, LglSeqNb, StmtPgntn(PgNb, LastPgInd)
Acct
Bal (OPBD, CLBD mandatory; CLAV, ITBD, ITAV optional)
Ntry (one booking)
Amt, CdtDbtInd, Sts, BookgDt, ValDt, AcctSvcrRef, BkTxCd
NtryDtls
Btch/NbOfTxs
TxDtls (0..n underlying transactions)
Refs (MsgId, InstrId, EndToEndId, UETR)
RltdPties, RmtInf (Ustrd, Strd), RtrInf
Limits that matter, checked against the published XSDs: EndToEndId, AcctSvcrRef and NtryRef are Max35Text. Ustrd is 140 characters per occurrence but can repeat. AddtlNtryInf is 500. Amounts are xs:decimal with up to five fraction digits, always non-negative; direction lives only in CdtDbtInd (CRDT/DBIT). If you store amounts in minor units, the ISO 4217 minor units guide covers the currency exponent trap.
The Bank Transaction Code is a three-level tree: Domn/Cd (e.g. PMNT), Fmly/Cd (RCDT, received credit transfer) and SubFmlyCd (ESCT, SEPA credit transfer). It is far more useful for routing than MT940's four-character NTRF.
camt.053.001.02 vs camt.053.001.08: What Breaks Your Parser
Many banks have moved from version 02 to 08 (Deutsche Bank, NatWest Bankline and the Bank of England's CHAPS reporting all use 08; Nordea's guide was still on 02 in late 2023). The changes look cosmetic and are not:
| Element | v02 | v08 |
|---|---|---|
| Entry status | (enum) | (choice of Cd or Prtry) |
| UETR | absent | Refs/UETR |
| Party wrapper | | |
| Return info type | ReturnReasonInformation10 | PaymentReturnReason5 |
A parser that reads Sts as text gets an empty string on v08 and quietly treats every entry as unknown status. Check the namespace (urn:iso:std:iso:20022:tech:xsd:camt.053.001.08) and dispatch on it. Newer versions exist too; Circle's Mint statements use camt.053.001.13. The ISO 20022 pain.001 vs pacs.008 guide explains how the version suffixes work.
The Same Payment in MT940 and camt.053
A €1,250 SEPA credit, ING-style MT940:
:61:2610151015C1250,00NTRFEREF//2610150012345
:86:/EREF/INV-2026-0418-ACME/REMI/USTD//Invoice 2026-0418/NAME/ACME BV
The same booking in camt.053.001.08:
2610150012345
1250.00
CRDT
BOOK
2026-10-15
2026-10-15
2610150012345
PMNT RCDT ESCT
INV-2026-0418-ACME
ACME BV
Invoice 2026-0418
In MT940 the end-to-end ID survives only because ING chose to put it in :86:. Another bank might truncate it to 16 characters in the :61: reference, or drop it. In camt.053 it has a typed field.
MT940 vs camt.053 vs BAI2: Comparison
| MT940 | camt.053 (v08) | BAI2 | |
|---|---|---|---|
| Syntax | Tagged text, 65-char lines | XML, schema-validated | Comma-delimited records ending / |
| Main region | Europe, global corporates | EU, UK, CBPR+ | US |
| Reference length | 16x in :61:, rest in :86: | 35 per typed field | Bank and customer ref in record 16 |
| Remittance | Within 390-char :86: | 140 per Ustrd, repeatable, plus structured Strd | Record 88 continuation, free text |
| Batch detail | No | Yes, TxDtls per item | No |
| Transaction codes | 4 chars (NTRF) | Domain/Family/Sub-family | 3-digit type codes |
| Amount format | Comma decimal, no sign | Decimal point, sign in CdtDbtInd | Implied decimals, no point |
| Return reasons | Bank-specific text | ISO code in RtrInf/Rsn/Cd | Bank-specific |
NatWest's Bankline offers all three, and its translation guide maps them field by field. If you integrate a UK bank and a US bank, expect to run all three parsers.
Where Bank Statement Reconciliation Fails
Batch bookings. One:61: line for 312 collections means you reconcile against a total and need a second file (often camt.054) for the items. In camt.053 the TxDtls amounts must sum to the Ntry amount; assert it.
Fees moved inside transactions. KPMG's write-up of German migrations notes banks that reported charges as separate MT940 lines began netting them inside one camt transaction. Rules matched on the old fee lines stopped firing.
Returns. A returned SEPA payment shows up as a new credit with a reason code: AC04 account closed, AM04 insufficient funds, MD06 refund requested by the payer. In camt.053 you get the code and usually the original end-to-end ID; in MT940 you get whatever the bank writes. The SEPA Direct Debit Core vs B2B guide covers the refund windows behind MD06.
Duplicates and gaps. Banks resend statements. Key each entry on AcctSvcrRef or NtryRef scoped to the account, and track ElctrncSeqNb for gaps the way you would :28C:. Balances have no dedupe key, so recompute rather than trust.
Pagination. StmtPgntn/LastPgInd tells you when a camt statement is complete. Don't book a day as closed until you have seen true. This matters if you run regulated reconciliations; the CASS 15 reconciliation guide explains why.
Which Open-Source MT940 and camt.053 Parsers Are Maintained?
Checked on GitHub on 16 October 2026:
| Library | Language | Formats | Status |
|---|---|---|---|
| wolph/mt940 | Python | MT940 | v5.1.1, September 2026 |
| prowide-core / prowide-iso20022 | Java | MT and MX | Active, October 2026 |
| genkgo/camt | PHP | camt.052/053/054 v02 to v08 | 2.10.3, August 2025 |
| railslove/cmxl | Ruby | MT940 | Updated May 2026 |
| svenstaro/mt940-rs | Rust | MT940 | Updated September 2026 |
| fruitl00p/php-mt940 | PHP | MT940 | Stale since 2024 |
| webschik/mt940-js | JavaScript | MT940 | Archived |
None of the MT940 libraries understands every :86: dialect. Budget for a per-bank :86: adapter on top of whichever you pick.
What This Means for Teams Reconciling Bank Statements in the UK and EU
1. Ask each bank for camt.053.001.08 now. It gives you end-to-end IDs, batch detail and ISO return codes. Get a sample file before you sign anything; bank variants differ.
2. Dispatch on namespace, not file extension. Support v02 and v08 side by side, and treat Sts as a choice.
3. Keep the MT940 parser. Banks will keep producing it after 2028 on non-FIN channels. Add one :86: adapter per bank and test it with real files containing returns and batch bookings.
4. Key on the bank reference plus account, then match on the end-to-end ID. Never match on amount and date alone; same-amount payments on the same day are common in payroll and collections.
5. Validate balances every file: opening balance equals yesterday's closing, entries sum to the movement, and intermediate pages chain. Alert on any break before matching starts.
I am Tom Wang, and the integrations I have seen go wrong rarely failed on XML versus text. They failed because someone assumed the reference they sent would come back intact. Check what each bank actually returns before writing a single matching rule. The Stripe vs Adyen reconciliation guide covers the PSP side of the same problem.