n8n Bank Reconciliation Workflow: Deterministic Matching With an AI Tail
Build an n8n bank reconciliation workflow that matches transactions on amount, date, and reference deterministically — and only uses AI for the unmatched tail.
The AI reconciliation demos all look the same: feed the bank statement to GPT-4, ask it to match the invoices, marvel at the output. Then you run it on a real month of data and it confidently matches a $1,240 deposit to a $1,420 invoice because the numbers "looked close." Reconciliation is the one finance task where close isn't good enough.
An n8n bank reconciliation workflow done right inverts the usual demo. Deterministic rules clear the overwhelming majority of lines — equal amount, close date, matching reference — and a language model only touches the unmatched tail. The arithmetic is exact where it has to be, and the fuzzy reasoning only runs where there's genuinely nothing left to match on.
This isn't anti-AI. It's putting AI where it adds value (parsing a mangled reference string) instead of where it introduces risk (deciding whether $1,240 equals $1,420).
What You Can Automate in Reconciliation
The pieces of a reconciliation that automate cleanly:
- Pulling a daily bank feed (CSV export, Plaid, or an accounting-platform endpoint)
- Reading open invoices or expected payments from your ledger
- Matching on amount plus date plus reference in a single Code node
- Auto-marking confident matches as reconciled in the source system
- Flagging amount mismatches and unmatched deposits as discrepancies
- Sending the unmatched tail to a human with the closest candidate attached
- Logging every match and discrepancy to an audit sheet finance can review
The matching engine is one node. The discrepancy alert is what makes the workflow worth running daily instead of letting things pile up to month-end.
The Reconciliation Pipeline
The shape, before any AI enters the picture:
Trigger → Validate feed → Match (deterministic) → Split → Alert / Log → AI tail (optional)
A concrete daily run:
Schedule Trigger v1.2 (cron: 0 6 * * *)
→ HTTP Request v4.2 / Google Sheets v4: fetch bank transactions
→ Code v2 (jsCode): validate rows (amount numeric, date parseable, no dupes)
→ Code v2 (jsCode): match each tx on amount + date(±3d) + reference
→ Switch v3: matched | mismatch | unmatched
→ Set reconciled flag (matched) → Slack alert (mismatch)
→ OpenAI v2.1: parse reference on the unmatched tail only
→ Google Sheets v4: append full reconciliation log
The validation step runs before the match, not after. A bank export with a blank amount or a duplicate row will produce a phantom discrepancy that wastes a human's afternoon. Catch the bad rows first. n8n users running reconciliation at volume report that input validation removes more false discrepancies than any matching-logic tweak.
A reconciliation workflow is only as trustworthy as its input. A duplicated CSV row reads as an unmatched transaction. A non-numeric amount string silently fails the equality test and gets flagged as a discrepancy. Run a required-fields-and-format check on every row before the matcher sees it — that single preflight step is the difference between a clean exception list and a noisy one.
Step-by-Step Breakdown
1. Fetch both sides
The bank feed (CSV, Plaid, or an API export) and the open ledger items. Pull them into the workflow as two named branches you can reference by node name later.
2. Validate before matching
A Code node checks every bank row: is the amount numeric, is the date parseable, is this row a duplicate of one already seen? Reject failures into a separate output so they never pollute the match.
3. Match deterministically
The core Code node compares amount (exact), date (within a tolerance window of a few days), and reference (normalized substring). Exact triple matches are confident. Two-of-three is a candidate, not a match.
4. Split three ways
A Switch node routes confident matches to auto-reconcile, amount-mismatches to a discrepancy alert, and clean unmatched rows to the optional AI step. Three outputs, three handling paths.
5. Handle the tail, then log
Only the genuinely unmatched rows reach a language model, and only to parse a messy reference (a typo'd invoice number, a concatenated memo field). Everything — matched, mismatched, AI-recovered — appends to a Google Sheet so the reconciliation is auditable after the fact.
Implementation Patterns That Hold Up
Pattern 1 — The three-field match. The whole engine fits in one Code node.
Code v2 (jsCode):
const sameAmount = Math.abs(tx.amount - inv.amount) < 0.005;
const closeDate = Math.abs(daysBetween(tx.date, inv.date)) <= 3;
const refMatch = normalize(tx.ref).includes(normalize(inv.number));
if (sameAmount && closeDate && refMatch) return 'matched';
if (sameAmount && closeDate) return 'candidate';
return 'unmatched';
Floating-point cents are why the amount test uses a small epsilon rather than ===. Two values that print as 1240.00 can differ at the fifteenth decimal after a currency conversion.
Pattern 2 — AI on the tail, never the trunk. Pass only the unmatched output to an OpenAI node, with a tight prompt: given this bank memo and these three candidate invoices, return the matching invoice number or none. Cap it there. The @n8n/n8n-nodes-langchain.openAi v2.1 node returns its answer at $json.output[0].content[0].text; a Code node parses that back into a match decision. If the model says none, it stays a discrepancy.
Pattern 3 — Discrepancy alerting with the closest candidate. A bare "unmatched transaction" alert is useless. Attach the nearest near-match (same amount, wrong date; or right reference, wrong amount) so the human reviewing it has a starting point instead of a mystery.
n8n Nodes You'll Use Most
| Node | Purpose |
|---|---|
n8n-nodes-base.code | Feed validation, the three-field matcher, AI-output parsing |
n8n-nodes-base.scheduleTrigger | Daily reconciliation run before business hours |
n8n-nodes-base.httpRequest | Fetch bank transactions and ledger items from APIs |
n8n-nodes-base.switch | Split matched / mismatch / unmatched |
@n8n/n8n-nodes-langchain.openAi | Parse the reference on the unmatched tail only |
n8n-nodes-base.slack | Discrepancy alert with the closest candidate attached |
n8n-nodes-base.googleSheets | Full reconciliation audit log |
Two Code nodes carry this workflow: one validates, one matches. Keep them separate. Folding validation into the matcher makes both harder to debug, and the validation logic is the part you'll reuse across other finance workflows.
Getting Started
- Get both feeds into the workflow as named branches. Bank transactions and open ledger items. Don't match until you can see both in the execution output.
- Write the validation node first. Required fields, numeric amount, parseable date, duplicate detection. Test it against a deliberately messy export.
- Build the three-field matcher. Run it on a full month of real data and eyeball the matched / candidate / unmatched split before automating any write-back.
- Wire the discrepancy alert with context. Attach the closest candidate, not just the orphan transaction.
- Add the AI tail only after the deterministic match is trustworthy. Scope it to reference parsing on the unmatched output. Nothing more.
- Log everything. Every match, mismatch, and AI recovery gets a timestamped row. Reconciliation that can't be audited isn't reconciliation.
The Data Gatekeeper — Preflight & Failure Logging template ships the validation half this workflow depends on: it checks every record in a Google Sheet for required fields, email and value format, and duplicates, logs a daily audit summary, and emails a failure report when bad rows appear — exactly the preflight that stops a duplicate CSV row from reading as a fake discrepancy. It's part of The Complete n8n Templates Bundle, a one-time lifetime license to the whole catalog (plus every template added later) if you run more than one of these data automations.
A practical caveat: bank export formats drift. A bank that delivered DD/MM/YYYY last quarter quietly switches to MM/DD/YYYY after a platform update, and a date parser that assumed one order silently mis-dates half the feed. Pin the date format explicitly in the validation node and fail loudly when a row doesn't match it.
If your reconciliation feeds a wider reporting setup, the n8n data pipeline automation guide covers the extract-validate-load pattern this builds on. For the surrounding accounts-payable and receivable context, the n8n finance automation guide ties the reconciliation step to the chase and payment workflows around it.
Build the deterministic matcher first. If it clears most of your month on its own, you've already won — the AI tail is a refinement, not the foundation.
See more finance templates →Common questions
Should an n8n bank reconciliation workflow use AI to match transactions?
How does n8n match bank transactions to invoices?
How do I catch reconciliation discrepancies in n8n?
Get the workflow templates this guide is built on
Import-ready n8n JSON, step-by-step setup, and tested end-to-end. One-time payment, own it forever.
Get 3 tested n8n templates, free
The full customer package for three real catalog templates — workflow JSON, step-by-step setup guide, credential checklist. Built through the same live-instance release process as everything we sell. Plus new templates and automation guides in your inbox. No spam, unsubscribe anytime.
- 01Smart To-Do List ManagerPre-built n8n workflow template that automates productivity with OpenAI. Live in about 10 minutes.$14
- 02Email Follow-Up AutomatorPre-built n8n workflow template that automates crm with OpenAI. Live in about 15 minutes.$12
- 03Market Trend AnalyzerPre-built n8n workflow template that automates data processing with OpenAI. Live in about 10 minutes.$14
More automation guides

n8n Backup Automation That Actually Verifies the Backup
A Backup You Never Verified Is a Coin Flip Every n8n backup automation tutorial that ranks does the same thing: schedule an export, push the JSON to Google Drive or S3, done. They back up the data and…

How to Build an n8n Log Alerting Workflow (No Grafana Required)
Most n8n Error Setups Tell You Everything, Which Means They Tell You Nothing An n8n log alerting workflow has one job: surface the failures that need a human and quietly file the ones that don't. The…

n8n Uptime Monitoring with Slack Alerts (Without the Alert Storms)
An Uptime Check That Cries Wolf Gets Muted in a Week The point of n8n uptime monitoring with Slack alerts isn't to detect a single outage. It's to be trusted the next hundred times it fires. Most of t…