Supported bank statement formats

CAMT, PAIN.001, MT940/MT942, BAI2, OFX/QFX, CSV and PDF — every dialect a bank might send you, normalised into one auditable model.

Reconciliation rarely fails because the numbers are wrong. It fails because every bank, payment rail and legacy back-office system speaks a slightly different dialect. One relationship bank sends you a pristine ISO 20022 CAMT file; another still exports a SWIFT MT940; your US cash-management provider drops a BAI2 lockbox file; a personal-finance tool hands you OFX; a regional bank e-mails a CSV with its own column order; and somewhere in the pile is a PDF that someone scanned on a photocopier. Written naively, you end up maintaining a bespoke parser — and a bespoke set of bugs — for each one.

bankstatementparser exists to end that. It reads all of these formats and normalises them into a single, typed, auditable Transaction model, so the code you write downstream — reconciliation, ledger posting, reporting — is written once and works everywhere. Under the bonnet there are two complementary pipelines. Structured, machine-readable formats take the deterministic path: explicit rules map known fields to known attributes, repeatably and testably, with no guesswork. Unstructured PDFs take a local model fallback: a configurable, on-device language model extracts the transactions, with a multimodal vision model handling scans. The sections below explain what each format is, who emits it, and how the toolkit handles it.

Privacy by default. Structured statements are parsed entirely on your machine with deterministic code. The PDF fallback uses a local model — Ollama by default — so your financial data never leaves your infrastructure unless you deliberately configure an external provider. There are no trackers, no telemetry and no phone-home.

CAMT (ISO 20022)

CAMT is the family of cash-management messages defined by the ISO 20022 standard — the modern, XML-based lingua franca that banks and market infrastructures are steadily adopting worldwide. The name is short for Cash Management, and the three members you will meet most often are:

camt.052 — intraday account report

A report of account activity during the business day, used for near-real-time visibility of balances and movements before the day is closed off.

camt.053 — end-of-day statement

The definitive bank-to-customer statement for a completed business day, with opening and closing balances and the full set of booked entries. This is the message most reconciliation processes are built around.

camt.054 — debit/credit notification

A notification of individual debits or credits — often batch payouts or collections — that lets you match settlement to the underlying instructions.

Because CAMT files are well-formed XML with a published schema, bankstatementparser handles them on the deterministic path: it walks the document structure, reads the entry, amount, currency, value date and counterparty elements, and maps them straight onto the unified model. The result is exact and reproducible, with no interpretation involved.

PAIN.001 — customer credit transfer initiation

PAIN is the ISO 20022 Payments Initiation family, and pain.001 is the customer credit transfer initiation message: the instruction a business sends to its bank to make one or many outbound payments. Where CAMT tells you what happened to an account, PAIN.001 records what you asked the bank to do. Including it means the toolkit can reason about both sides — instructions issued and movements booked — which is invaluable when you are matching payment runs against subsequent statements.

Like CAMT, PAIN.001 is structured XML, so it is parsed deterministically. Payment amounts, currencies, requested execution dates, remittance information and creditor details are read directly from their defined elements and folded into the same Transaction shape as every other format.

SWIFT MT940 & MT942

Before ISO 20022, and still ubiquitous today, the SWIFT MT message types carried statement data between banks and their corporate customers. They are flat, tag-delimited text files rather than XML — each line begins with a field tag such as :20:, :25:, :60F: or :61: that identifies what follows.

MT940 — end-of-day statement

MT940 is the customer statement message: opening balance, a sequence of statement lines, and a closing balance for a completed period. It remains one of the most common formats corporate treasuries receive from their banks. bankstatementparser reads MT940 natively in the core library, parsing each field tag and translating the balances and statement lines into the unified model.

MT942 — interim transaction report

MT942 is the intraday or interim counterpart — it reports movements that have occurred so far within the current period, before the end-of-day MT940 is produced. It is handled through the dedicated bankstatementparser-loader-mt942 package, which reads the interim report and loads its entries into exactly the same Transaction model as everything else, so intraday and end-of-day data sit side by side.

BAI2

BAI2 is the cash-management reporting format defined by the Bank Administration Institute, and it is the workhorse of corporate banking in the United States. It is a structured, record-oriented text format used for balance and transaction reporting and for lockbox files, organised into a hierarchy of file, group, account and transaction records identified by numeric type codes.

bankstatementparser handles BAI2 through the dedicated bankstatementparser-loader-bai2 package. The loader parses the record hierarchy and its type and status codes deterministically, resolving balances and individual transactions, and feeds them into the shared Transaction model. That means a US cash-management BAI2 file and a European CAMT file end up in precisely the same shape for downstream processing.

OFX / QFX

Open Financial Exchange (OFX) is a data-exchange format used widely for downloading account activity from banks and into personal-finance and accounting software. QFX is a closely related variant produced by some consumer tools. Both encode statement transactions — dates, amounts, types, memos and identifiers — in a tagged, SGML/XML-style structure.

Because OFX and QFX are structured, they take the deterministic path. bankstatementparser reads the transaction list, resolves each posting's amount, date and description, and maps it onto the unified model. This makes it straightforward to bring exports from online banking portals and finance apps into the same reconciliation pipeline as your institutional formats.

CSV — bank exports

CSV is the lowest common denominator: almost every bank and portal can export a statement as comma-separated values, but no two agree on the columns, their order, the date format or how debits and credits are signed. That flexibility is exactly what makes naive CSV parsing so brittle.

bankstatementparser addresses this with configurable column mapping. You tell it which columns correspond to the date, description, amount, balance and any reference fields, and it maps each row into the shared Transaction model. Once a mapping is defined for a given bank's export, the process is deterministic and repeatable — a new file in the same layout simply works.

PDF — digital & scanned

PDFs are where the deterministic approach reaches its limit. A bank statement PDF has no reliable machine-readable schema: the transactions are laid out visually, and two banks that both send “a PDF” may structure their pages completely differently. This is where the local model fallback comes in.

Digital PDFs

For digital (text-bearing) PDFs, the toolkit extracts the text and passes it to a configurable local language model to identify and structure the transactions. By default this is Ollama running on your own machine, but because the integration is built on LiteLLM you can point it at any LiteLLM-supported provider if you choose to.

Scanned & photocopied statements

For scanned or photocopied statements — where there is no extractable text, only an image — a local multimodal vision model reads the page directly and recovers the transactions. This lets the same toolkit cope with everything from a clean bank-issued PDF to a crooked photocopy.

Your data stays on your machine. The default configuration runs both the language model and the vision model locally, so financial statements are never transmitted anywhere. An external provider is used only if you explicitly configure one. Exact model choices and defaults are configurable, and the descriptions here are illustrative of how the fallback is intended to be run.

One model out

Whatever the input — a camt.053 statement, an MT940, a BAI2 lockbox file, an OFX export, a mapped CSV or a scanned PDF — the output is always the same unified Transaction model. Each record carries the essentials in a consistent, typed form: booking and value dates, signed amounts and currencies, counterparties, and references. Balances and statement metadata come through alongside.

Because everything converges on that one shape, your downstream work is written once. Feed the transactions into a reconciliation routine, post them to a ledger, or hand them to the bankstatementparser-writer-xlsx package to produce clean, formatted Excel workbooks for analysts and auditors. The format the bank happened to send stops being your problem.