Skip to content

BR-48: Add the VAT rate to each VAT breakdown

Every VAT breakdown needs cbc:Percent in its tax category, even when the rate is 0. Only category O, not subject to VAT, may leave it out.

EN 16931Fatal: the document is invalidVAT

The short answer

BR-48 fails for each cac:TaxSubtotal whose VAT tax category has no cbc:Percent, unless the category is O. Add cbc:Percent to the breakdown cac:TaxCategory, straight after cbc:ID, with the rate as a percentage: 20 for 20%, and 0 for zero rated, exempt and the other categories that charge no VAT.

Category O is the single exception. A supply outside the scope of VAT has no rate to state, so its breakdown may omit the element.

What the rule checks

The rule runs on every cac:TaxSubtotal inside a cac:TaxTotal and reads the cac:TaxCategory whose tax scheme is VAT. It passes when that category has a cbc:Percent element, or when its cbc:ID is O.

Zero is a rate like any other. An exempt breakdown without cbc:Percent was reported by this rule alone when tried; the fix there is 0, not leaving the element out.

The exception only permits the rate to be absent. A category O breakdown carrying a cbc:Percent of 0 was also accepted when tried.

An empty cbc:Percent is not a number. When tried it failed the XSD layer, so this rule and the other business rules were never evaluated.

Line rates are not read. With the rate removed from a Standard rated line instead, the findings were BR-S-05 and BR-S-08 when tried, not this rule.

TermMeaningUBL element
BT-119VAT category ratecac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:Percent
BT-118VAT category codecac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:ID

How an integration ends up here

Possible causes, from the shape of the rule rather than from measured usage:

  • Zero rates are treated as no rate and suppressed, so zero rated and exempt breakdowns lose cbc:Percent.
  • The VAT summary is grouped by category only and the rate is not carried into the breakdown.
  • The exception for O is applied to every category that charges no VAT, removing the rate from exempt or reverse-charge breakdowns too.
  • The rate is held as text such as Standard, and the export drops it when it cannot be written as a number.

How to fix it

  1. For each breakdown, take the rate of the lines, allowances and charges it covers. A breakdown groups items by category and rate, so there is exactly one.
  2. Write it to cbc:Percent inside the breakdown cac:TaxCategory, after cbc:ID and before any exemption reason, as a percentage number: 20, not 0.2 or 20%.
  3. For Z, E, AE, K and G, write 0. Leave the element out only for O.
  4. Recalculate the subtotal cbc:TaxAmount from the taxable amount and the rate, since BR-CO-17 checks the two together.

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 Standard rated breakdown gives no rate

<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>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:TaxSubtotal>

Fragment of the corrected invoice: the rate of 20 follows the category code

<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>

The corrected invoice has <cbc:Percent>20</cbc:Percent> after the category code in the breakdown; nothing else differs. The failing document also reports BR-CO-17 and BR-S-09, which both check the 5.00 of tax as taxable amount x rate / 100 and cannot reach 5.00 without a rate. BR-CO-17 handles a missing rate like a zero one and expects tax that rounds to nothing; BR-S-09 has no answer at all without a rate. Restoring the rate clears all three.

What the validator reported

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 Invoice and CreditNote. A credit note with the rate removed from its breakdown reported the same three rules when tried.
  • Reported by the EN 16931 layer; the Peppol layer passes the recorded example.
  • A breakdown whose tax scheme is not VAT has no VAT rate as far as this rule can see: when tried, one under GST failed here despite its cbc:Percent, alongside BR-47 and BR-CO-17.

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-24.1: source checked 2026-09-24, explanation last updated 2026-09-24.

The official definition of BR-48 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.