camt.053 Structure: Reading the Statement Field by Field
The camt.053 statement field by field: GroupHeader to TransactionDetails, OPBD/CLBD balance codes, the Bank Transaction Code, and where bank files diverge.
Connectivity 4 of 11 see the reading order →
Reviewed by Tan Gravam Fact-checked
On this page
camt.053 is the ISO 20022 BankToCustomerStatement — the end-of-day statement the account-servicing bank sends the account owner — and structurally it is one GroupHeader plus one or more Statement blocks, each carrying the account, a set of typed Balances, and the booked Entries, with the transaction detail nested two levels further down. If you're deciding between statement formats, that's the MT940 vs camt.053 vs BAI2 comparison; this post is for the day you've already received a camt.053 and have to make reconciliation work against it. Field by field, with the multiplicities that bite, verified against a real bank implementation guideline (Nordea's camt.053.001.02 MIG) and ISO's own code lists.
The skeleton
The message root is <BkToCstmrStmt>. Inside it, exactly one <GrpHdr> (GroupHeader) and one or more <Stmt> (Statement) blocks — [1..n], and that multiplicity is the first practical fact: one file can carry statements for many accounts. An importer that assumes one account per file works until the bank consolidates delivery, then silently drops accounts.
Here's the shape, as an illustrative skeleton built from the elements in Nordea's MIG (not a complete or valid instance):
<BkToCstmrStmt>
<GrpHdr>
<MsgId>…</MsgId> <!-- bank's unique message reference -->
<CreDtTm>…</CreDtTm>
</GrpHdr>
<Stmt> <!-- [1..n] one per account statement -->
<Id>…</Id>
<ElctrncSeqNb>…</ElctrncSeqNb>
<Acct>
<Id><IBAN>…</IBAN></Id> <!-- or <Othr> for non-IBAN accounts -->
</Acct>
<Bal>…</Bal> <!-- [1..n] typed balances -->
<Ntry> <!-- [0..n] booked entries -->
<NtryDtls> <!-- [0..n] -->
<TxDtls>…</TxDtls> <!-- [0..n] underlying transactions -->
</NtryDtls>
</Ntry>
</Stmt>
</BkToCstmrStmt>
The GroupHeader is thin on purpose: a <MsgId> the bank generates uniquely, a creation timestamp, optionally a message recipient. Everything that matters lives per statement. Within <Stmt>, the <ElctrncSeqNb> (electronic sequence number) increments with each statement sent — which gives you a free gap check: if today's number isn't yesterday's plus one, you missed a statement, and a missed statement is a silently wrong cash position. The <Acct> block identifies the account as an IBAN or, through the <Othr> branch, a domestic account number, plus currency and servicer BIC.
One more structural observation worth a sentence: the ISO type names are version-suffixed — in camt.053.001.02 the statement is an AccountStatement2, an entry is a ReportEntry2, a balance a CashBalance3. Those numbers climb with each message version, which is the concrete reason camt versions are not drop-in compatible: the types themselves change shape.
Balances: typed, repeating, and bank-dependent
<Bal> is [1..n] — a statement carries a list of balances, each one typed by a code under <Tp><CdOrPrtry><Cd>. The ISO external code set defines ten balance types:
| Code | Meaning (per the ISO external code set) |
|---|---|
| OPBD | Opening booked — book balance at the start of the reporting period; always equals the previous closing booked balance |
| CLBD | Closing booked — opening booked plus all entries booked in the period |
| OPAV | Opening available — what was at the owner's disposal at the start |
| CLAV | Closing available — what is at the owner's disposal at the end |
| ITBD | Interim booked — calculated during the business day, subject to change |
| ITAV | Interim available — the available equivalent, also intraday |
| FWAV | Forward available — funds at the owner's disposal on a specified future date |
| PRCD | Previously closed booked — the prior period's closing balance, restated |
| XPCD | Expected — booked entries plus known pending items, projecting the end-of-day balance |
| INFO | Informational only |
Each <Bal> then carries the amount (with a currency attribute), a <CdtDbtInd> of CRDT or DBIT — the sign lives in a separate element, not in the amount — and a date.
That's the textbook. The reality is that no bank sends you ten balances. Nordea's MIG allows exactly three: CLBD, OPBD, and CLAV "if reported by local system" — a phrase worth savoring, because it means even within one bank, whether you get an available balance depends on which country's back end produced the statement. The two checks I'd build into any importer regardless of bank: OPBD must equal the previous statement's CLBD (the code set's own definition says so), and OPBD plus the sum of signed entries must equal CLBD. When either fails, you have a missing statement or a broken file, and you want to know before the cash position goes out.
The Entry: what the bank actually booked
Each <Ntry> ([0..n] — a no-movement day legally produces a statement with balances and no entries) is one booked movement, and its fields are the reconciliation workhorses:
<Amt>+<CdtDbtInd>— the amount, always in the account currency in Nordea's implementation, and the credit/debit indicator. Same pattern as the balance: sign is separate.<Sts>— the entry status. Nordea sends only BOOK (booked). If a bank sends you other statuses in an end-of-day statement, filter deliberately: only booked entries belong in reconciliation.<BookgDt>vs<ValDt>— booking date and value date, both optional in the schema, both usually present. Position and interest care about value date; matching against the ledger cares about booking date. Pick per use, explicitly.<AcctSvcrRef>— the account servicer reference: the bank's own reference for the entry. When you call the bank about a statement line, this is the number their support desk can find. Store it verbatim.<NtryRef>— an entry reference, distinct from the above; optional.<BkTxCd>— mandatory, and important enough for its own section.
BkTxCd: domain, family, subfamily
Every entry carries a Bank Transaction Code, structured as three levels:
<BkTxCd>
<Domn>
<Cd>PMNT</Cd> <!-- domain: business area -->
<Fmly>
<Cd>RCDT</Cd> <!-- family: received credit transfers -->
<SubFmlyCd>ESCT</SubFmlyCd> <!-- subfamily: SEPA credit transfer -->
</Fmly>
</Domn>
</BkTxCd>
The domain is the business area — ISO's codification lists eleven: payments (PMNT), cash management (CAMT), foreign exchange (FORX), loans and deposits (LDAS), securities (SECU), derivatives (DERV), commodities (CMDT), precious metal (PMET), trade services (TRAD), account management (ACMT), and an extended domain (XTND). The family narrows within it — under PMNT you'll meet received credit transfers (RCDT), issued credit transfers (ICDT), the direct-debit pair (RDDT/IDDT), cheques, cards, counter transactions. The subfamily is the specific flavor: under PMNT/RCDT alone the list runs from ESCT (SEPA credit transfer) through DMCT (domestic credit transfer), XBCT (cross-border credit transfer), SALA (payroll), STDO (standing order) to BOOK (internal book transfer). ISO publishes the full set of permitted combinations as a spreadsheet — 1,567 rows in the 30 November 2025 codification.
Why care? Because this is the field statement automation branches on. When an electronic bank statement run in SAP decides which posting rule applies to a line, the external transaction code it keys on is, for a camt statement, this code. A clean BkTxCd means the entry can be interpreted without parsing text; that's most of camt.053's advantage over MT940 in practice.
Now the reality, in three parts. First, the code list includes its own escape hatches: OTHR ("other") and NTAV ("not available") exist as families and subfamilies, and an entry classified PMNT/OTHR/OTHR has told you almost nothing — the classification quality you actually receive is a property of the bank's back end, not of the standard. Second, the <Domn> block is [0..1] in the schema — a structurally valid entry can arrive without the ISO code at all (the structure has room for proprietary codes instead; Nordea's MIG commits to ISO codes only, which is exactly the kind of commitment you want to see in writing). Third, two banks can classify the same economic event under different combinations. The audit step I'd never skip on a statement-onboarding project: pull a month of real statements and histogram the BkTxCd combinations per bank before writing posting rules. The distribution is never what the standard suggests.
Entry vs EntryDetails vs TransactionDetails: the batch problem
This nesting is the part of camt.053 that most reconciliation implementations get wrong first. Three levels:
<Ntry>— what the bank booked. One amount, one line on the account.<NtryDtls>—[0..n]detail containers inside the entry.<TxDtls>—[0..n]transaction detail blocks inside each container, each with its own references (<Refs>), amount details (<AmtDtls>), related parties (<RltdPties>), and remittance information (<RmtInf>).
For a single payment booked individually, the levels collapse: one entry, one details block, one transaction, and Nordea's MIG notes the transaction amount is "same amount as on Entry level". Boring, correct, easy.
The interesting case is batch booking: the bank books one collective entry — say, one debit for an entire pain.001 payment run, or one credit for a bundle of incoming ACH items — and the individual payments exist only as multiple <TxDtls> blocks under that single entry. Now the entry amount is a sum, the entry's references are batch-level, and everything you need to clear individual open items lives at transaction level. Reconciliation logic written against <Ntry> alone will match the happy single-payment path and fall over on the first collective booking, which in most companies is the main path for payables.
Nordea's identification table makes the dependency explicit: the customer's own reference (<InstrId>) appears "when single booking applies", while the payment-order reference (<PmtInfId>) "may only appear when batch booking applies". Which references you receive, and at which level, is a function of the booking arrangement you agreed with the bank — it's negotiated, not discovered.
References: which one comes back to you
A camt.053 carries a small zoo of references, and knowing who generated each is the whole game:
| Reference | Level | Who created it |
|---|---|---|
<MsgId> | GroupHeader | The bank — unique per message |
<AcctSvcrRef> | Entry | The bank — its own reference for the booking |
<PmtInfId> | TransactionDetails | You — the payment-information (debit batch) level of your instruction; batch booking |
<InstrId> | TransactionDetails | You — your instruction reference; single booking |
<EndToEndId> | TransactionDetails | You — set in pain.001, carried through the chain |
<EndToEndId> deserves the emphasis. It's the reference you assigned per payment in the pain.001, and its return on the statement is what closes the loop: instruction out, statement in, matched by a key you control. That's the cleanest auto-reconciliation mechanism the format offers — and it's [0..1] in the schema, so whether it actually survives the round trip through a given bank and clearing channel is a test case, not an assumption. Alongside the references, <TxDtls> carries the related parties (debtor and creditor accounts, ultimate parties) and unstructured remittance lines (<Ustrd>, up to 140 characters each, repeating). One detail from Nordea's MIG that belongs in a divergence museum: <UltmtDbtr> is in the schema with the comment "currently not supported by any countries." The element exists; the data doesn't.
Where bank implementations diverge
Everything above sharpens into one working rule: the ISO schema tells you what can appear; the bank's MIG tells you what will. The divergence shows up in predictable places:
- Balance subset. Ten types in the code set; two or three in a given bank's file, with availability balances often conditional on the local back end.
- Reference population. Which of InstrId / PmtInfId / EndToEndId you get, and at which level, depends on booking arrangements and the local clearing.
- BkTxCd quality. ISO combinations vs proprietary codes vs OTHR/NTAV — per bank, sometimes per country within one bank.
- Optional elements that stay empty. Schema-present, never populated (see UltmtDbtr above).
- Version spread. The ISO catalogue is at camt.053.001.14; camt.053.001.02 — defined in the 2009 payments maintenance cycle — is still widely delivered, with MIGs for it maintained as recently as 2023. Two banks on "camt.053" may be on different message versions with differently-shaped types.
This is the same conclusion the format comparison reaches from one level up — camt.053 from Bank A and Bank B are not identical — but at field level you can see why, and plan for it: collect each bank's MIG, diff it against the elements your importer and matching logic actually consume, and test with production statements per bank before go-live. On the SAP side, where the imported statement lands in the FEBKO/FEBEP tables, the treasury tables reference covers what the import writes and where to look when a line misbehaves.
What usually goes wrong
- Reconciling at entry level. Works for single bookings, breaks on the first batch. Write matching against TxDtls, and treat the entry as the sum it is.
- Assuming one account per file.
<Stmt>is[1..n]. Loop. - Ignoring the sequence number. ElctrncSeqNb gaps are missed statements — and missed statements are invisible until the position is wrong.
- Trusting EndToEndId without testing it. Optional in the schema; verify each bank returns it before your match rules depend on it.
- Writing posting rules from the standard instead of the data. Histogram real BkTxCd values per bank first; the standard's 1,567 combinations are the menu, not the meal.
The structure itself is genuinely good — typed balances, a mandatory classification code, references at the level they belong. The craft is in the gap between the schema and each bank's file, and that gap is documented: it's called the MIG, and reading it is the cheapest reconciliation improvement you'll ever make.
See also bank statement formats: MT940 vs camt.053 vs BAI2, electronic bank statement processing in SAP, and the ISO 20022 migration from MT to MX.
Primary sources
Element names, XML tags and multiplicities verified against a camt.053.001.02 implementation guideline; the ISO catalogue is at BankToCustomerStatementV14. Later versions rename types and restructure some blocks — verify against your bank's MIG and version.
- Nordea — Corporate eGateway MIG camt.053.001.02 BankToCustomerStatementV02 (v1.9, 2023)
- ISO 20022 — External Code Sets (ExternalBalanceType1Code and BTC code sets)
- ISO 20022 — Bank Transaction Code combinations (codification, 30 Nov 2025)
- ISO 20022 — Message definitions catalogue (camt.053 BankToCustomerStatement)
Frequently asked questions
4
What is the difference between Entry, EntryDetails and TransactionDetails in camt.053?
An Entry (Ntry) is one booked movement on the account — one line the bank actually posted, with its own amount, status, dates and Bank Transaction Code. EntryDetails (NtryDtls) sits inside an entry and holds one or more TransactionDetails (TxDtls) blocks, each describing an underlying transaction with its references, parties and remittance information. For a single payment there is one of each. For a batch — one collective debit covering many payments — there is one entry and many TransactionDetails, which is why reconciliation logic must be written against the detail level, not just the entry level.
What do the balance codes OPBD, CLBD and CLAV mean on a camt.053 statement?
They are ISO 20022 balance type codes. OPBD is the opening booked balance — the book balance at the start of the reporting period, which always equals the previous statement's closing book balance. CLBD is the closing booked balance — the opening booked balance plus everything booked during the period. CLAV is the closing available balance — what is actually at the account owner's disposal on that date, which can differ from the booked figure. The external code set defines ten balance types in total, but each bank sends only the subset its systems support, so check the bank's implementation guide rather than the standard.
What is the Bank Transaction Code (BkTxCd) in camt.053?
BkTxCd is the mandatory classification on every statement entry, structured as domain, family and subfamily. The domain is the business area (PMNT for payments, FORX for foreign exchange, and nine others), the family narrows it (RCDT is received credit transfers), and the subfamily is specific (ESCT is a SEPA credit transfer). ISO publishes the permitted combinations as an external code list — about 1,500 of them. It's the field statement-driven automation keys on: posting rules and reconciliation logic branch on the code, so an entry classified OTHR or NTAV ('other', 'not available') is an entry your automation can't do much with.
Which version of camt.053 do banks actually send?
Older than you'd expect. The ISO catalogue currently lists camt.053.001.14, but camt.053.001.02 — defined back in the 2009 payments maintenance cycle — is still what many bank channels deliver; Nordea's implementation guideline for it was still being maintained in 2023. Versions are not drop-in replacements: type names and structures change between them, so an importer built for one version needs checking against another. Ask each bank which version and which implementation guide applies to your channel, and treat that document as the contract.