# BR-S-07: State a VAT rate above zero on a Standard rated document charge

A document-level charge in VAT category `S` needs a positive rate in `cbc:Percent`. Leaving the rate out fails, and so does a rate of 0.

- Layer: EN 16931
- Severity: fatal (the document is invalid)
- Topics: VAT, Allowances and charges
- Official definition: https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/BR-S-07/
- Explanation last updated: 2026-09-28

## The short answer

`BR-S-07` fails on each charge whose `cac:TaxCategory` has `cbc:ID` of `S` under the `VAT` scheme but no positive `cbc:Percent`. Write the Standard rate at which the charge is taxed; the freight charge in the recorded example had lost its rate entirely, and the corrected invoice states `20`.

Without a rate the charge cannot be matched to a Standard rated breakdown, so the taxable amount at 20 stops adding up as well.

## What the rule checks

The rule visits every `cac:TaxCategory` of `S` under the `VAT` scheme inside a `cac:AllowanceCharge` with `cbc:ChargeIndicator` of `true`, including one inside an invoice line: when tried, a line charge with its own `S` category at 0 reported this rule at `cac:InvoiceLine[1]/cac:AllowanceCharge[1]/cac:TaxCategory[1]`, together with the warning `UBL-CR-558`.

An absent `cbc:Percent` is not above zero, so it fails, as in the recorded example. The freight charge at a rate of `0` failed the same way when tried, again with `BR-S-08`.

An empty `cbc:Percent` never gets this far. When tried, `<cbc:Percent></cbc:Percent>` on the freight charge was rejected by the XSD layer, and the EN 16931 and Peppol layers were skipped.

The comparison is only with zero. A charge rate written as the fraction `0.2` passed this rule when tried, and `BR-S-08` reported the breakdown at 20 instead, because the charge no longer sat at that rate.

| Term | Meaning | UBL element |
|---|---|---|
| BT-102 | Document level charge VAT category code | `cac:AllowanceCharge[cbc:ChargeIndicator = true]/cac:TaxCategory/cbc:ID` |
| BT-103 | Document level charge VAT rate | `cac:AllowanceCharge[cbc:ChargeIndicator = true]/cac:TaxCategory/cbc:Percent` |

## How an integration ends up here

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

- The shipping or carrier module that adds the freight stores a tax category but no rate, and the export writes the category alone.
- Rates are only looked up for items, and a document-level charge has no item record to look one up from.
- Charges are exported with `cbc:Percent` set to 0 because the fee is treated as outside VAT, while the category is still `S`.
- A blank rate field in the source is dropped by the serialiser instead of being flagged, so the gap reaches the document.

## How to fix it

1. Find the charge from the finding location, `cac:AllowanceCharge[1]` in the recorded example. The index counts every `cac:AllowanceCharge` under the root, allowances and charges together.
2. Establish the VAT rate of the charge from its tax code. The Standard rated freight charge in the recorded example is taxed at `20`.
3. Write the rate to `cbc:Percent`, directly after `cbc:ID` in the charge's `cac:TaxCategory` and before `cac:TaxScheme`.
4. If the charge is not really Standard rated, give it the category that applies, with the rate that category requires, and move it to that breakdown.
5. Check that the Standard rated breakdown for the rate includes the charge in its taxable amount, which `BR-S-08` verifies.

## 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 freight charge says S but gives no rate

```xml
<cac:AllowanceCharge>
  <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
  <cbc:AllowanceChargeReasonCode>FC</cbc:AllowanceChargeReasonCode>
  <cbc:AllowanceChargeReason>Freight</cbc:AllowanceChargeReason>
  <cbc:Amount currencyID="GBP">7.50</cbc:Amount>
  <cac:TaxCategory>
    <cbc:ID>S</cbc:ID>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:AllowanceCharge>

<cac:TaxSubtotal>
  <cbc:TaxableAmount currencyID="GBP">32.50</cbc:TaxableAmount>
  <cbc:TaxAmount currencyID="GBP">6.50</cbc:TaxAmount>
  <cac:TaxCategory>
    <cbc:ID>S</cbc:ID>
    <cbc:Percent>20</cbc:Percent>
    <!-- tax scheme omitted from this fragment -->
  </cac:TaxCategory>
</cac:TaxSubtotal>
```

Fragment of the corrected invoice: the freight charge is Standard rated at 20

```xml
<cac:AllowanceCharge>
  <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
  <cbc:AllowanceChargeReasonCode>FC</cbc:AllowanceChargeReasonCode>
  <cbc:AllowanceChargeReason>Freight</cbc:AllowanceChargeReason>
  <cbc:Amount currencyID="GBP">7.50</cbc:Amount>
  <cac:TaxCategory>
    <cbc:ID>S</cbc:ID>
    <cbc:Percent>20</cbc:Percent>
    <cac:TaxScheme>
      <cbc:ID>VAT</cbc:ID>
    </cac:TaxScheme>
  </cac:TaxCategory>
</cac:AllowanceCharge>
```

The failing invoice has no `cbc:Percent` in the freight charge's `cac:TaxCategory`; the corrected one has `20` there, and nothing else differs. `BR-S-08` is reported as well: a charge without a rate is not counted at 20, so the Standard rated content at that rate falls to the 25.00 line against a taxable amount of 32.50. Restoring the rate clears both findings.

### What the validator reported

- The failing invoice reports **BR-S-07** and [BR-S-08](https://ironfang.com/docs/finance/rules/BR-S-08.md). The corrected document passes every layer with no findings.
  - [Download the failing XML](https://ironfang.com/finance/rule-examples/BR-S-07-invalid.xml)
  - [Download the corrected XML](https://ironfang.com/finance/rule-examples/standard-rated-charge-valid.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 made from the recorded example reported `BR-S-07` and `BR-S-08` when tried.
- The EN 16931 layer reports it as fatal, at the charge's `cac:TaxCategory`, for each offending charge.
- A charge without any `cac:TaxCategory` is caught by `BR-37` instead. Zero rated charges need a rate of exactly 0 under `BR-Z-07`.
- Allowances are covered by `BR-S-06` in the same way.

## Related rules

- [BR-S-06 is the same requirement for Standard rated document-level allowances](https://ironfang.com/docs/finance/rules/BR-S-06.md)
- [BR-S-08 adds the charge to the taxable amount at its rate, and failed alongside this rule in the recorded example](https://ironfang.com/docs/finance/rules/BR-S-08.md)
- [BR-37 requires every document-level charge to carry a VAT category](https://ironfang.com/docs/finance/rules/BR-37.md)
- [BR-S-04 requires a seller VAT identifier once a document-level charge is Standard rated](https://ironfang.com/docs/finance/rules/BR-S-04.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-28.1: source checked 2026-09-28, explanation last updated 2026-09-28.

[The official definition of BR-S-07](https://docs.peppol.eu/poacc/billing/3.0/rules/ubl-tc434/BR-S-07/) 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.com/docs/finance/rules/BR-S-07)
- [Free Peppol invoice validator](https://ironfang.com/tools/peppol-validator)
- [Rule index](https://ironfang.com/docs/finance/rules.md)
- [Ironfang Finance API docs](https://ironfang.com/docs/finance)
- The same rule is available to MCP clients as the tool `finance.rule.get` on https://mcp.ironfang.com/mcp
