Skip to content
Bahman Shadmehr Independent AI Systems & Automation Engineer

Finance operations · Reference design

Invoice checks before ERP entry

Every field matched. The bank account didn't.

Let a model read invoices into candidates with page evidence, let code run the checks a careful clerk runs, and let people own every exception. Nothing becomes payable automatically.

Company Brenner is a hypothetical company. Every figure is illustrative.

A printed invoice with one line circled in blue ink and a handwritten question about a new bank account.

About Company Brenner

Company Brenner is a hypothetical company, written for this reference design; the details below are its constraints. Every figure is illustrative, computed from stated assumptions. No client work or measured result is claimed.

Industry
Manufacturer of industrial enclosures and brackets
Size
About 450 people in two plants; five accounts-payable clerks
Systems
An ERP with purchase orders and goods receipts, a shared AP mailbox, a scanner for paper invoices
Volume
About 3,500 supplier invoices a month; month-end roughly doubles the daily load
Controls
Four-eyes principle; bank changes only through treasury call-back; audit wants every field traced to a page
Constraints
No automatic posting or payment; processing in the EU

In brief

ProblemKeying and judging happen together, so a tool that takes over typing must also surface arithmetic errors, duplicates, PO mismatches and changed bank details.
SystemEvidence-linked extraction, a check engine in code (arithmetic, supplier, duplicate, PO and receipt match, bank details), parked ERP drafts, and exception queues per owner.
People decideAP releases drafts and resolves arithmetic and matching exceptions; procurement resolves supplier identity; treasury resolves every bank-detail mismatch.

How the work ran before

Company Brenner makes industrial enclosures and brackets, with 450 people in two plants. Its accounts payable team is five clerks. About 3,500 supplier invoices arrive every month, mostly as PDFs in a shared mailbox, some as paper that gets scanned. One in five runs to several pages. In the last three days of the month the volume roughly doubles.

A clerk opens each invoice, types the header (supplier, number, date, amounts) and the line items into the ERP, and matches them against the purchase order and the goods receipt. If something doesn't match, the clerk emails the buyer. An old OCR tool fills in some header fields, but nobody trusts it with line items.

The work is slow but careful, and the clerks are good at it. The trouble is what "careful" depends on: a person noticing.

Where it broke

Two things happen at Company Brenner in the same quarter.

First, month-end keying errors cluster on continuation pages. When a line-item table runs onto page two and the supplier's layout doesn't repeat the column headers, a tired clerk shifts a column: a quantity lands in the unit-price field. Most of these get caught by the purchase-order match. A few don't.

Second, and worse: an email that looks like it comes from a long-standing supplier asks to update their bank details. A week later an invoice arrives from that supplier with the new account printed at the bottom. Every other field is right: the PO number, the amounts, the tax. A treasury clerk catches it because she happens to remember the supplier's bank. It was luck, not a control.

Brenner's first instinct is "automate the typing". That is the easy half. The dangerous half is that typing and judging are done by the same person in the same motion, so any tool that takes over the typing also has to take over, or at least surface, the judging.

What I would build

I would split the work into three jobs with different owners.

  1. Read. A model extracts the invoice into a fixed schema: header fields, line items, totals, remittance details. Every value keeps a pointer to where it came from (page and region). These are candidates, not facts.
  2. Check. Plain code runs the checks a careful clerk runs: do the line items add up to the net amount, does net plus tax equal the total, does the supplier exist, is this invoice number already in the ERP for that supplier, does it match an open purchase order and goods receipt, and do the bank details match the vendor master.
  3. Decide. If every check passes, the system creates a parked invoice in the ERP: a draft that cannot be paid until a clerk releases it. If any check fails, the invoice goes to the queue of whoever owns that failure: AP for arithmetic and matching, procurement for unknown suppliers, treasury for bank details.

Nothing the model returns can make an invoice payable. The strongest thing the system can do is prepare a draft for a person to release.

Following one invoice through

Sample data throughout. A four-page invoice arrives as package INV-PKG-04417. The model extracts the header, 23 line items and the totals. Page 4 shows net EUR 10,487.82, tax EUR 1,992.68 and a total of EUR 12.480,50, in German number format.

The checks run in order:

Check Candidate value Source Result
Line items sum to net 23 lines = EUR 10,487.82 pages 1 to 3 Pass
Net + tax = total 10,487.82 + 1,992.68 = 12,480.50 page 4, totals region Pass
Supplier exists matched on tax ID page 1, header Pass
Duplicate invoice number none found for this supplier ERP lookup Pass
PO and goods receipt match all 23 lines within tolerance ERP lookup Pass
Bank details match vendor master TEST-IBAN-INVOICE-04417 vs TEST-IBAN-MASTER-009 page 4, remittance region Fail

