Skip to main content
Lifetime license included with every purchase
n8n workflowsbank reconciliationfinance automationdata validation

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.

Nn8n Marketplace Team·July 19, 2026·Updated July 19, 2026·8 min read

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.

Validate the feed before you match it

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

NodePurpose
n8n-nodes-base.codeFeed validation, the three-field matcher, AI-output parsing
n8n-nodes-base.scheduleTriggerDaily reconciliation run before business hours
n8n-nodes-base.httpRequestFetch bank transactions and ledger items from APIs
n8n-nodes-base.switchSplit matched / mismatch / unmatched
@n8n/n8n-nodes-langchain.openAiParse the reference on the unmatched tail only
n8n-nodes-base.slackDiscrepancy alert with the closest candidate attached
n8n-nodes-base.googleSheetsFull 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

  1. 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.
  2. Write the validation node first. Required fields, numeric amount, parseable date, duplicate detection. Test it against a deliberately messy export.
  3. 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.
  4. Wire the discrepancy alert with context. Attach the closest candidate, not just the orphan transaction.
  5. Add the AI tail only after the deterministic match is trustworthy. Scope it to reference parsing on the unmatched output. Nothing more.
  6. Log everything. Every match, mismatch, and AI recovery gets a timestamped row. Reconciliation that can't be audited isn't reconciliation.
Browse the data-validation templates
Skip the build

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.

Get the Data Gatekeeper template

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
FAQ

Common questions

Should an n8n bank reconciliation workflow use AI to match transactions?
No, not for the bulk of them. Matching a bank line to an invoice is arithmetic: equal amount, close date, shared reference. A Code node clears the large majority deterministically, faster and more reliably than a language model. Reserve AI for the unmatched tail — parsing a garbled payment reference on the handful of lines deterministic rules couldn't clear. Running every transaction through an LLM is slower, costs money per line, and matches worse.
How does n8n match bank transactions to invoices?
Pull the bank feed and the open invoices into a Code node (v2), then compare three fields: amount (exact), date (within a tolerance window of a few days), and reference (substring or normalized match). Exact triple matches are safe to mark reconciled automatically. Partial or ambiguous matches drop to a review output. That three-field test is the core of every reliable reconciliation workflow.
How do I catch reconciliation discrepancies in n8n?
After matching, any bank transaction with no invoice (or an amount mismatch on a near-match) is a discrepancy. Route those to a Slack or email alert with the transaction details and the closest candidate, and log them to a Google Sheet. Validating the input feed first — required fields, parseable amounts, no duplicate rows — stops bad data from masquerading as a discrepancy, which is what the Data Gatekeeper template handles.
Stop reading. Start running.

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.

Free — $40 value

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