Parse an MT940 Statement into Reconciliation Data
Skill: Convert a SWIFT MT940 customer statement into structured reconciliation data
Region: Global (SWIFT FIN standard)
Category: Banking — SWIFT MT940 Customer Statement Message
Does: Takes a SWIFT MT940 end-of-day customer statement (the tag-based text format) and extracts a flat, postable reconciliation dataset — the :20: / :25: / :28C: / :60F: / :61: / :86: / :62F: tags, transaction-type (SWIFT) codes, and opening/closing-balance continuity checks.
Schema version: SWIFT MT940 (FIN Customer Statement; Category 9)
The AI parses and structures the statement; it does not connect to your bank. MT940
:86:narrative formatting is bank-specific (German banks use structured?20–?29subfields; others use free text). Always reconcile the opening + entries against the closing balance before posting.
When this applies
- Daily cash application and bank reconciliation from legacy SWIFT statements.
- Banks/regions that still deliver MT940 rather than ISO 20022 camt.053.
- Feeding an ERP/treasury system that imports MT940.
Parsing procedure
- Read the source — an MT940 text block. A file may hold several statements; split on each
:20:transaction-reference tag. - Header tags —
:20:transaction reference,:25:account identification,:28C:statement/sequence number. - Opening balance
:60F:(or:60M:intermediate) — parseD|Cmark, dateYYMMDD, currency, amount (comma decimal). - Statement lines
:61:— value dateYYMMDD, optional entry dateMMDD,D|C(orRD/RCreversal) mark, amount, transaction-type code (N/S/F+ 3-char code), customer & bank references. - Information
:86:— narrative tied to the preceding:61:; extract counterparty name, IBAN, and remittance (parse?-subfields if present). - Closing balance
:62F:(or:62M:) — same layout as:60F:. - Normalize — comma decimal
1500,00→1500.00;YYMMDD→YYYY-MM-DD; sign each amount (Cpositive,Dnegative; reversals flip). - Reconcile — opening + Σ signed
:61:amounts must equal:62F:; flag any gap. - Emit — a structured JSON reconciliation dataset, per the worked example.
MT940 tag → field map
| Tag | Meaning | → Output field |
|---|---|---|
:20: |
Transaction reference | statement.reference |
:25: |
Account identification | account.id |
:28C: |
Statement / sequence number | statement.number |
:60F: |
Opening booked balance | balances.opening (+ date, ccy) |
:61: |
Statement line | entries[] (date, amount, type) |
:86: |
Line narrative | entries[].counterparty, .remittance |
:62F: |
Closing booked balance | balances.closing |
:64: |
Closing available balance | balances.available |
Statement-line :61: layout
:61:YYMMDD[MMDD]<mark><amount><type-code><cust-ref>//<bank-ref>
│ │ │ │ │ │ └ account-servicing ref
│ │ │ │ │ └ customer reference
│ │ │ │ └ N/S/F + 3-char transaction type code
│ │ │ └ amount (comma decimal)
│ │ └ C | D | RC | RD (credit/debit, Rx = reversal)
│ └ optional entry date (MMDD)
└ value date (YYMMDD)
Code tables
Debit/Credit mark (:60F:/:61:/:62F:)
| Mark | Meaning |
|---|---|
C |
Credit |
D |
Debit |
RC |
Reversal of credit |
RD |
Reversal of debit |
Transaction type identifier (:61:)
| Prefix | Meaning |
|---|---|
N |
SWIFT transaction type code follows (e.g. NTRF, NDDT, NCHG) |
S |
Identifies an MT message type as the source |
F |
First advice / non-SWIFT |
Common N codes: NTRF transfer, NDDT direct debit, NCHG charges, NINT interest, NRTI returned item.
Calculation rules
- Comma is the decimal separator in MT940:
1.234,56→1234.56. - Signed amount:
C→ positive,D→ negative;RC/RDflip the sign of the original. - Reconciliation invariant:
:60F: amount + Σ signed :61: amounts = :62F: amount. Mismatch ⇒ flag (often a parsing error in:86:-split lines). - Statement continuity: the
:60F:of one statement should equal the prior:62F:(same account/currency).
Worked example (end-to-end)
Input — MT940 statement
:20:STMT260611
:25:DE21500500009876543210
:28C:00115/001
:60F:C260611EUR10000,00
:61:2606110611C1500,00NTRFINV-7781//BANKREF001
:86:166?20Invoice INV-7781?32ACME SUPPLIES LTD?31DE89370400440532013000
:62F:C260611EUR11500,00
Output — reconciliation dataset (JSON)
{
"account": { "id": "DE21500500009876543210", "currency": "EUR" },
"statement": { "reference": "STMT260611", "number": "00115/001" },
"balances": { "opening": 10000.00, "closing": 11500.00 },
"entries": [
{
"valueDate": "2026-06-11",
"entryDate": "2026-06-11",
"amount": 1500.00,
"typeCode": "NTRF",
"customerRef": "INV-7781",
"bankRef": "BANKREF001",
"counterparty": "ACME SUPPLIES LTD",
"counterpartyIban": "DE89370400440532013000",
"remittance": "Invoice INV-7781"
}
],
"reconciliation": { "expectedClosing": 11500.00, "balances": true }
}
Normalization notes: 10000,00 → 10000.00; value date 260611 → 2026-06-11; :86: ?20→remittance, ?31→counterparty IBAN, ?32→counterparty name; reconcile 10000.00 + 1500.00 = 11500.00.
Validation checklist
- Multi-statement files split on each
:20: -
:60F:opening and:62F:closing balances parsed with correct D/C sign - Each
:61:line: value date, mark, amount (comma decimal), type code, references -
:86:narrative mapped to the preceding:61:(bank-specific?-subfields handled) - Amounts signed; reversals (
RC/RD) flip the sign - opening + Σ entries = closing (discrepancy flagged)
- Statement continuity: this
:60F:= prior:62F:for the same account
Last updated: 2026-06-12 — confirm your bank's :86: narrative convention (structured ?-subfields vs free text) and transaction-type code set before posting.