On this page
The short answer
BR-O-08 fails when the cbc:TaxableAmount of an O breakdown differs from the document's O content: the cbc:LineExtensionAmount of each line in O, plus the root-level charges in O, minus the root-level allowances in O. The recorded invoice sends 25.00, the line alone, and forgets the 5.00 Loyalty discount; the right figure is 20.00.
The figure has to match to the penny. O has no rates to group by and the rule allows no tolerance, so there is one sum per document and it is compared exactly.
What the rule checks
The rule is evaluated at each cac:TaxCategory with cbc:ID O under the VAT scheme in cac:TaxTotal/cac:TaxSubtotal, and the sum is always built from the whole document. A duplicated O breakdown carrying the full 25.00 passed this rule twice when tried and was left to BR-O-01; split into 25.00 and 10.00 for two O lines, both parts failed here.
Lines are selected by cac:Item/cac:ClassifiedTaxCategory/cbc:ID of O, and allowances and charges by their own cac:TaxCategory/cbc:ID, directly under the root only. Line-level allowances and charges are already inside the line net amount and are not counted twice.
Charges add and allowances subtract. When tried, 30.00, the result of adding the 5.00 discount instead of deducting it, failed; so did 25.00 on an invoice where a 4.00 delivery charge in O had to be added to reach 29.00.
Exactness cuts both ways: 25.01 against a single O line of 25.00 reported this rule when tried, while 25 written in place of 25.00 passed, because the values are compared as numbers.
| Term | Meaning | UBL element |
|---|---|---|
| BT-116 | VAT category taxable amount | cac:TaxTotal/cac:TaxSubtotal/cbc:TaxableAmount |
| BT-118 | VAT category code | cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:ID |
| BT-131 | Invoice line net amount | cac:InvoiceLine/cbc:LineExtensionAmount (cac:CreditNoteLine/cbc:LineExtensionAmount in a credit note) |
| BT-92 | Document level allowance amount | cac:AllowanceCharge[cbc:ChargeIndicator = false]/cbc:Amount |
| BT-99 | Document level charge amount | cac:AllowanceCharge[cbc:ChargeIndicator = true]/cbc:Amount |
How an integration ends up here
Possible causes, from the shape of the rule rather than from measured usage:
- The taxable amount is copied from the sum of the line net amounts, so a document-level discount or charge in
Onever reaches it. - The allowance is added instead of subtracted, or a charge is subtracted, when the breakdown is built.
- Amounts from other nil-VAT categories, such as Zero rated or exempt lines, are pooled into the
Ofigure. - The breakdown is taken from a tax summary stored before the allowance or charge was added to the order.
- One
Obreakdown is written per line, so each holds only part of the total.
How to fix it
- Start from the lines in
O: in the recorded example, line 1 with acbc:LineExtensionAmountof 25.00. Keep the sign of any negative line. - Bring in the root-level
cac:AllowanceChargeelements inO, charges (cbc:ChargeIndicatortrue) with a plus sign and allowances (false) with a minus sign: here only the 5.00Loyalty discount, giving 20.00. - Write the result with two decimals as the
cbc:TaxableAmountof the oneOcac:TaxSubtotal, and leave its tax amount at0.00, asBR-O-09requires. - Cross-check with
cbc:TaxExclusiveAmount, which is built from the same parts: on an invoice entirely inOthe two figures are equal, 20.00 in the recorded example.
The recorded example has one line and one document-level allowance, both in category O, and no document-level charge.
Line net amount in O: 25.00 Document-level charges in O: none, so + 0.00 Document-level allowance in O, the loyalty discount: - 5.00 Expected O taxable amount: 25.00 + 0.00 - 5.00 = 20.00 Sent: 25.00, the line total alone, so the rule fails
Validate your corrected invoice
Before and after
These are fragments, not complete documents. The complete synthetic documents they come from are linked below.
Fragment of the failing invoice: 25.00 taxable in O, although the O discount of 5.00 brings the O content to 20.00
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<!-- reason code 95 and reason omitted from this fragment -->
<cbc:Amount currencyID="GBP">5.00</cbc:Amount>
<cac:TaxCategory>
<cbc:ID>O</cbc:ID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="GBP">0.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="GBP">25.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="GBP">0.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>O</cbc:ID>
<!-- reason code and text omitted from this fragment -->
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<!-- line 1 in category O: LineExtensionAmount 25.00 -->Fragment of the corrected invoice: 25.00 - 5.00 = 20.00 taxable in O
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="GBP">20.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="GBP">0.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>O</cbc:ID>
<cbc:TaxExemptionReasonCode>VATEX-EU-O</cbc:TaxExemptionReasonCode>
<cbc:TaxExemptionReason>Not subject to VAT</cbc:TaxExemptionReason>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>Only the O cbc:TaxableAmount differs: 25.00 in the failing invoice and 20.00 in the corrected one. The failing document reports only BR-O-08. Its monetary totals already deduct the discount, with cbc:TaxExclusiveAmount and cbc:PayableAmount at 20.00 in both documents, and nothing else in it reacts to the wrong breakdown figure.
What the validator reported
- The failing invoice reports BR-O-08. The corrected document passes every layer with no findings.Download the failing XMLDownload the corrected XML
Recorded on phive 12.1.0 / phive-rules-peppol 4.5.6 / Saxon-HE 12.10, the engine behind the free validator, using synthetic data. A recorded result is regression evidence for these documents; it is not a certification.
Where it applies
- Applies to UBL
InvoiceandCreditNote; for a credit note the rule adds upcac:CreditNoteLinenet amounts, and the failing invoice rewritten that way reported this rule again when tried. - The rule presumes one
Obreakdown.BR-O-01requires exactly that, andBR-O-09requires its tax amount to be 0. - Taxable amounts in other categories are checked by rules of their own, such as
BR-S-08for Standard rated breakdowns, which tolerates a difference under 1.00 where this rule tolerates none.
Related rules
- BR-O-01 requires the single O breakdown whose taxable amount this rule checks
- BR-O-09 requires the tax amount beside this taxable amount to be zero
- BR-S-08 is the Standard rated taxable amount check, grouped by rate and with a tolerance
- BR-CO-13 checks the total without VAT, built from the same line, allowance and charge amounts
- Browse every rule in the reference
- Background: Understanding EN 16931 validation errors
Scope and source
Written for Peppol BIS Billing 3.0.21 (May 2026), EN 16931 1.3.16, as applied to UBL 2.1 Invoice and CreditNote documents. Other profiles, syntaxes and releases can define this identifier differently. Guidance version 2026-09-28.1: source checked 2026-09-28, explanation last updated 2026-09-28.
The official definition of BR-O-08 carries the normative wording and test. This page is our explanation of it, not a copy.
Guidance does not change the engine verdict. Fixing this finding does not mean the document passes every layer, and validation does not certify legal or tax compliance or transmit a document over Peppol.