Sample data. Both bank tokens are placeholders, not real accounts.

Five checks pass, which is exactly what makes this invoice dangerous. The system parks nothing. It routes the package to treasury with the two bank values side by side and a crop of page 4. Treasury follows its call-back procedure with the supplier's known contact. AP never sees a "ready to post" invoice for it.

Company Brenner · ERP · invoice candidate Worked example · sample data

Package INV-PKG-04417 · four-page invoice

Page 4 of 4 · Gross EUR 12,480.50

Candidate Not parked Bank check failed
Remittance account differs from the vendor master

Five checks passed. The bank check has no tolerance and no override here: the package goes to treasury only.

Line items → net
23 lines = EUR 10,487.82 ✓
Net + tax = total
10,487.82 + 1,992.68 = 12,480.50 ✓
Supplier · duplicate · PO and receipt
Matched · none found · within tolerance ✓
Remittance token (invoice)
TEST-IBAN-INVOICE-04417 page 4 · remittance region
Vendor-master token
TEST-IBAN-MASTER-009 placeholder · not a real account
Park Route to treasury Treasury verifies through its call-back procedure.
Worked example · sample data. An ERP candidate view for Company Brenner, a hypothetical company.

A quieter failure: the continuation page

A second sample, INV-PKG-CT-002, is two pages long. Page 2 continues the line-item table without repeating the header row. An extraction model can easily read "160" as the unit price instead of the quantity on that page.

Item Qty Unit price Stated total Recomputed
Cable assembly 40 EUR 18.60 EUR 744.00 EUR 744.00
Housing bracket 160 EUR 18.60 EUR 2,976.00 EUR 2,976.00
Gasket set 12 EUR 31.25 EUR 375.00 EUR 375.00

Sample data. The correct reading of page 2.

Suppose the columns shift by one on page 2: the model reads 18.60 as the quantity and 2,976.00 as the unit price. The recomputed line total becomes 55,353.60, which doesn't match anything on the page, and the invoice goes to AP with the page region highlighted. The check catches the error without knowing why it happened. That is the point of doing arithmetic in code: it doesn't care which model made the mistake.

Arithmetic has a blind spot, though. If the model swaps quantity and unit price, 160 × 18.60 and 18.60 × 160 give the same total, and the line passes. That is why the purchase-order match compares unit price and quantity separately against the order. No single check is enough; they cover each other's gaps.

What changes for the team

Task Before After
Typing headers and lines Every invoice Only invoices a check sends back
Arithmetic and PO matching By eye, per invoice By code, every invoice; failures explained
Bank-detail changes Noticed if someone remembers Always held for treasury
Audit question "where did this number come from?" Find the PDF, search Click through to the page region

Illustrative planning figures, computed from assumptions stated in the technical design. Not measured.

Illustrative month (3,500 invoices) Manual keying Extraction + checks
Invoices a clerk types in full 3,500 about 700 (those failing a check)
Invoices a clerk reviews and releases 3,500 3,500
Clerk time on routine invoices about 6 min each about 1.5 min each
Bank mismatches that reach "ready to pay" depends on memory 0, by construction

The second row matters. Every invoice still passes through a person's hands before payment. The saving comes from turning typing into checking, not from removing the person.

What this does not solve

It cannot fix a vendor master that is already wrong: if a fraudulent bank change was entered months ago, the invoice will match it. It doesn't read contracts, so price agreements outside the purchase order are invisible to it. And an ERP's notion of a "parked" or "held" invoice differs between products; the adapter has to map onto the real permission model, not an idealized one.

How I would prove it

Take 300 invoices from last quarter that were already entered by hand, including the known problem cases. Run extraction and checks against them. Compare field by field with what the clerks entered. Report accuracy per field, and separately report every invoice where the system would have created a draft that the clerks later corrected. That second list is the one that decides whether the pilot goes ahead.

The technical design

The same system for engineers: architecture, records, failure handling, evaluation, the options I rejected, and the stack. About 5 minutes.

  1. Scope and assumptions
  2. Architecture
  3. Data model
  4. Checks and their owners
  5. Failure handling
  6. Evaluation
  7. Trade-offs I considered
  8. Stack
  9. Security and operations

Read the technical design

Keying invoices by hand?

Bring five anonymized invoices.

A few invoices, including an awkward one, plus the checks your team runs are enough to sketch the first validation workflow.