# The three-way match gap: what ERPs miss

> Three-way matching checks invoice against PO and receipt. It does not test rate card tiers, surcharge triggers, or rebate terms. Here is why.

Source: https://valuexpa.com/insights/the-three-way-match-gap-what-your-erp-structurally-cannot
Publisher: ValueXPA (https://valuexpa.com)
Updated: 2026-09-05

---

Margin drift is the gap between what a vendor contract says and what the invoice actually charges. Three-way matching, the control most ERPs run by default, closes part of that gap and leaves the rest untouched.

The control was built to catch a different problem: an invoice that does not match what was ordered or received. It was never built to read a rate card, a rebate tier, or a surcharge expiration clause. That distinction matters because AP teams treat a passed match as a clean invoice, and for a large share of contract terms, it is not a test at all.

## Executive Summary

Three-way matching compares three documents: the purchase order, the receipt, and the invoice. When the three agree, the invoice pays. That comparison answers one question well: did the vendor bill for what was ordered and delivered? It answers nothing about whether the price on that PO was ever correct against the contract, whether a surcharge should have expired, or whether a volume tier changed the rate mid-period.

The mechanism is structural, not a training gap or a staffing shortfall. The PO carries a price field that gets set once, usually at requisition or approval, and the match logic checks the invoice against that field, not against the contract document that produced it. A contract lives in a PDF, a rate card, or a signed amendment, none of which the match engine reads.

Closing the gap does not require replacing the ERP. It requires a second check that reads the contract terms the match was never designed to see, run against the same invoice stream. What that check looks like, and where it fits against the audit and enforcement work described elsewhere on this site, is the subject of the sections below.

## 1. What does three-way matching actually check, and what does it leave out?

**Three-way matching confirms that the quantity and price on an invoice agree with the purchase order and that the goods or services were received. It is a document-agreement test, not a price-correctness test. It never opens the underlying contract, so a PO built on a stale or wrong rate passes the match every time, cleanly and repeatedly.**

The match logic runs on three fields it can compare directly: quantity ordered, quantity received, and price invoiced against price on the PO. All three live inside the ERP's own transaction tables, which is exactly why the check is fast and reliable for what it does.

A contract term is a different kind of object. A volume tier, a rebate clause, or a surcharge sunset date is conditional logic written in prose, sitting in a PDF outside the transaction tables the match engine reads. The engine has no field to compare it against.

This is why a vendor can bill correctly against a PO that was itself wrong, and the invoice sails through. The match was never asked whether the PO price reflects the contract. It was only asked whether the invoice reflects the PO.

## 2. Why does the PO price field freeze at the wrong moment?

**A PO price field is set once, at requisition or approval, and then treated as fixed truth for every invoice matched against it afterward. Contracts are not static: rates step down at volume thresholds, surcharges expire on a date, and rebates accrue against period totals. The PO field tracks none of that movement.**

Procurement enters a price when the PO is cut. From that point forward, the three-way match treats the number as correct until someone manually revises the PO. Nothing in the standard workflow prompts that revision when the contract itself changes.

A rate card with a step-down at a volume threshold is a clear example. The threshold is a condition on total spend across a period, not a single line item, so there is no PO event that triggers a recheck. The invoice keeps matching the frozen price long after the real rate has moved.

The fix is not a better PO template. It is a separate process that revisits the contract terms on a cadence and feeds corrected rates back into procurement, which is the subject of [price file governance](/guides/price-file-governance-why-annual-uploads-create-twelve), covered separately.

## 3. Can three-way matching catch a surcharge that has outlived its trigger condition?

**No. A fuel or peak-season surcharge is conditional on a date range or an index level stated in the contract, not on any field the match engine reads. The invoice line looks identical whether the surcharge is currently valid or expired, so the match passes in both cases with no way to distinguish them.**

A surcharge clause typically reads as an if-then statement: apply this charge while a condition holds, remove it once the condition lapses. The condition is written in the contract, evaluated against a calendar date or an external index, neither of which the ERP tracks against that invoice line.

Three-way matching has no concept of an expiration date attached to a charge type. It checks that the line item on the invoice equals the line item on the PO, and if the surcharge was ever added to the PO, it stays there until someone removes it by hand.

This is a distinct problem from a wrong base rate, and it needs a distinct control, one built around dating and reviewing surcharge conditions on their own schedule rather than relying on the match to notice when a condition has lapsed.

## 4. What about rebates and volume tiers, does the match ever touch them?

**Rebates and volume tiers are period-level calculations, not per-invoice ones, so the three-way match structurally cannot evaluate them. The match runs invoice by invoice. A rebate depends on cumulative spend across a quarter or a year, a number that does not exist at the moment any single invoice is being matched.**

Each of these failure modes has the same root cause: the match operates on a single document set, and a rebate or tier is a claim about a set of invoices considered together. No amount of tuning the three-way match closes this, because the calculation it would need to run sits outside its data model entirely.

The reconciliation that actually catches this compares accrued rebate against rebate actually received or credited, invoice by invoice, across the period. That comparison is covered on its own, since it is a distinct exercise from anything a PO-level match can do.

- **Volume tier triggers:** A rate that steps down after a spend threshold requires running total across every invoice in the period, a calculation the match never performs.

- **Rebate accrual terms:** An earned rebate sits in the contract as a formula against period spend, unconnected to any PO or receipt the match engine reads.

- **Timing mismatches:** A rebate earned in one quarter is often payable in the next, so the invoice that should reflect it has already been matched and paid.

- **Manual claim dependency:** Where a rebate must be claimed rather than applied automatically, nothing in the match workflow prompts anyone to file the claim.

## 5. Where do NTE caps and labor rate cards slip through the same structural gap?

**A not-to-exceed cap and a contract labor rate card both live in the master service agreement, not in the PO the invoice is matched against. Even where a timesheet was approved and the hours match what was worked, the billed rate can still diverge from the contract rate card, and three-way matching has no field for either check.**

An approved timesheet answers one question: did the person work the hours. It says nothing about whether the rate applied to those hours is the one the contract specifies for that role, seniority level, or site. A three-way match built around timesheet approval inherits that blind spot completely.

An NTE cap fails the same way from a different angle. Nothing in a standard PO structure represents a running ceiling across an engagement, so an invoice can clear the match every month while the cumulative total quietly passes the cap the contract set.

What three-way matching checks versus what the contract actually governs, by control point.

| Control point
| What three-way matching checks
| What the contract governs

| Hours billed
| Invoiced hours equal approved timesheet
| Whether the rate applied to those hours matches the rate card

| NTE cap
| Nothing, no field exists for it
| A ceiling on total billing per engagement or period

| Off-contract labor
| Invoiced role matches PO line
| Whether that role or resource was ever approved under the MSA

| Rate card tier
| PO price equals invoice price
| Whether the PO price itself reflects the current contract tier

## 6. What does it take to close the gap without replacing the ERP?

**Closing the gap means running a second layer of checks against the contract document itself, not against the PO, and running it on a cadence that matches how fast the terms move. That layer can sit alongside the existing ERP and match workflow rather than replacing either, since the ERP still does its own job correctly.**

Either way, the ERP and its three-way match keep doing exactly what they were built for: confirming that invoices agree with orders and receipts. The contract-level check is additive, not a replacement, and it can start from a vendor master and rate card that are already clean, which is its own prerequisite worth checking first.

### A. A one-time diagnostic

A retrospective pass reads the contracts, rebuilds the rate cards, tier thresholds and surcharge conditions as explicit rules, and runs the invoice history against those rules instead of against the PO. This finds what has already leaked in 12 to 18 months of historical spend, across ValueXPA diagnostics, and produces a prioritized list of which vendors and clauses to fix first.

### B. A standing control

Once the rules exist, applying them to every new invoice as it arrives is a different exercise from the one-time pass: continuous rather than periodic, and aimed at prevention rather than recovery. Choosing between running that check periodically or continuously is a cadence decision on its own, not an ERP replacement decision.

For the wider pattern this sits inside, start with the [margin drift](/guides/contract-compliance-controls-p2p) guide. See also [margin drift vs. legitimate price increases: how to tell them apart](/guides/margin-drift-vs-legitimate-price-increases-how-to-tell-them) and [accessorial charge audit: the surcharges nobody validates](/guides/accessorial-charge-audit-the-surcharges-nobody-validates).

## 7. Frequently Asked Questions (People Also Ask)

### Does three-way matching check invoices against the contract?

No. Three-way matching compares the invoice to the purchase order and the receipt. The PO price is set once and treated as correct from then on. It is never compared back against the contract, rate card, or rebate terms that should have produced it.

### Can I configure my ERP's matching rules to catch surcharge expirations?

Standard three-way matching has no field for a date-based or index-based condition attached to a charge line. Some ERPs allow custom validation rules, but building and maintaining those rules requires the same contract-reading work as a separate control, just implemented inside the ERP instead of alongside it.

### If a timesheet is approved, does that mean the invoice is correct?

An approved timesheet confirms hours worked. It does not confirm the rate billed for those hours matches the contract rate card, or that the total billed stays under a not-to-exceed cap. Those are separate checks that timesheet approval does not perform.

### Why doesn't my ERP flag when a vendor rate changes mid-contract?

The PO price field is static once set. A rate card step-down triggered by cumulative volume, or a negotiated rate change, has no mechanism inside standard PO workflows to update automatically and re-trigger a match.

### Is this a problem with our AP team, or with the system?

It is structural. Three-way matching was designed to confirm document agreement, not contract compliance. No amount of AP staff diligence changes what fields the match engine compares, since the contract terms sit outside the ERP's transaction data entirely.

### Do we need new software to close this gap?

Not necessarily. A one-time diagnostic can rebuild contract rules and test historical invoices against them without any system change. Whether to make that check continuous afterward is a separate, later decision.

### Does this apply to freight and 3PL invoices the same way as labor invoices?

The mechanism is the same across categories: a surcharge condition, a rate tier, or an NTE cap sits in the contract, not the PO, whether the vendor is a carrier or a staffing firm. The specific terms and how to test them differ by category.

### How do rebates fit into this if they aren't tied to any single invoice?

A rebate is calculated against cumulative spend across a period, not against one invoice. Three-way matching evaluates invoices one at a time, so it has no mechanism to hold a running total or compare it to an accrual formula.

### Is contract complexity quietly draining your operating margin?

A small systematic drift between your negotiated contracts and your actual vendor billing compounds quietly across a year of invoices. Stop guessing at your exposure and run a targeted audit.

**[Take the Free Screener → https://valuexpa.com/margin-drift-screener](https://valuexpa.com/margin-drift-screener)**

## Executive Summary

Three-way matching compares three documents: the purchase order, the receipt, and the invoice. When the three agree, the invoice pays. That comparison answers one question well: did the vendor bill for what was ordered and delivered? It answers nothing about whether the price on that PO was ever correct against the contract, whether a surcharge should have expired, or whether a volume tier changed the rate mid-period. The mechanism is structural, not a training gap or a staffing shortfall. The PO carries a price field that gets set once, usually at requisition or approval, and the match logic checks the invoice against that field, not against the contract document that produced it. A contract lives in a PDF, a rate card, or a signed amendment, none of which the match engine reads. Closing the gap does not require replacing the ERP. It requires a second check that reads the contract terms the match was never designed to see, run against the same invoice stream. What that check looks like, and where it fits against the audit and enforcement work described elsewhere on this site, is the subject of the sections below.

## 1. What does three-way matching actually check, and what does it leave out?

Three-way matching confirms that the quantity and price on an invoice agree with the purchase order and that the goods or services were received. It is a document-agreement test, not a price-correctness test. It never opens the underlying contract, so a PO built on a stale or wrong rate passes the match every time, cleanly and repeatedly. The match logic runs on three fields it can compare directly: quantity ordered, quantity received, and price invoiced against price on the PO. All three live inside the ERP's own transaction tables, which is exactly why the check is fast and reliable for what it does. A contract term is a different kind of object. A volume tier, a rebate clause, or a surcharge sunset date is conditional logic written in prose, sitting in a PDF outside the transaction tables the match engine reads. The engine has no field to compare it against. This is why a vendor can bill correctly against a PO that was itself wrong, and the invoice sails through. The match was never asked whether the PO price reflects the contract. It was only asked whether the invoice reflects the PO.

## 2. Why does the PO price field freeze at the wrong moment?

A PO price field is set once, at requisition or approval, and then treated as fixed truth for every invoice matched against it afterward. Contracts are not static: rates step down at volume thresholds, surcharges expire on a date, and rebates accrue against period totals. The PO field tracks none of that movement. Procurement enters a price when the PO is cut. From that point forward, the three-way match treats the number as correct until someone manually revises the PO. Nothing in the standard workflow prompts that revision when the contract itself changes. A rate card with a step-down at a volume threshold is a clear example. The threshold is a condition on total spend across a period, not a single line item, so there is no PO event that triggers a recheck. The invoice keeps matching the frozen price long after the real rate has moved. The fix is not a better PO template. It is a separate process that revisits the contract terms on a cadence and feeds corrected rates back into procurement, which is the subject of [price file governance](/guides/price-file-governance-why-annual-uploads-create-twelve), covered separately.

## 3. Can three-way matching catch a surcharge that has outlived its trigger condition?

No. A fuel or peak-season surcharge is conditional on a date range or an index level stated in the contract, not on any field the match engine reads. The invoice line looks identical whether the surcharge is currently valid or expired, so the match passes in both cases with no way to distinguish them. A surcharge clause typically reads as an if-then statement: apply this charge while a condition holds, remove it once the condition lapses. The condition is written in the contract, evaluated against a calendar date or an external index, neither of which the ERP tracks against that invoice line. Three-way matching has no concept of an expiration date attached to a charge type. It checks that the line item on the invoice equals the line item on the PO, and if the surcharge was ever added to the PO, it stays there until someone removes it by hand. This is a distinct problem from a wrong base rate, and it needs a distinct control, one built around dating and reviewing surcharge conditions on their own schedule rather than relying on the match to notice when a condition has lapsed.

## 4. What about rebates and volume tiers, does the match ever touch them?

Rebates and volume tiers are period-level calculations, not per-invoice ones, so the three-way match structurally cannot evaluate them. The match runs invoice by invoice. A rebate depends on cumulative spend across a quarter or a year, a number that does not exist at the moment any single invoice is being matched. Each of these failure modes has the same root cause: the match operates on a single document set, and a rebate or tier is a claim about a set of invoices considered together. No amount of tuning the three-way match closes this, because the calculation it would need to run sits outside its data model entirely. The reconciliation that actually catches this compares accrued rebate against rebate actually received or credited, invoice by invoice, across the period. That comparison is covered on its own, since it is a distinct exercise from anything a PO-level match can do. - Volume tier triggers: A rate that steps down after a spend threshold requires running total across every invoice in the period, a calculation the match never performs. - Rebate accrual terms: An earned rebate sits in the contract as a formula against period spend, unconnected to any PO or receipt the match engine reads. - Timing mismatches: A rebate earned in one quarter is often payable in the next, so the invoice that should reflect it has already been matched and paid. - Manual claim dependency: Where a rebate must be claimed rather than applied automatically, nothing in the match workflow prompts anyone to file the claim.

## 5. Where do NTE caps and labor rate cards slip through the same structural gap?

A not-to-exceed cap and a contract labor rate card both live in the master service agreement, not in the PO the invoice is matched against. Even where a timesheet was approved and the hours match what was worked, the billed rate can still diverge from the contract rate card, and three-way matching has no field for either check. An approved timesheet answers one question: did the person work the hours. It says nothing about whether the rate applied to those hours is the one the contract specifies for that role, seniority level, or site. A three-way match built around timesheet approval inherits that blind spot completely. An NTE cap fails the same way from a different angle. Nothing in a standard PO structure represents a running ceiling across an engagement, so an invoice can clear the match every month while the cumulative total quietly passes the cap the contract set. What three-way matching checks versus what the contract actually governs, by control point. | Control point | What three-way matching checks | What the contract governs | | --- | --- | --- | | Hours billed | Invoiced hours equal approved timesheet | Whether the rate applied to those hours matches the rate card | | NTE cap | Nothing, no field exists for it | A ceiling on total billing per engagement or period | | Off-contract labor | Invoiced role matches PO line | Whether that role or resource was ever approved under the MSA | | Rate card tier | PO price equals invoice price | Whether the PO price itself reflects the current contract tier |

## 6. What does it take to close the gap without replacing the ERP?

Closing the gap means running a second layer of checks against the contract document itself, not against the PO, and running it on a cadence that matches how fast the terms move. That layer can sit alongside the existing ERP and match workflow rather than replacing either, since the ERP still does its own job correctly. Either way, the ERP and its three-way match keep doing exactly what they were built for: confirming that invoices agree with orders and receipts. The contract-level check is additive, not a replacement, and it can start from a vendor master and rate card that are already clean, which is its own prerequisite worth checking first. ### A. A one-time diagnostic A retrospective pass reads the contracts, rebuilds the rate cards, tier thresholds and surcharge conditions as explicit rules, and runs the invoice history against those rules instead of against the PO. This finds what has already leaked in 12 to 18 months of historical spend, across ValueXPA diagnostics, and produces a prioritized list of which vendors and clauses to fix first. ### B. A standing control Once the rules exist, applying them to every new invoice as it arrives is a different exercise from the one-time pass: continuous rather than periodic, and aimed at prevention rather than recovery. Choosing between running that check periodically or continuously is a cadence decision on its own, not an ERP replacement decision. For the wider pattern this sits inside, start with the [margin drift](/guides/contract-compliance-controls-p2p) guide. See also [margin drift vs. legitimate price increases: how to tell them apart](/guides/margin-drift-vs-legitimate-price-increases-how-to-tell-them) and [accessorial charge audit: the surcharges nobody validates](/guides/accessorial-charge-audit-the-surcharges-nobody-validates).

## Common questions

### Does three-way matching check invoices against the contract?

No. Three-way matching compares the invoice to the purchase order and the receipt. The PO price is set once and treated as correct from then on. It is never compared back against the contract, rate card, or rebate terms that should have produced it.

### Can I configure my ERP's matching rules to catch surcharge expirations?

Standard three-way matching has no field for a date-based or index-based condition attached to a charge line. Some ERPs allow custom validation rules, but building and maintaining those rules requires the same contract-reading work as a separate control, just implemented inside the ERP instead of alongside it.

### If a timesheet is approved, does that mean the invoice is correct?

An approved timesheet confirms hours worked. It does not confirm the rate billed for those hours matches the contract rate card, or that the total billed stays under a not-to-exceed cap. Those are separate checks that timesheet approval does not perform.

### Why doesn't my ERP flag when a vendor rate changes mid-contract?

The PO price field is static once set. A rate card step-down triggered by cumulative volume, or a negotiated rate change, has no mechanism inside standard PO workflows to update automatically and re-trigger a match.

### Is this a problem with our AP team, or with the system?

It is structural. Three-way matching was designed to confirm document agreement, not contract compliance. No amount of AP staff diligence changes what fields the match engine compares, since the contract terms sit outside the ERP's transaction data entirely.

---

ValueXPA runs a fixed-scope Margin Drift Diagnostic that validates every service vendor invoice against contract terms, for $100M+ US industrial manufacturers and distributors. Two to four weeks. The client retains 100% of recoveries. https://valuexpa.com/contact-us
