Price variance between invoice and PO: how to calculate it and when to stop the payment
ininvoice: Price variance is calculated line by line with the formula price_variance = (invoice_price − PO_price) × invoice_quantity, always on pre-tax unit prices. Standard tolerance is 2% OR EUR 1.50 per line in OR mode (either condition triggers it). Example: 200 units, PO price EUR 1.00, invoice price EUR 1.05 → variance = (1.05 − 1.00) × 200 = EUR 10. If it exceeds tolerance, you stop the payment and open an exception for purchasing.
The price variance between invoice and PO is one of those numbers everyone assumes is well understood until the day a supplier sends an invoice above what was agreed and reconciliation takes two weeks.
This article explains the maths with three EUR examples. No “AI magic”. Just arithmetic a controller can reproduce in a spreadsheet. Thesis: variance is always calculated line by line on pre-tax unit prices, never on header totals.
The formula
The operational definition we use in three-way matching:
price_variance = (invoice_price − PO_price) × invoice_quantity
Three details that matter:
- Pre-tax. Unit prices without VAT. VAT is a percentage applied on top and should not enter the calculation.
- Unit. Price of one unit, not line total. If the supplier invoices 100 units instead of 80 at the right price, the price variance is zero (it is a quantity issue).
- Multiplied by invoiced quantity. To express the impact in euros. EUR 0.05 on 200 units is EUR 10; on 20,000 it is EUR 1,000. The formula gives you euros, which is what decides whether you stop the payment.
To separate price from quantity:
quantity_variance = (invoice_quantity − PO_quantity) × PO_price
That way each exception goes to the right team: price to purchasing, quantity to receiving.
Example 1: small discrepancy, automatic reconciliation
PO and invoice for a single line of 200 units of a consumable with an agreed price of EUR 1.00 pre-tax. The invoice arrives at EUR 1.05 pre-tax.
| Field | PO | Invoice |
|---|---|---|
| Quantity | 200 | 200 |
| Pre-tax unit price | EUR 1.00 | EUR 1.05 |
| Pre-tax line total | EUR 200.00 | EUR 210.00 |
Calculation:
price_variance = (1.05 − 1.00) × 200 = EUR 10.00
deviation_pct = (1.05 − 1.00) / 1.00 = 5.00%
5% exceeds 2% and EUR 10 exceeds EUR 1.50: the line is out of tolerance and flagged as an exception.
If the invoiced price had been EUR 1.005, the variance would be EUR 1.00 (200 × 0.005). Below EUR 1.50 absolute: within tolerance even though the percentage deviation is 0.5%. OR mode absorbs small roundings at low prices without blocking payments.
Example 2: significant discrepancy, exception to purchasing
Same scenario, but the supplier invoices at EUR 1.50 pre-tax.
price_variance = (1.50 − 1.00) × 200 = EUR 100.00
deviation_pct = 50.00%
50% and EUR 100. The line becomes an exception and the invoice is not approved without a buyer’s justification (contract change, rate error, rate revision). The most useful indicator for routing is not the percentage but the euros: EUR 100 is actionable for purchasing.
Example 3: the total matches but the lines don’t
This is the case that proves why comparing by header totals is a trap.
PO with three lines: A, B and C. Invoice with the same three lines. Invoice total equal to PO total.
| Line | Qty | PO price | Invoice price | PO total | Invoice total |
|---|---|---|---|---|---|
| A | 100 | EUR 2.00 | EUR 2.50 | EUR 200.00 | EUR 250.00 |
| B | 100 | EUR 3.00 | EUR 3.00 | EUR 300.00 | EUR 300.00 |
| C | 100 | EUR 5.00 | EUR 4.50 | EUR 500.00 | EUR 450.00 |
| Total | EUR 1,000.00 | EUR 1,000.00 |
The header total says EUR 1,000 on both sides. Perfect match. If your system cross-checks by totals, this invoice passes. Line by line:
- Line A: variance = (2.50 − 2.00) × 100 = +EUR 50.00
- Line B: variance = EUR 0.00
- Line C: variance = (4.50 − 5.00) × 100 = −EUR 50.00
A is EUR 50 overpriced, C has a EUR 50 discount. They cancel at the header but they hide two undisclosed contractual changes. If your purchase mix changes next month, you lose margin without noticing. That is why honest three-way matching is always line by line: the total never lies, but the lines do.
OR-mode tolerance: 2% or EUR 1.50
Per-line tolerance: 2% OR EUR 1.50 absolute. Stays within if either covers it. Not both. Why OR and not AND:
- Low prices. A EUR 2 toner with a EUR 0.05 deviation is 2.5% (above threshold) but only EUR 0.05 absolute. AND blocks it; OR lets it pass if the euros are small.
- High prices. EUR 5,000 equipment with a EUR 100 deviation: exactly 2% but EUR 100 absolute. AND lets it pass; OR applies the stricter condition.
OR mode mirrors how a controller decides by hand: if one of the two is small, I don’t fight.
Tolerance by purchase type
2% / EUR 1.50 is a reasonable default. For critical purchases adjust:
| Purchase type | Suggested % tolerance | Suggested EUR tolerance |
|---|---|---|
| Office supplies, consumables | 3% | EUR 2.00 |
| General equipment | 2% | EUR 1.50 |
| Critical raw materials | 0.5% | EUR 1.00 |
| Professional services | 5% | EUR 5.00 |
Price variance vs quantity variance
Two different variances, two different destinations:
- Price variance → purchasing. Why am I being invoiced at a different price from the one agreed?
- Quantity variance → warehouse / receiving. Why have I received a quantity different from what I ordered or what was invoiced?
If an invoice has both, you raise two exceptions in parallel. Mixing them in a single alert sends the wrong team to look at the problem.
When you do NOT stop the payment
Not every variance is an error. Three cases where the line is out of tolerance but the invoice is still payable:
- VAT and base rounding. Calculating the pre-tax unit by dividing line total by quantity creates millicent differences that absolute mode absorbs. The Spanish Royal Decree 1619/2012 on invoicing sets out how bases and taxes are broken down.
- Documented contractual adjustments. Signed addendum, price escalation, index revision. If the PO still reflects the previous price, the variance is a stale master-data artefact, not an error.
- Early-payment discount. If you agreed 2% for 7-day payment and the invoice comes gross, the apparent variance is a payment discount, not a matching alert.
In these cases the line is marked as reconciled with justification. That way it does not reappear next month with the same supplier.
What if we show you on your real invoices?
ininvoice cross-checks line by line with a 2% / EUR 1.50 OR-mode tolerance, separates price from quantity variance, and exports to your accounting. Book a spot and measure how many invoices would go touchless today.
Routing: who owns the exception and within what deadline
- Price variance: to the responsible buyer. Deadline: 48 business hours. No reply, escalate.
- Quantity variance: to warehouse / receiving. Deadline: 24h. Usually a partial delivery note or an unrecorded receipt.
- Double variance: both in parallel, not in series.
Resolution averages are published by IOFM: teams that cross-check line by line with automatic routing resolve exceptions in hours, not days.
Automation: how ininvoice applies it without re-keying
The variance calculation is trivial when data is structured. The real problem is keeping quantities, unit prices and clean descriptions on invoice, PO and delivery note all at once. ininvoice solves the full chain:
- Automatic intake from Gmail or Outlook with no manual forwarding.
- Structured reading of PDF, XML and FacturaE: prioritises signed data over pixels.
- Line-by-line matching by description with configurable 2% / EUR 1.50 OR tolerance.
- Automatic separation of price vs quantity variance with differentiated routing.
- Export to common accounting ERPs with verified data.
Full flow at three-way matching, touchless accounts payable and invoice and delivery note reconciliation.
FAQ
- Why compare pre-tax prices and not VAT-inclusive prices?
- VAT is a percentage on top of the taxable base. Comparing VAT-inclusive only adds noise. The Spanish BOE defines the breakdown in Royal Decree 1619/2012.
- Why multiply by invoice quantity and not by PO quantity?
- Because you express the deviation in euros actually invoiced. The 200 vs 100 unit gap is quantity variance and is calculated separately.
- What if the invoice price is lower than the PO price?
- The variance is negative. It is in your favour but still flagged and justified: a promotional discount or a supplier mistake that will be claimed via a correction invoice.
- What tolerance does IOFM recommend?
- IOFM publishes annual benchmarks. Typical mid-market tolerances sit between 1-3% and EUR 1-5 absolute per line. 2% / EUR 1.50 OR is a reasonable midpoint.
- Why OR mode and not AND?
- AND lets through what it shouldn’t at high prices and blocks what it shouldn’t at low prices. OR replicates the controller’s common sense.
- How is line-by-line matching done when descriptions vary?
- By semantic similarity of description plus article codes when available. “HP CF410A Toner” should match “HP 410A Black Toner”. Here IDP improves clearly over classic OCR.
- Does line-by-line variance work without a formal PO?
- Without a PO there is nothing to cross-check against. The alternative is matching against historical prices paid to that supplier, weaker but useful. For true three-way matching, purchases go through a PO.
How many of your invoices would go touchless with line-by-line variance today?
Connect Gmail or Outlook and measure the real rate on 30 days of your own invoices. Get started.
Three things to remember
- Price variance is calculated line by line, on pre-tax unit prices, multiplied by the invoiced quantity. Never on headers.
- Tolerance 2% OR EUR 1.50 absolute per line, OR mode. AND lets through what it shouldn’t at high prices and blocks what it shouldn’t at low prices.
- Separate price variance (to purchasing) from quantity variance (to warehouse). Mixing them sends the wrong team to the problem.
If you want to see how this looks on your own invoices, try ininvoice. You can also check the pricing and features.
Related content
See a demo with my invoices
Connect Gmail or Outlook. ininvoice ingests, cross-checks line by line with 2% / EUR 1.50 OR-mode tolerance and exports to your accounting.
Get started