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.