Automation MCP Server Features Blog Pricing Contact
Validation rule EN 16931 core

BR-S-08

Each standard-rate VAT group must account for exactly the amounts taxed at its rate: BR-S-08 requires the taxable amount (BT-116) of every category S breakdown to equal the sum of the line amounts, document level charges and allowances carrying that same rate. Multi-rate invoices are its natural habitat.

What BR-S-08 checks

BR-S-08 audits the base of every standard-rate VAT group: for each distinct rate with category code S, the VAT category taxable amount (BT-116) must equal the sum of the invoice line net amounts (BT-131) plus document level charges (BT-99) minus document level allowances (BT-92) that declare the same category and rate. The breakdown group is not free-standing: it is an aggregation over the document, and this rule recomputes that aggregation.

Layer and formats

An en16931 core layer rule, applying to every syntax and profile. Its siblings do the same audit for the other categories (BR-Z-08 for zero rated, BR-E-08 for exempt, BR-AE-08 for reverse charge), and BR-CO-17 then verifies the multiplication inside each group.

Why it fails in practice

  • Multi-rate invoices grouped wrong. Lines at 7% and 19% end up in one group, or a rate change mid-contract leaves lines at the old rate feeding the new rate's group.
  • Charges and allowances without a category. A shipping charge taxed at 19% is emitted without its VAT category, so it never enters any group's base.
  • Stale breakdowns after line edits. A line is added or re-rated and the previously computed breakdown block is left untouched.

How to fix it

Rebuild each group's base from the rate-scoped amounts: group every line, charge and allowance by (category, rate), sum per group, and emit one cac:TaxSubtotal per group with that sum as BT-116. In an InvoiceXML create request the clean fix is omission: leave invoice.vatBreakdowns out, give every line its vatInformation (category and rate), and the API performs the grouping server-side. Line-scoped findings even come back with the concrete index, for example lines[3].vatInformation.rate, when a single line's rate is the culprit.

The raw rejection vs the InvoiceXML finding

The Schematron rule text is a hundred-word sentence; the report quotes it in full:

<svrl:failed-assert id="BR-S-08" flag="fatal"
    location="/*:Invoice[namespace-uri()='...']/cac:TaxTotal[1]/cac:TaxSubtotal[1]">
  <svrl:text>[BR-S-08]-For each different value of VAT category rate
    (BT-119) where the VAT category code (BT-118) is "Standard rated",
    the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23)
    shall equal the sum of Invoice line net amounts (BT-131) plus the
    sum of document level charge amounts (BT-99) minus the sum of
    document level allowance amounts (BT-92) where the VAT category
    code (BT-151, BT-102, BT-95) is "Standard rated" and the VAT rate
    (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119).</svrl:text>
</svrl:failed-assert>

The InvoiceXML finding for the same failure:

{
  "rule": "BR-S-08",
  "layer": "en16931",
  "line": null,
  "message": "The VAT breakdown for Standard rate must have a positive taxable amount and the correct rate. Check the tax breakdown.",
  "btCodes": ["BT-116", "BT-119"],
  "fields": null,
  "raw": "[BR-S-08] EN16931: For each different value of VAT category rate (BT-119) where the VAT category code (BT-118) is \"Standard rated\", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line net amounts (BT-131) ..."
}

Your end customer gets one actionable sentence instead of the hundred-word original, the BT codes anchor the finding to the breakdown fields, and the full rule text stays available in raw for debugging. Clients localize by the stable rule key.

Check or generate documents with consistent VAT

Validate a multi-rate document in the UBL validator or the XRechnung validator. Generation via POST /v1/create/ubl or POST /v1/create/facturx derives the groups from the lines server-side, so the bases match by construction. The category model is part of EN 16931 explained.

  • BR-CO-17, the multiplication inside each breakdown group
  • BR-CO-14, the sum of the groups against the invoice VAT total
  • BR-AE-10 and BR-E-10, the reason requirements of the 0% categories

Frequently asked questions

Why does the rule speak of 'each different value of VAT category rate'?

Because an invoice can legitimately carry several standard-rate groups, one per distinct rate: 19% and 7% in Germany, 20% and 5.5% in France. BR-S-08 checks each group against exactly the lines, charges and allowances declaring that group's rate; a line taxed at 7% must not leak into the 19% base.

What belongs in the taxable amount besides lines?

Document level charges taxed at the rate add to the base; document level allowances taxed at the rate subtract from it. Forgetting the VAT category on an allowance or charge is a classic way to unbalance the group it should have adjusted.

How does BR-S-08 differ from BR-CO-17?

BR-S-08 checks where the taxable amount comes from (the rate-scoped sum of lines, charges, allowances). BR-CO-17 checks what happens to it next (base times rate equals the group's tax amount). A wrong base fails BR-S-08 first, then usually drags BR-CO-17 and BR-CO-14 along.

Can documents created via the API fail this rule?

Not in practice. Omit invoice.vatBreakdowns in a /v1/create/* request and the API groups the lines by category and rate server-side, so every group's base is the rate-scoped sum by construction, validated before delivery.