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

BR-CO-10

BR-CO-10 is the first link in the totals chain: the declared sum of invoice line net amounts (BT-106) must equal the actual sum of every line's net amount (BT-131), to the cent. It is where rounding strategies and float arithmetic come to confess.

What BR-CO-10 checks

BR-CO-10 is pure arithmetic: Sum of Invoice line net amount (BT-106) = Σ Invoice line net amount (BT-131). The document declares a sum over its own lines, and the validator recomputes it. In UBL, BT-106 is cbc:LineExtensionAmount inside cac:LegalMonetaryTotal, and each BT-131 is the cbc:LineExtensionAmount of an invoice line; CII has the same pair under SpecifiedTradeSettlementHeaderMonetarySummation and the line settlement. There is no tolerance: a single cent of drift fails the rule.

Layer and formats

The finding carries "layer": "en16931". BR-CO-10 fires in every format and profile, from plain UBL to XRechnung, Peppol BIS and the CII inside hybrid PDFs. It is the head of a chain of calculation rules: BR-CO-13 derives the total without VAT from the lines, BR-CO-14 ties the VAT total to the breakdown, BR-CO-15 and BR-CO-16 carry the arithmetic to the amount due. An error in one line ripples through all of them, so fix the chain bottom-up.

Why it fails in practice

  • Round-then-sum vs sum-then-round. Lines are rounded to two decimals individually while the header total was computed from unrounded values, or vice versa.
  • Floating-point arithmetic. Binary floats accumulate errors that surface exactly at the second decimal; totals computed with double instead of decimal types drift by a cent.
  • Filtered or edited lines. A line was removed or a quantity corrected after the totals were computed, and the header block was never refreshed.

How to fix it

Recompute BT-106 as the sum of the BT-131 values you actually emit, using decimal arithmetic, and refresh it whenever a line changes. In an InvoiceXML create request the simplest fix is to not send totals at all: leave invoice.totals out and the API computes totals.sumOfLineNetAmounts and the rest of the chain from invoice.lines server-side. If you do supply totals, they are validated and any mismatch comes back as a finding before a broken document ever leaves the API.

The raw rejection vs the InvoiceXML finding

The Schematron report states the equation and leaves the debugging to you:

<svrl:failed-assert id="BR-CO-10" flag="fatal"
    location="/*:Invoice[namespace-uri()='urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'][1]">
  <svrl:text>[BR-CO-10]-Sum of Invoice line net amount (BT-106) =
    Σ Invoice line net amount (BT-131).</svrl:text>
</svrl:failed-assert>

The InvoiceXML finding for the same failure:

{
  "rule": "BR-CO-10",
  "layer": "en16931",
  "line": null,
  "message": "The sum of line net amounts does not match the total of all line amounts. Recalculate line totals.",
  "btCodes": ["BT-106", "BT-131"],
  "fields": ["totals.sumOfLineNetAmounts"],
  "raw": "[BR-CO-10] EN16931: Sum of Invoice line net amount (BT-106) = Σ Invoice line net amount (BT-131)."
}

The message reads like something you can show a customer, and fields points at the request field to correct. Because the message table is keyed by rule code, clients can localize by rule and keep the field mapping.

Check or generate documents with correct totals

Validate incoming files with the UBL validator or the XRechnung validator. If your own documents fail the totals chain, that first red report is usually the argument for moving generation to the API too: with POST /v1/create/ubl or POST /v1/create/facturx the chain is computed server-side from your line items and cannot drift. The arithmetic rules are walked through in EN 16931 explained.

  • BR-CO-10, the line sum (BT-106), this page
  • BR-CO-11, the allowance sum (BT-107)
  • BR-CO-13, the total without VAT (BT-109)
  • BR-CO-14, the VAT total against the breakdown (BT-110)
  • BR-CO-15, the total with VAT (BT-112), and BR-CO-16, the amount due (BT-115)
  • BR-16, at least one invoice line must exist for the sum to mean anything

Frequently asked questions

My total is off by one cent. Why?

Almost always rounding. If you round per line and then sum, versus sum unrounded values and round once, the results can differ by a cent. EN 16931 compares the declared BT-106 against the sum of the (declared, already rounded) BT-131 values, so compute BT-106 by summing exactly the line amounts you emit.

Is BR-CO-10 the same as BR-CO-13?

No. BR-CO-10 checks BT-106 against the sum of the lines. BR-CO-13 then checks that the invoice total without VAT (BT-109) equals BT-106 minus document-level allowances (BT-107) plus charges (BT-108). They usually fail together when a line amount is wrong, because the error propagates up the chain.

Which formats does BR-CO-10 apply to?

All of them. It is an en16931 core layer rule, inherited by UBL, CII, XRechnung, Peppol BIS, Factur-X and ZUGFeRD alike. There is no profile that relaxes the totals arithmetic.

Can documents created via the API fail this rule?

Not in practice. When you omit totals in a /v1/create/* request, BT-106 and the rest of the chain are computed server-side from the line items, and every generated document is validated against the full rule set before delivery. The rule bites on documents arriving from other systems.