Skip to main content
DoneThat

AI Adoption GuideFinancePay

Three-way match agent

Agent matches invoice to PO and goods receipt, auto-posts clean matches, and routes exceptions, using tools like Vic.ai.

Finance processPlanBudgetInvoiceCollectPayCloseReportAudit

By Don, DoneThat’s AI coach · updated

A match packet is three cites, or it is empty

A three-way match is complete only when the agent can point at an invoice line, the PO line that authorized it, and the goods receipt that proves the goods or services arrived. If any of those three pointers is missing, the packet stays empty. The agent does not fill a blank receipt with a guessed quantity, a copied PO quantity, or a received-as-invoiced assumption.

Quality here is citation, not throughput. Auto-post is allowed only after the packet names the three documents and their line IDs. Everything else is an exception for a person in AP to resolve and post.

The packet itself is the audit object. For each matched line it must hold invoice document and line, PO document and line, and receipt document and line, plus billed quantity, received quantity, PO price, billed price, and the pass or fail on each comparison. If a receipt document number cannot be named, those receipt fields stay blank. Blank is a valid, honest state.

Load invoice, PO, and receipt as separate legs

Start with three independent loads. Do not treat the invoice as a stand-in for the other two documents.

Invoice: take header and lines from the AP inbox after invoice OCR and extraction. You need vendor, invoice number, dates, currency, tax, and every billed line: item, quantity, unit price, unit of measure, and amount. Run invoice pre-flight check before matching so you do not spend match cycles on a duplicate invoice number, a blocked vendor, or a document that failed basic completeness. Pair that with duplicate and fraud detection so a second copy of the same bill never reaches three-way match as if it were a new liability.

PO: pull the open purchase order from the ERP, not from a PDF the vendor attached. The PO is the authorization. You need PO number, buyer, remaining open quantity, price, account assignment, and receiving plant or location. Capture products such as Vic.ai present the invoice; ledgers such as Workday, SAP, and Oracle hold the PO master and the goods-receipt history. Read them as one operating picture.

Receipt: load goods receipts, and service entry sheets where that is the receiving document, that still have open quantity against that PO line. A receipt is a warehouse or receiving event. It is not the invoice and it is not the PO. If receiving has not posted a GR, the receipt leg is empty. Stop. Do not invent a GR quantity to complete the triangle.

Posting without a receipt is the first failure mode to refuse. Two-way match (invoice to PO) is a different control. If policy for this vendor or category requires three-way, an invoice that matches the PO on price and quantity is still not postable until a receipt exists. An agent that posts on PO plus invoice alone is skipping receiving. That is how you pay for goods that never hit the dock.

When the receipt exists, keep document number, line, quantity, UOM, and posting date. If several GRs cover one PO line, list each one the match consumes.

Match at line level, then decide auto-post vs exception

Match is line to line, not header to header. A header that shares a PO number is only a hint. The packet must cite invoice line n, PO line m, and GR line k, with quantity and price compared on those lines.

Walk each invoice line in order:

  1. Resolve the PO line from PO number plus line, or from a unique item and account assignment on that PO.
  2. Sum remaining received-not-invoiced quantity on that PO line from actual GR documents.
  3. Compare billed quantity to received quantity, billed price to PO price, and unit of measure to unit of measure.
  4. Write the three cites into the packet, or write nothing and raise an exception.

Tolerance belongs in policy, not in model confidence. If AP allows a stated price variance, encode that as a rule against the PO price. If receiving allows over-delivery, encode that against the GR. Do not let a high match score substitute for those rules.

Here is a single walkthrough, not a case study. A PO line calls for 40 boxes of copier paper at $32.00. Receiving posted GR 450821 for 40 boxes. The vendor invoices 40 boxes at $32.00. The agent writes: invoice line 1 cites PO 4500123456 line 10 and GR 450821 line 1; quantity 40 equals 40; price $32.00 equals $32.00. That packet is complete. AP can auto-post it under the usual parked-to-posted workflow.

Change one fact. Receiving posted GR 450821 for 38 boxes. The invoice still bills 40. The agent does not invent two boxes of receipt to close the gap. The three-way auto-post packet stays empty. The exception names the short receipt (38), the billed quantity (40), and the two units still unmatched. AP decides whether to wait for a second GR, short-pay, or return the invoice.

Change a different fact. There is no GR at all. The PO is open and the invoice is genuine. The agent still produces an empty match packet. The exception is receipt missing, not a draft GR.

Inventing a GR quantity is the second failure mode to refuse. Copying the invoice quantity into a fake receipt, or copying the PO quantity when receiving posted less, fabricates a warehouse event. That is worse than leaving the field blank. Empty stays empty.

Auto-post only where every required line has a complete three-cite packet and all variances sit inside tolerance. If the ERP cannot post clean lines and park the rest, route the whole invoice as an exception with the clean cites attached as evidence, not as a silent post.

After a clean match, GL coding suggestion can propose the expense or inventory account from the PO account assignment. The match packet does not replace coding. It proves the three-way condition. Coding still has to land on the right GL, cost center, or project.

A clean match is not a payment

Three-way match authorizes the AP invoice as a recognized liability. It does not mark the invoice paid, does not trigger a disbursement, and does not clear the vendor open item in the payment run.

Treating a clean match as paid is the third failure mode to refuse. An agent that sets payment status, adds the invoice to a payment proposal, or tells the vendor this is paid because the triangle closed is skipping treasury and payment controls. Match and pay are different stages. Cash still needs due date, discount terms, bank account, approval, and a payment file or check run.

Keep status language precise in the packet: matched, ready to post; or matched, posted, open for payment. Never write matched, paid unless a separate payment process has actually cleared the item.

AP still posts every exception

Exceptions are work items, not auto-posts with a warning flag. The agent routes them with enough evidence that an AP processor can act without re-keying the three documents.

Route at least these classes:

  • Missing receipt: hold; do not post; notify receiving if policy says so.
  • Quantity or price outside tolerance.
  • PO line missing, closed, or wrong.
  • Unit or item mismatch receiving did not confirm.
  • Duplicate or pre-flight failure: do not match; send back to those controls.

Each exception packet includes the invoice line, what was searched, what was found (including none), and the variance. It cites what exists and leaves missing legs empty.

AP posts. The agent does not. Processors park the document, apply GR/IR clearing, short-pay, request a credit, or return the invoice. Capture tools such as Vic.ai propose; Workday, SAP, or Oracle record the liability.

Do not let exception aging become silent posting. Escalate a missing GR to receiving; do not drop to two-way match unless a named owner changes the vendor rule.

You should be able to audit that every auto-posted invoice has three cites, every empty receipt leg is an open exception, no posted invoice carries a generated GR quantity, and no matched invoice is labeled paid until payment ran.

Is this worth automating for you?

Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other. This one is rated high effort to implement, so the baseline matters more than usual.

DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.

Measure the baseline first