AP invoice automation, end to end
A mid-size distributor moves 4,000 supplier invoices a month from a shared inbox into their ERP. This is what that looks like in IDPForge — every decision, in order, including the ones that go wrong.
- Situation — 4,000 invoices/month arriving at
ap@northwind.example, keyed by hand into Coupa by three people. - Goal — 80%+ straight-through delivery, with a review loop for the rest that two people can hold.
- Uses — Email source · Split & Classify · AP Invoice v3 schema · three-way match validation · Coupa destination · one work queue
- Outcome — 83% straight-through in week 6. Average handling 3.4 min on the remainder.
The shape of the problem
Northwind's inbox is not clean. A single email might carry an invoice, its packing slip, and a statement of account in one PDF. Around one in nine attachments is not an invoice at all — credit memos, remittance advice, and the occasional signed contract. Any design that assumes "one file, one invoice" fails in the first week.
So the pipeline is built around the split, not around the extract.
Step 1 — Point the source at the inbox
The email source generates an address; Northwind forwards ap@ to it with a mail rule rather than changing what suppliers are told. Attachments only — the body is ignored. Source tag ap-inbox so this traffic stays separable from the API submissions the procurement team also sends.

Once the forward is live, jobs appear tagged ap-inbox and you can watch them cross stages.
Step 2 — Split before you classify
Split runs first and cuts the 6-page attachment into three documents. Only then does Classify assign each one a class from the taxonomy: FIN.INV, FIN.CM, LOG.PACK, FIN.STMT. Packing slips and statements route to a no-op destination — captured for the record, not extracted.
Because the class of a package is meaningless. Classifying before splitting produced a 62% accuracy ceiling in Northwind's first attempt — the model was asked a question with no correct answer.
Step 3 — One schema, bound to one class
Only FIN.INV routes to AP Invoice v3: 14 header fields and a line-item table. Credit memos get their own schema. The temptation to build one big schema with optional fields was resisted — optional fields make every confidence score mushier, because the model cannot tell "absent" from "missed."
Step 4 — Validation is where the value is
Three rules run after extract, and they catch far more than the extractor does:
| Rule | Catches | On failure |
|---|---|---|
| Line items sum to total (± $0.01) | Missed line, OCR digit slip | validation_failed → review |
| Vendor resolves in the master list | New supplier, name variant | Auto-fill from fuzzy match ≥ 0.92, else review |
| PO exists and is open | Duplicate billing, closed PO | policy → review, flagged for AP lead |
Step 5 — One queue, not five
The instinct is a queue per exception type. Northwind ships one: "AP invoices needing attention," filtered to FIN.INV with any open exception, sorted oldest-wait first. Two operators work it. Splitting into five queues would have created five ways to be idle while a sixth pile grew.
The whole loop, one email to one ERP record.
Step 6 — Coverage that shrinks
Week one, every correction is verified — 100% flat coverage while the team learns what "correct" means for these documents. By week six, coverage is 5% flat with two exceptions held at 100%: new operators in their first 30 days, and any invoice over $50,000.
What went wrong
- Scanned faxes destroyed the split — A handful of suppliers still fax. At 200 DPI with skew, the split model cut mid-invoice. Fixed by raising the deskew threshold in Initialization and adding a
faxsource tag so those documents are excluded from straight-through metrics. - Duplicate deliveries after a retry storm — Coupa timed out for 40 minutes; the destination retried. Without an idempotency key on the delivery, 19 invoices posted twice. Now every delivery carries the document id as the key.
- The 92% fuzzy-match threshold was too generous — "Globex Ltd" auto-filled as "Globex Inc" — a different legal entity, and a real payment to the wrong account. Threshold moved to 0.97, and entity-suffix mismatches now force review regardless of score.
Where it landed
| Metric | Before | Week 6 |
|---|---|---|
| Straight-through rate | — | 83% |
| Documents touched by a human / month | 4,000 | 680 |
| Average handling time | ~6 min (full key-in) | 3.4 min (correction only) |
| People on AP entry | 3 | 2, part-time |
Extraction accuracy was good on day one. What took six weeks was getting the routing and the validation rules right — which is where almost all IDP projects actually spend their time.