Projects / Demo
Transaction Categorisation
Demo · All data is synthetic
I built this demo around the month-end job of tagging every line in a business's card and bank feed so the books make sense. Having worked on card programs, first as a software engineer at i2c and now as a fintech/payments PM, I know most of the feed is easy, the same SaaS tools and the same ride apps every month, and the real risk is in the few lines that look normal but aren't: a double charge, a refund that gets counted as income, or a transfer to savings that shows up as spend. So the workflow works in a fixed order. It first matches the messy card descriptor to a known merchant, then looks for keywords like a Stripe payout or payroll, then falls back to the card's merchant category code, and anything still unknown goes to a person instead of being guessed. Each line records which rule tagged it, and duplicates, refunds, internal transfers, and large payments get flagged. The rules live in a JSON file a bookkeeper can edit. I made up 40 transactions with the answer each one should get, and a check script confirms the workflow gets all of them right. It's a demo on synthetic data; going live means pointing it at Stripe, Plaid, or a bank export and sending the results to QuickBooks, Xero, or a Sheet, with an LLM optionally suggesting categories for the leftover lines.
How it works
Manual / daily trigger → Read + Parse rules.json → Read + Parse transactions.csv → Categorise & Flag (Code) → categorised.csv + summary.mdRules, in order
1. MerchantThe messy card descriptor (AMZN Mktp US*2K4L19, GOOGLE *Workspace) is matched to a known merchant, which maps to a category.
2. KeywordPatterns in the description, such as STRIPE PAYOUT, PAYROLL or TRANSFER TO SAVINGS.
3. MCCThe card network's merchant category code, by range. For example, 3000-3299 (airlines) and 3500-3999 (hotels) go to Travel.
4. Needs reviewNothing matched, so the line is left for a person instead of guessed.
Flagspossible_duplicate (same descriptor and amount within 2 days), refund (netted against spend), internal (transfers between own accounts), large (1,000 or more) and review.
Check40 made-up transactions, each with the answer it should get. The check script passes 40 of 40 on category, method and flags. That checks my own seeded cases, not accuracy on real data.
Demo
A short walkthrough of the demo, made from the screenshots below, not a screen recording.
Screenshots




Stack
n8n 2.8.4 (self-hosted, SQLite), JavaScript in the Code nodes, and Python 3 for the synthetic data and the check script. Categories live in a JSON rules file a bookkeeper can edit.
This is a demo on synthetic data. The 40 transactions were made up for the demo, and no real accounts, API keys or paid services are used.