Supplier bill matcher
A serverless matcher that reads every supplier bill as it arrives, finds the matching purchase order and goods-received note, and checks them line by line — right item, right quantity received, right price. Clean three-way matches clear for a manager’s one-tap approval; anything off is flagged with the exact reason. It never pays a bill on its own. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.
-
01
A supplier bill matcher on AWS for a few dollars a month
The whole system on one page — a bill intake, a matcher, and an approval piece, plus the four outcomes every bill lands in.
-
02
How a supplier bill gets read
Three lanes bring bills in — an emailed-PDF lane parsed by Textract, a supplier-portal poll, and a manual upload — and one Bedrock call per bill turns the raw read into clean lines.
-
03
How a bill gets matched three ways
A plain-Python matcher lines the bill up against the purchase order and the goods-received note, checks item, quantity, and price against tolerances, and picks one of four outcomes. No model on the match.
-
04
How a mismatch reaches the right person
Routing per outcome, quiet hours, the right approver per supplier, an email with the exact line and the exact gap, and the four guardrails between a flag and the actual message landing.
-
05
How a bill gets approved for payment
Three actions on every bill: approve (clear for payment, with a reason if it overrides a flag), query (send a templated question back to the supplier), and reject. Every action is logged. No bill pays itself.
-
06
What the bill matcher costs
A few dollars a month at SMB volume. The match itself is free; the cost is Textract reading each bill and one small Bedrock call per bill to clean up the lines.
-
07
Engineering reference: the bill matcher architecture
Same system, drawn purely for engineers. Service names, resource identifiers, region, Bedrock model IDs, Lambda inventory, IAM scopes, the SES inbound rule set, EventBridge Scheduler config, and the DynamoDB schemas.
Frequently asked questions
- What is a supplier bill matcher?
- A small serverless system that reads every supplier bill (invoice) as it arrives, finds the matching purchase order and the goods-received note, and checks them line by line — right item, right quantity received, right price. Clean three-way matches are cleared for a manager’s one-tap approval; anything off is flagged to the right person with the exact reason. It never pays a bill on its own; a human approves every payment.
- How much does it cost to run?
- About $3.20/month at typical small-business volume (around 200 bills a month). The fixed cost is essentially zero. The variable cost is dominated by Textract reading each bill PDF and one Bedrock Haiku 4.5 call per bill to turn the read text into clean lines; the three-way match itself is plain Python and costs almost nothing. At 1,000 bills a month the bill lands around $14.
- Which AWS services does it use?
- Lambda (Python 3.14, arm64) with Function URLs for the approve/query/reject buttons, EventBridge Scheduler for the portal poll and the daily aged-bill sweep, DynamoDB on-demand, S3 (with versioning), SES inbound + outbound, SQS with a dead-letter queue, Secrets Manager, CloudWatch Logs (7-day retention), AWS Budgets, Textract for reading bill PDFs, and Bedrock (Claude Haiku 4.5 via Global cross-Region inference) to turn read text into clean lines. No API Gateway, no NAT Gateway, no always-on compute.
- Where do the purchase orders and goods-received notes live?
- In a Google Sheet in a Drive folder — one tab for open purchase orders, one tab for goods-received notes. Each PO line has the item code, ordered quantity, agreed price, and supplier. Each goods-received line records what actually arrived at the dock. A small
drive-syncLambda mirrors both tabs to S3 every 15 minutes; the matcher reads from S3 to keep Drive calls predictable and to get S3 versioning for free. - Does the matcher use AI?
- Sparingly. The three-way match is plain Python that compares numbers against tolerances — no AI on that hot path. Bedrock Haiku 4.5 fires once per bill, only to turn the raw Textract read into clean, structured lines (item, quantity, unit price) that the deterministic matcher can compare. The match decision itself never depends on a model.
- What are the four outcomes?
- Every bill lands in exactly one of four outcomes. Matched: every line agrees with the PO and the goods-received note inside tolerance — cleared for one-tap approval. Price variance: the right items arrived but the supplier billed a higher unit price than the PO agreed. Quantity variance: the billed quantity doesn’t match what the dock actually received. No PO: the bill has no purchase order to match against at all. The last three are flagged to the right person with the exact line and the exact gap.
- Can it ever pay a bill by itself?
- No. The matcher only ever proposes. A clean match clears the bill for approval, but a human still taps Approve before anything is queued for payment. On a flagged bill the approver gets three choices: Approve (override the flag with a reason), Query (send a templated question back to the supplier), or Reject (decline the bill). Every action is recorded in the
bm-auditDynamoDB table with timestamp, bill, action, by-user, and a before-and-after snapshot.