★ GitHub Connect

Import a bank statement into AI: from PDF mess to clean data in one message

Somewhere on your disk there is a folder of bank statement PDFs you have never opened twice. The data in them answers every question you have about your own money, and until recently, extracting it meant an evening with Excel and regret. Vision models ended that evening. But "AI can read my statement" and "AI imported my statement correctly" are different claims, and the distance between them is exactly two failure modes.

TL;DR
  • Modern AI reads CSV and PDF statements reliably. The parsing is solved; the bookkeeping is not.
  • Failure mode 1: silent invention. A model transcribing 200 rows will occasionally round, merge or invent one. Always reconcile against the statement total.
  • Failure mode 2: duplicates. Re-import the same file, or overlap a statement with hand-logged expenses, and your totals quietly double.
  • Fix both with two rules: every row carries the bank's own reference id, and every import ends with a checksum against the statement.

Why statements beat bank APIs (for most people, still, in 2026)

Open banking is real in the EU and UK, and where it works it is the better answer. But coverage is uneven: US access runs through commercial aggregators, many banks worldwide expose nothing, and every aggregator supports a finite list. The statement file is the universal fallback: every bank on earth produces one, it needs no consent flow, and it contains the bank's own canonical record of what happened. If your tooling handles statements well, no bank is unsupported.

Failure mode 1: the model invents a number

Ask an LLM to transcribe a 200-row PDF and it will get 199 rows right with total confidence, which is precisely the problem: you cannot see which row is wrong. Long transcriptions drift: merged rows, a rounded amount, an off-by-one date at a page break.

The defense is an accounting idea, not an AI idea: reconciliation. Every statement states its own total (or opening and closing balance). After import, the sum of imported rows must equal that total, computed by a database, not by the model that did the transcription. A mismatch means a specific row is wrong, and the difference tells you roughly where to look.

Whatever tool you use, never accept an import without a checksum line: "187 rows, net -2,431.90 EUR, matches statement". If your tool cannot say that sentence, add the check yourself: ask the AI for the imported sum and compare against the statement footer.

Failure mode 2: the duplicate spiral

The subtler killer. Duplicates arrive from three directions:

The fix is boring and absolute: stable ids. Banks print a reference for every transaction; a correct import carries that reference on every row, making re-imports no-ops instead of disasters. This is the same idempotency idea YNAB formalized for CSV imports years ago, and any AI-era tool that skipped it has re-learned why it exists. For the manual-overlap case, the right behavior is a merge that keeps your category and note while attaching the bank's reference, not a delete.

See the difference yourself. Same June statement, dropped a second time by accident:

[drops revolut-june.pdf again] import this Imported 156 rows into Revolut EUR. June total is now -4,863.80 EUR.

No error, no warning, a confident summary. Every transaction now exists twice, June spending doubled, and every budget shows an overspend. You will discover this weeks later, and unpicking duplicates by hand is worse than the original Excel evening.

[drops revolut-june.pdf again] import this Imported 0 of 156 rows: all 156 already exist (same bank reference). June total unchanged: -2,431.90 EUR.

The re-import is a no-op because every row carries the bank's own reference. Drop the file five times, nothing changes. This is the behavior to demand from any tool before trusting it with history.

What a good import looks like end to end

[drops revolut-june.pdf] import this into my EUR account Imported 143 of 156 rows into Revolut EUR. Skipped 13: 11 already imported (same bank reference), 2 merged with your manual entries (kept your categories). Net for June: -2,431.90 EUR, matches the statement. Largest new expense: 380.00 EUR, flights.

Every sentence in that reply is a safety property: counted rows, named skip reasons, merge behavior, reconciled total. This flow is what we built MyFinance MCP around (open source, MIT, free while in beta): your AI client parses the file, the server enforces ids, dedup and reconciliation, and SQL does every sum. But the properties are tool-agnostic; hold any workflow, including a spreadsheet one, to the same standard.

Practical tips that save an hour each

Where this approach ends

Statement import is batch catch-up, not real-time awareness: you learn about June in July. If your bank is reachable by read-only open banking (EU/UK), a daily sync closes that gap and demotes statements to a backup plan. And if you need audited books for a business, none of this replaces accounting software; it feeds it.

Try it this week

  1. Download last month's statement from your main account, CSV if available.
  2. Pick a tool that stores rows with bank references and reconciles totals. (Ours connects to Claude or ChatGPT in under a minute; bring your own if you prefer, just interrogate its dedup.)
  3. Drop the file in, read the import summary line by line, verify the total against the statement footer.
  4. Drop the same file in again. If anything imports twice, stop using that tool.

That folder of PDFs is the most complete dataset anyone has ever kept about you. This is the year it starts working for you instead of against you.

Last updated: July 20, 2026. Product names are trademarks of their respective owners. MyFinance MCP is an independent open-source project by Rteam.

Track money inside the AI you already use.

Free and open source. It works with Claude, ChatGPT and any MCP client.