FlowKit

Vendor Invoice Approval Workflows in n8n: Thresholds, Matching and Audit Trail

Published 19 August 2026 · 6 min read

Automatically extracting the amount, date and vendor from a PDF invoice — see our AI invoice extraction guide — only solves half the problem. The real friction in a small business is almost never data entry: it's the decision circuit that follows. Who is allowed to approve a €200 expense? What about an €8,000 one? Should you check that a purchase order exists before paying? And who steps in when the right approver is on vacation? These are the questions — not OCR accuracy — that leave an invoice sitting in an inbox for two weeks before it gets paid. This guide builds the approval circuit itself, on top of an extraction pipeline you already have running.

The problem extraction alone doesn't solve

Once an invoice's fields are cleanly extracted into a Supabase table (factures_extraites), you still need to decide, automatically: pay directly, request validation, or block and alert. Without this decision layer, two failure modes show up in practice — either everything still gets manually re-checked by a human (automation changed nothing), or everything gets paid without control as soon as the "amount" field is filled in correctly (error and fraud risk explodes). The right setting sits between the two, and it depends on the amount, the vendor, and whether a matching purchase order exists.

Define thresholds before you build the workflow

This part happens on paper, not in n8n: without a clear threshold grid, the workflow just automates an existing ambiguity. A simple grid, stored in a Supabase table or a Google Sheet rather than hardcoded into the workflow (so it can be adjusted without redeploying):

  • Below a first threshold (say €300) with an already-known vendor: automatic payment, logged, no human step.
  • Between that threshold and a second one (say €300 to €3,000): a single approver, assigned by expense category.
  • Above the second threshold, or a vendor never seen before: two approvers required (the department lead, then finance), regardless of amount.

Keeping these values in a table rather than hardcoded into an IF node is what lets you evolve the spending policy without touching the workflow — a Switch node (n8n-nodes-base.switch) then reads that table and routes each invoice to the right branch.

Matching the invoice against the purchase order (three-way matching)

Before any payment above the first threshold, compare three things: what was ordered (purchase order), what was received (delivery note or confirmation), and what is being invoiced. This is the three-way matching principle, standard in accounts payable to catch duplicate billing, price discrepancies, and invoices for goods that were never delivered. In n8n, this is straightforward: a Supabase query (Select node) on the orders table, filtered by the purchase order number extracted from the invoice, then an IF node comparing the invoiced amount to the ordered amount with a tolerance (2 to 5% depending on your policy, to absorb shipping costs or small roundings). A gap outside that tolerance automatically routes the invoice to manual review instead of standard approval.

This is exactly the kind of control a landmark automation study, Parasuraman & Manzey (2010), Complacency and Bias in Human Use of Automation, published in Human Factors, helps justify: the authors show that excessive trust in an automated system — here, blindly trusting AI extraction without ever cross-checking it against an independent source — increases the rate of undetected errors, even among experienced users. Purchase order matching isn't extra bureaucracy: it's the safeguard that keeps a mis-extracted figure or a fraudulent invoice from sailing through just because the PDF looked correctly formatted.

Routing to the approver: Switch, Wait and Slack

Once the amount and the matching result are known, the Switch node sends the invoice down the right branch. For invoices that need human sign-off, the mechanism is the one already detailed in our article on human-in-the-loop approval with the Wait node and Slack buttons: a Slack message with the invoice's key fields (vendor, amount, any gap versus the purchase order), "Approve" / "Reject" buttons, a Wait node in On Webhook Call mode to suspend the execution without consuming resources, and resumption via the resumeUrl on click. For the two-approver circuit, simply chain two passes through this same pattern — the second Wait only triggers after the first is validated — each with its own timeout and its own escalation path if nobody responds.

A caution from an entirely different field of research applies directly here: the now-classic study by Danziger, Levav & Avnaim-Pesso (2011), Extraneous Factors in Judicial Decisions, published in PNAS, documents how decision fatigue pushes people toward the simplest option — approving without checking — as the number of consecutive decisions grows. Concretely, for an invoice circuit: avoid sending twenty separate approval requests to the same person within the same hour. A grouped digest (one Slack notification listing all pending invoices, instead of one message per invoice) reduces this risk and is easy to build with a Schedule Trigger running twice a day — see our Schedule Trigger node guide — which queries Supabase for every invoice still in "pending" status.

Logging every decision

An approval circuit that leaves no trace protects no one in an audit or a dispute with a vendor. On every Wait node resumption, write a row to an append-only audit table (journal_factures: invoice, amount, approver, decision, timestamp) — the same principle detailed in our GDPR audit trail guide with n8n and Supabase, applied here to accounting compliance rather than data protection. If your Supabase credential isn't set up yet, our n8n-to-Supabase connection guide covers the full setup.

Handling failures without losing an invoice

A failed Slack call, a timeout with no response, a Supabase query that times out: none of these should ever silently drop an invoice awaiting payment. Wire up a dedicated Error Workflow — see our n8n error handling guide — that flips the invoice's status to "error" rather than leaving it in a blind spot, and alerts a supervision Slack channel separate from the approval channel. Also watch out for duplicates: the same vendor reminder email, received twice, shouldn't generate two approval requests for the same invoice — the n8n webhook idempotency principle applies just as well here, by checking the invoice-number-plus-vendor pair before any insert.

Common pitfalls

  • Thresholds hardcoded into IF nodes. Any change to the spending policy then requires editing and redeploying the workflow. A configuration table read at runtime avoids this coupling.
  • A single approver with no backup. A Wait node without a configured time limit will block an invoice indefinitely if the assigned person is unavailable — always plan an escalation to a second approver after a reasonable delay (24 to 48 business hours).
  • No matching check on recurring invoices. A "known" monthly subscription is exactly the preferred target for fraud via a quietly swapped bank account — verify the amount and bank details on every occurrence, not just the first invoice.

Going further

This circuit — extraction, thresholds, matching, multi-level approval, and audit trail — matches the exact architecture of the guided questionnaire bot and Supabase logging module in the Compliance & Audit Pack (€149), best combined with the automatic incoming-invoice triage from the AI Inbox Pack (€79) to cover the full chain from email receipt to validated payment. The Complete FlowKit Bundle (€269) includes both, plus the RAG Assistant Pack. If your team is still handling vendor invoices in a shared inbox with no audit trail, this is the first thing worth automating before you look any further.

Bundle FlowKit Complet

€269