The invoice checker is my own project, and you can try it on this page. Everything else I built in my job. It belongs to the company, so I describe it without names, screenshots or numbers that aren't mine to share.
Own project
Invoice checker
It reads invoice PDFs, compares every line with the purchase order and the shipping records, and holds back the ones that don't match. Each held invoice opens with the problem line marked.
It also reads scans. When a scan is misread, the lines stop adding up to the printed total, and the invoice is held instead of booked.
The sample invoices are made up. The real tool runs on the company's own server, so documents don't leave the building.
Each supplier layout gets its own reading profile; these ten were built in about a week. Scans are checked by arithmetic, so a misread is held, not booked.
Python, pdfplumber, Tesseract for scans, Streamlit for the review screen.
A held invoice. 40 were ordered, 45 were billed, and the line is marked.
Incoming invoices
Click an invoice on the left, then a reason on the right.
What it caught in the ten samples
Quantity
45 impact drivers billed, 40 ordered. $420 too much.
Price
Cutting discs billed at £34.20. The agreed price was £31.50.
Arithmetic
Lines add up to 4,683.50. The invoice total is built on 4,773.50.
Billed twice
One waybill number appears twice on the same carrier invoice.
Never sent
A waybill with no match in the shipping records.
Re-weighed
A parcel sent as 4 kg and billed as 18 kg.
Extra fee
A 21.00 bulky goods surcharge that was never declared.
No order number
Matched to the right order by supplier and item codes, then held for a person to confirm.
A visitor has a question at eleven at night and nobody is there to answer it. The same questions arrive by email all day.
What I built
A chatbot on the Claude API that answers only from a written description of my services, in the visitor's language. When someone wants a call, it collects their name and email, saves the lead on my server and sends it to my phone and inbox within a second. If the model is unavailable, a plain form takes over.
How it is built
Node.js on my own server, the Anthropic SDK, one tool call for sending the lead, a rate limit per visitor. Nothing is stored except the leads.
Marketplace price monitor.
The idea rebuilt on an invented catalogue. Try the report
Rebuilt on made-up data
Price monitor
The problem
Selling on Amazon and eBay means a competitor can undercut you overnight, and checking their listings by hand for every product is an hour a day that never happens.
What I built
A tool that collects the competing offers for each product in the catalogue every morning, matches them by product code, and produces a price list with a recommendation under fixed rules: undercut the lowest in-stock offer by a set percentage, never below cost plus margin, raise when alone. Approved prices went back to the listings.
What it does
Collects the competing offers for each product every morning, matches them by product code, and recommends a price under fixed rules: undercut the lowest in-stock offer, never below cost plus margin, raise when alone.
Built in my job.
These run inside the company I work for. The ideas were mine and I built them, but the code and the data belong to the company, so I can describe them and show nothing. Where I can, I rebuild the idea on made-up data so you can try it.
Every week the finance team opened the accounting export and one export per marketplace, and worked out by hand who owed what, what was overdue, and what had been overpaid, for each of the group's companies.
What I built
An Apps Script inside the spreadsheet they already used. It takes the exports, keeps the columns that matter, splits overdue, waiting and overpaid, groups the key accounts with their own subtotals, buckets the overdue amounts by age from 30 days to 3 years, and fills a roll-up sheet with one column per company.
My part
All of it: the idea, the import screen and the script.
The parcel carrier's monthly invoice ran to thousands of lines, and nobody could check by hand whether every shipment on it was ours, billed once, at the declared weight and the agreed rate.
What I built
A check that matches each invoice line to our own shipping export and lists the lines to dispute with the reason: billed twice, never shipped, re-weighed, surcharge not in the contract, wrong rate.