Every supplier bill approved by AI.
And by a person.
A self-hosted n8n workflow that reads a supplier invoice, checks it against the approved-supplier record, files what is safe, and puts everything else in front of a human — with a written audit trail for every decision. No cloud AI bill. No invoice paid by a machine.
The problem
Small businesses approve bills by email and memory. The limit list lives in someone's head or a spreadsheet nobody updates. Bills get paid twice, paid late, or paid to a supplier whose account is on hold. When someone asks “who approved this?”, the answer is a search through a mailbox.
What it does
The invoice gate as built: 24 nodes in n8n, three workflows in total (gate, reply handler, error alert). Config and supplier limits are read from the client's own spreadsheet at the start of every run.
The human step is the product
The AI prepares the decision and writes the reason. It never pays, never files a bill it was not allowed to file, and never sends the outbound message. A person is the last word.
What it does not do
No payment. No write-back to an ERP. No PDF attachment parsing yet — today the invoice text is typed in or read from the email body. Those are quoted separately, not implied.
Evidence — from runs, not a mock-up
| Check | Result |
|---|---|
| Invoices approved automatically | 2 of 5 cases: known supplier, active account, amount inside the limit → ledger row + local audit line |
| Invoices stopped for review | 3 of 5: over the limit, unknown supplier, supplier account inactive → exception row + approval email, each with the failed rule written down |
| Reply loop | 12 human replies processed, one audit row per reply, one Sheet update per invoice; a second pass adds nothing (idempotent) |
| Config is live | A limit changed in the Sheet (2,500 → 1,000) rerouted a $1,840 invoice to review on the next run. No workflow edit, no restart |
| Approver is live | Approver changed in the Sheet; the next approval email went to the new address |
| Guard | 8/8 tests: model approvals above the limit, for unknown suppliers, for inactive accounts, below the confidence floor, wrapped in markdown, or in prose are all downgraded |
| Failure visibility | A real trigger-mode failure produced one alert email with workflow, node, execution id and stack |
The reply handler: watches the mailbox, updates the Sheet, writes the audit row, labels the email so the same reply can never be processed twice.
Why it is cheap to run
| AI | Local model (Ollama, qwen2.5:7b) on the same small server. No per-token API bill, no data leaves the machine for the AI step. |
| Gmail API + Sheets API on the client's own account. No charge at this volume. | |
| n8n | Self-hosted, free. One instance per client. |
| Hosting | A $6/month VPS, or the client's own machine |
| Data | Invoice data stays in the client's Google account. The audit is a Sheet they own. |
Options
Prices are estimates for a single-entity business; scope is fixed in writing before work starts.
How to start
A 20-minute call with one real bill. We map the current approval path, agree the limit table and the approver, and I install a Pilot against your own Google account. You keep the Sheet, the workflow and the audit.