# BR-47: Add the VAT category code to each VAT breakdown

Every `cac:TaxSubtotal` needs a `cac:TaxCategory/cbc:ID` holding the VAT category code, in a tax category whose tax scheme is `VAT`.

- Layer: EN 16931
- Severity: fatal (the document is invalid)
- Topics: VAT
- Official definition: https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/BR-47/
- Explanation last updated: 2026-09-24

## The short answer

`BR-47` fails for each `cac:TaxSubtotal` whose `cac:TaxCategory` has no `cbc:ID`, or whose tax category is not under the `VAT` tax scheme. Add `cbc:ID` as the first child of `cac:TaxCategory`, carrying the category of the lines, allowances and charges that the breakdown totals: `S` in the recorded example.

A breakdown without a code matches no category, so the category rule for the lines it should cover fires as well; here that is `BR-S-01`.

## What the rule checks

The rule runs on every `cac:TaxSubtotal` inside a `cac:TaxTotal`. It passes when the subtotal has a `cac:TaxCategory` whose `cac:TaxScheme/cbc:ID` reads `VAT` and that category contains a `cbc:ID` element.

The tax scheme is trimmed and upper-cased before it is compared, so `vat` was accepted when tried. Another scheme is not: a breakdown under `GST` reported this rule, `BR-48` and `BR-CO-17`, because its category and rate were no longer read as VAT at all.

Only the presence of the element is tested. An empty `cbc:ID` passes this rule, but when tried it was reported by `BR-CL-17` as an invalid code, by `PEPPOL-EN16931-R008` as an empty element, and by `BR-S-01`.

Leaving out the whole `cac:TaxCategory` does not reach this rule. UBL requires one in every subtotal, and when tried the document failed the XSD layer instead.

| Term | Meaning | UBL element |
|---|---|---|
| BG-23 | VAT breakdown | `cac:TaxTotal/cac:TaxSubtotal` |
| BT-118 | VAT category code | `cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cbc:ID` |
| - | Tax scheme of the VAT category | `cac:TaxTotal/cac:TaxSubtotal/cac:TaxCategory/cac:TaxScheme/cbc:ID` |

## How an integration ends up here

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

- The VAT summary is keyed by rate alone, so the export knows 20% but not which category the rate belongs to.
- The category comes from a mapping of internal tax codes, and a code without a mapping is written as nothing instead of stopping the export.
- The tax scheme is filled from a generic tax type such as `GST` or `TAX` rather than the fixed value `VAT`.
- The serialiser writes `cac:TaxCategory` with only `cbc:Percent` and `cac:TaxScheme`, following a layout meant for another format.

## How to fix it

1. For each breakdown, find the VAT category of the items it totals: the `cac:ClassifiedTaxCategory/cbc:ID` of its lines and the `cac:TaxCategory/cbc:ID` of its document-level allowances and charges.
2. Write that code as `cbc:ID`, the first child of the breakdown `cac:TaxCategory`, before `cbc:Percent`. Use one of the permitted codes: `S`, `Z`, `E`, `AE`, `K`, `G`, `O`, `L`, `M` or `B`.
3. Set `cac:TaxScheme/cbc:ID` inside the same tax category to `VAT`.
4. Make an unmapped tax code stop the export, so a breakdown without a category is never sent.

## 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 line is fine, but its breakdown has no category code

```xml
<cac:TaxSubtotal>
  <cbc:TaxableAmount currencyID="GBP">25.00</cbc:TaxableAmount>
  <cbc:TaxAmount currencyID="GBP">5.00</cbc:TaxAmount>
  <cac:TaxCategory>
    <cbc:Percent>20</cbc:Percent>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:TaxSubtotal>

<cac:Item>
  <cbc:Name>Example service</cbc:Name>
  <cac:ClassifiedTaxCategory>
    <cbc:ID>S</cbc:ID>
    <cbc:Percent>20</cbc:Percent>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:ClassifiedTaxCategory>
</cac:Item>
```

Fragment of the corrected invoice: the breakdown is Standard rated, like its line

```xml
<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:ID>S</cbc:ID>` as the first child of the breakdown `cac:TaxCategory`; the failing one does not, and nothing else differs. The failing document also reports `BR-S-01`, because its line is Standard rated and, with the code gone, no breakdown says `S`. Adding the code clears both. The arithmetic rules stay silent: the rate and amounts are still present, and the Standard rated checks only run on a breakdown coded `S`.

### What the validator reported

- The failing invoice reports **BR-47** and [BR-S-01](https://ironfang.uk/docs/finance/rules/BR-S-01.md). The corrected document passes every layer with no findings.
  - [Download the failing XML](https://ironfang.uk/finance/rule-examples/BR-47-invalid.xml)
  - [Download the corrected XML](https://ironfang.uk/finance/rule-examples/invoice-minimal.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 `Invoice` and `CreditNote`. A credit note with the code removed from its breakdown reported the same two rules when tried.
- Reported by the EN 16931 layer; the Peppol layer passes the recorded example.
- The companion rule follows the category of the lines. With the `E` removed from an exempt breakdown, the findings were this rule and `BR-E-01` when tried.
- The line-level counterpart is `BR-CO-04`. Once a breakdown code is present, `BR-CL-17` checks that it is a permitted one.

## Related rules

- [BR-S-01 needs a breakdown coded S for Standard rated lines and is reported with this rule](https://ironfang.uk/docs/finance/rules/BR-S-01.md)
- [BR-CL-17 checks that the breakdown category code is one of the permitted codes](https://ironfang.uk/docs/finance/rules/BR-CL-17.md)
- [BR-CO-04 is the same requirement for the VAT category on each line](https://ironfang.uk/docs/finance/rules/BR-CO-04.md)
- [BR-48 requires the rate beside the category code in the same tax category](https://ironfang.uk/docs/finance/rules/BR-48.md)

## 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-47](https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/BR-47/) 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.

## Links

- [This rule as a web page](https://ironfang.uk/docs/finance/rules/BR-47)
- [Free Peppol invoice validator](https://ironfang.uk/tools/peppol-validator)
- [Rule index](https://ironfang.uk/docs/finance/rules.md)
- [Ironfang Finance API docs](https://ironfang.uk/docs/finance)
- The same rule is available to MCP clients as the tool `finance.rule.get` on https://mcp.ironfang.uk/mcp
