The bank reconciliation matcher: payments and invoices, matched without typing a row
A payment comes in. This matcher finds the invoice. It marks it paid without typing.
A workflow that reads your bank statement and closes the invoices it already paid
Paste it into your AI assistant — ChatGPT, Claude, Gemini, whichever you use. It first asks what tools you already have, then rebuilds this blueprint to fit them.
- Your bank must offer CSV or CAMT.053 statement export
- Customers must put the invoice number in the payment reference at least some of the time
- Every invoice must live in Invoice Ninja, reachable with a working API token
- 8-16 GB of RAM for the local model handling the ambiguous leftovers
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 architecture
the same flow as text
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.
Paste it into your AI assistant — ChatGPT, Claude, Gemini, whichever you use. It first asks what tools you already have, then rebuilds this blueprint to fit them.
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.
Tool choices — and why
Setup outline
- 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.
- 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.
- In Firefly III, generate a Personal Access Token (Options → Profile → OAuth) with read/write access to transactions and tags.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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 — what goes wrong when you build this
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
What this costs to run
Priced as Classify & route — one email or ticket including a short quoted thread; output is a label plus a one-line reason. only the ambiguous leftover payments reach the local model; exact amount+reference matches are free deterministic comparison. Adjust the volume to yours; the bill is a range because the assumptions are ranges.
| Model | $/day | $/month | Reasoning |
|---|
Cheapest eight shown — straight per-token
arithmetic on list prices: no caching, no batch discount, thinking tokens bill as output.
All models + every assumption in the full explorer →
Capability & cost data: Artificial Analysis