The bank reconciliation matcher: payments and invoices, matched without typing a row
A workflow that reads your bank statement and closes the invoices it already paid
Version history
Bank reconciliation is the single largest consumer of non-advisory bookkeeping hours: the AICPA's 2025 practice economics survey puts it at an average 11.3 hours per client per month for firms doing the work by hand, and even a one-account small business runs 45 minutes to several hours a month just ticking off which payments landed. None of that time is bookkeeping. It's matching a euro amount on a screen to a euro amount on an invoice, twice, for every payment you ever receive.
The problem
You send an invoice. Weeks later, money appears in your bank account. Somewhere in your head — or worse, in a spreadsheet — you have to connect the two: was that €840 the graphic design invoice from March, or the March retainer, or both halves of a split payment? Multiply that by every payment you get in a month and it is a real, recurring chore, not a one-off. The mid-market answer is bank-feed accounting software — Xero's reconciliation runs $16-70+/month depending on tier, QuickBooks Online sits in similar territory — which does exactly this matching for you, as long as your invoicing also lives inside their walls. If you already keep your ledger in Firefly III and your invoices in Invoice Ninja (two blueprints we've published separately), paying a third SaaS tool just to bridge the two makes no sense. This blueprint builds the bridge instead.
The architecture
CSV or CAMT.053 via REST API
└──────────┬──────────┘
▼
[ Firefly III (self-hosted) — the ledger ]
imports the statement daily via Data Importer, no bank API needed
▼ new deposit appears
[ n8n — the matcher ]
├─ exact match: amount + invoice number in description → mark paid, tag transaction
├─ ambiguous: amount matches 2+ open invoices, no reference → local AI compares
│ the payer name against your client list, flags its best guess for a nod
└─ no match: left untouched, visible as unreconciled in Firefly III
The matcher never guesses on money. Only certainty auto-closes an invoice — everything else waits for you.
The order matters. Deterministic matching (exact amount plus an invoice number your invoicing tool already put in the payment reference) handles the majority of payments for free, with no model in the loop at all — it's string and number comparison. A local model only gets called for the leftover cases where the bank's payer-name field is mangled ("J LIEFOOGHE CONSULT" instead of your client's registered name) and two invoices happen to share an amount. That's the 10-20% tail, not the whole job, which is why this stays fast and cheap to run even on modest hardware.
Tool choices — and why
Firefly III (AGPL-3.0, 24.1k GitHub stars, active) is the ledger. It's completely self-hosted, never phones home, and ships a REST JSON API that covers almost every part of the app — reading transactions, updating tags, the works. If you've already built our money-dashboard blueprint on Firefly III, this reuses that same instance; there's nothing new to stand up here.
Firefly III Data Importer (AGPL-3.0, 794 stars, actively maintained — v2.3.2, 19/04/2026) is the piece that gets your bank statement in without touching a bank API at all. It reads CSV, CAMT.052 and CAMT.053 files directly. That last format matters more than it used to: as of November 2025, CAMT.053 (ISO 20022) became the mandatory bank-statement standard across the EU and Switzerland, replacing the older MT940 format — so if your bank is European, you can now export a clean, structured statement rather than wrestling with a CSV whose columns move every time the bank redesigns its portal. This also sidesteps the open-banking API churn that's hit this space before (GoCardless's free Bank Account Data API shut down in mid-2025) — a plain file export can't be deprecated out from under you.
Invoice Ninja (Elastic License v2, source-available, free to self-host for your own business — 9.7k stars, active, v5.13.22, 08/05/2026) holds your invoices and exposes a REST API with a documented "mark paid" action, so the matcher can close an invoice the moment it finds its payment — no manual click needed on your end.
n8n (Sustainable Use License — fair-code, free for self-hosted internal business use — 197.7k stars, active) is the glue: a scheduled trigger reads new Firefly III transactions, a Code node does the amount/reference comparison, HTTP Request nodes call back into both APIs. No separate matching library needed — a few lines of JavaScript in n8n's own Code node handle exact matching; nothing here needs a paid service.
Ollama (MIT license, actively maintained, widely deployed) runs the fallback name-comparison step locally, only for the ambiguous cases. Bank payer names are the one piece of this workflow that's genuinely messy text, and that's the one place a small local model earns its keep — everything else is exact-match arithmetic that doesn't need one.
Monthly cost. Software: €0, all of it. If you already run Firefly III and Invoice Ninja from our other blueprints, the only new cost is n8n, which fits comfortably alongside them on the same small VPS — call it €0-5/month extra. Building all three from scratch: a €10-15/month VPS covers the lot. Compare that to a mid-tier accounting SaaS reconciliation feature at $16-70+/month, and this pays for itself before the first payment gets matched.
Setup outline
1. If you don't already run them: deploy Firefly III and the Data Importer (Docker Compose, both official images), then Invoice Ninja. If you built our money-dashboard or late-invoice-chaser blueprints already, you have these — skip to step 2.
2. In Invoice Ninja, generate an API token (Settings → Account Management → API Tokens) with read access to invoices and the ability to trigger the "mark paid" action.
3. In Firefly III, generate a Personal Access Token (Options → Profile → OAuth) with read/write access to transactions and tags.
4. Set up the recurring import: your bank's export (CSV or CAMT.053, exported daily or weekly depending on how your bank allows it) feeds the Data Importer, which posts new transactions into Firefly III automatically.
5. Build the n8n workflow: a Schedule Trigger (once daily, after the import runs) → HTTP Request to Firefly III's transactions endpoint, filtered to new, uncategorised deposits → HTTP Request to Invoice Ninja for the list of open (sent/partial) invoices.
6. Code node: for each new deposit, look for an exact amount match where the invoice number also appears in the transaction description. On a hit, call Invoice Ninja's mark-paid action and tag the Firefly III transaction with the invoice number.
7. For deposits that match an amount but not a clean reference, and where more than one open invoice shares that amount: send the payer name plus the candidate client names to Ollama, ask for its best guess and a confidence note, and route that guess to a Telegram message or an n8n form for a one-tap confirm — never an auto-close.
8. Everything else — no amount match at all — gets left alone. It stays visible in Firefly III as an unreconciled deposit, exactly as if you'd done nothing, because that's the honest state.
9. Run it in parallel with your existing manual check for two weeks before you trust the auto-close step. Count how many exact matches it got right and how many ambiguous ones it flagged sensibly.
Pitfalls — the real ones
Never let anything auto-close on a guess. The whole design rests on one rule: only an exact amount-plus-reference match closes an invoice automatically. A model's "probably this one" is not the same as a bank record saying so, and money is the one place where "probably" costs you a bookkeeping error you won't notice until your accountant does.
Split and partial payments break simple amount matching. A client who pays half now and half later, or bundles two invoices into one transfer, won't produce a clean 1:1 amount match. Route anything that doesn't match cleanly to the ambiguous pile rather than trying to get clever with combinatorial matching — it's not worth the complexity for the volume a small business sees.
Your bank's export format will drift. Column order, date format and encoding change when a bank redesigns its portal, silently breaking a CSV-based import. CAMT.053, where your bank offers it, is far more stable because it's a fixed EU-mandated schema rather than a bank's own CSV whims — prefer it when you have the choice.
Currency and fee deductions cause false negatives. A payment sent in USD that lands as EUR after conversion, or one where the bank clips a transfer fee off the top, won't amount-match an invoice total exactly. Widen the match tolerance by a percent or two rather than requiring an exact cent-for-cent hit, and always show the difference when you do.
Duplicate imports are a real risk if you re-run a statement. Firefly III's Data Importer has duplicate detection built in, but only if it recognises the same transaction twice — a re-exported statement with slightly different formatting can slip past that. Spot-check your transaction count after each import for the first month.
The API tokens you create can write, not just read. A leaked Invoice Ninja token that can mark invoices paid, or a Firefly III token that can edit transactions, is worth protecting like a password. Store both in n8n's credential store, not in plain text in a workflow node.
Verified repos
Firefly III — AGPL-3.0, 24.1k stars, active
Firefly III Data Importer — AGPL-3.0, 794 stars, active (v2.3.2, 19/04/2026)
Invoice Ninja — Elastic License v2 (source-available, free self-hosted use), 9.7k stars, active (v5.13.22, 08/05/2026)
n8n — Sustainable Use License (fair-code, free self-hosted internal use), 197.7k stars, active
Ollama — MIT, active
Sources: AICPA 2025 Practice Economics Survey (bank reconciliation hours) · CAMT.053 format guide (SEPA for Corporates) · Firefly III documentation · Invoice Ninja API reference
Get the next blueprint as it publishes — free, practical, verified tooling only.
Subscribe · Want this audited or extended for your business? DM @RXed_EU
Get this blueprint tailored to your business — free
Tell us what you run and where. We research your sector's specifics — rules, tools, customer habits — and send you a version of this blueprint rebuilt for your situation, usually within 24 hours.