The short answer
BR-CO-18 fails when the document has no cac:TaxSubtotal inside a cac:TaxTotal directly under the root. Add one cac:TaxSubtotal for each VAT category and rate used on the lines and the document-level allowances and charges, with its taxable amount, tax amount and cac:TaxCategory.
A cac:TaxTotal that carries only the overall cbc:TaxAmount is not enough, even when that amount is correct.
What the rule checks
This is a presence check on the document root: at least one cac:TaxTotal/cac:TaxSubtotal must exist. It does not look inside the breakdown; the amounts and the category are checked by other rules.
The XSD accepts a cac:TaxTotal without any cac:TaxSubtotal, and a document without a cac:TaxTotal at all, so the omission is first reported here rather than by the schema layer.
A document with no VAT to pay still needs a breakdown. An exempt invoice with a VAT total of 0.00 fails this rule once its cac:TaxSubtotal is removed.
| Term | Meaning | UBL element |
|---|---|---|
| BG-23 | VAT breakdown | cac:TaxTotal/cac:TaxSubtotal |
How an integration ends up here
Possible causes, from the shape of the rule rather than from measured usage:
- The mapping writes the VAT total from a header field and never builds the per-category breakdown.
- The breakdown is generated only when the VAT amount is above zero, so zero-rated, exempt or reverse-charge documents lose it.
- The source grouping by VAT category returns no rows, for example because lines have no tax code assigned, and the loop that writes
cac:TaxSubtotalemits nothing. - The breakdown is written into a
cac:TaxTotalunder each line instead of the document-levelcac:TaxTotal. Only breakdowns directly under the root count.
How to fix it
- Group the line net amounts, document-level allowances and document-level charges by VAT category code and rate.
- For each group write a
cac:TaxSubtotalwithcbc:TaxableAmount,cbc:TaxAmountand acac:TaxCategoryholdingcbc:ID,cbc:Percentandcac:TaxScheme/cbc:IDofVAT. Some categories also need an exemption reason. - Put the breakdowns in the
cac:TaxTotalthat carries the VAT total in the document currency, and make thatcbc:TaxAmountthe sum of the breakdown tax amounts.BR-CO-14checks it. - Use the VAT categories the transaction really has. Do not add a breakdown for a category that is not on the lines just to satisfy this rule.
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: the tax total has an amount but no breakdown
<cac:TaxTotal>
<cbc:TaxAmount currencyID="GBP">5.00</cbc:TaxAmount>
</cac:TaxTotal>Fragment of the corrected invoice: one standard-rated breakdown for the single line of 25.00
<cac:TaxTotal>
<cbc:TaxAmount currencyID="GBP">5.00</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="GBP">25.00</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="GBP">5.00</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>20</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>The corrected document has the cac:TaxSubtotal that the failing one lacks; nothing else differs. The failing document also reports BR-S-01, because its line is standard rated and no standard-rated breakdown exists, and two Peppol findings about the shape of the tax totals: PEPPOL-EN16931-R053, because no tax total carries a breakdown, and PEPPOL-EN16931-R054, because a tax total without a breakdown is present although no VAT accounting currency is declared. Restoring the breakdown clears all four.
What the validator reported
- The failing invoice reports BR-CO-18, BR-S-01,
PEPPOL-EN16931-R053andPEPPOL-EN16931-R054. 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
InvoiceandCreditNotealike; a credit note with its only breakdown removed reports the same four findings. - The category rule that accompanies this finding depends on the VAT categories in the document. The recorded example is standard rated and reports
BR-S-01; an exempt invoice reports the corresponding exempt-category rule instead. BR-CO-14stays silent in this situation. It skips a tax total that has no breakdown, so the VAT total is not compared with a breakdown until one is back.- An empty
cac:TaxSubtotalelement is no way round the rule: the XSD layer rejects it and the later layers are skipped.
Related rules
- BR-S-01 requires a standard-rated breakdown when lines, allowances or charges are standard rated
- BR-CO-14 checks the VAT total against the sum of the breakdown tax amounts
- BR-CO-17 checks each breakdown tax amount against its taxable amount and rate
- BR-S-08 checks the taxable amount of a standard-rated breakdown against the lines, allowances and charges
- Browse every rule in the reference
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-20.1: source checked 2026-09-20, explanation last updated 2026-09-20.
The official definition of BR-CO-18 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.
