What BR-CO-13 checks
BR-CO-13 defines the invoice's net total: Invoice total amount without VAT (BT-109) = Σ Invoice line net amount (BT-131) minus Sum of allowances on document level (BT-107) plus Sum of charges on document level (BT-108). It is the point where the three lower bookkeeping rules meet: the lines, the discounts, and the surcharges must combine, to the cent, into the declared net total. In UBL, BT-109 is the cbc:TaxExclusiveAmount of the legal monetary total.
Layer and formats
An en16931 core layer rule for every syntax and profile. Because the equation reuses the line amounts, an error low in the chain propagates: a wrong line amount typically fails BR-CO-10, BR-CO-13, BR-CO-15 and BR-CO-16 in one report. Fix bottom-up: lines first, then allowances and charges, then the derived totals.
Why it fails in practice
- Double-counted discounts. A rebate is baked into the line prices and declared again as a document level allowance, so BT-109 subtracts it twice relative to the lines.
- Charges missing from the total. Shipping or handling is added as a BG-21 charge group, but the pre-existing totals block never adds BT-108.
- Rounding at the wrong step. The net total is computed from unrounded intermediate values while the declared BT-131, BT-107 and BT-108 are already rounded; on the wrong invoice the results differ by a cent.
How to fix it
Compute BT-109 from the declared components, not from source data: sum the emitted line amounts, subtract the emitted allowance sum, add the emitted charge sum.
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="EUR">1000.00</cbc:LineExtensionAmount>
<cbc:AllowanceTotalAmount currencyID="EUR">50.00</cbc:AllowanceTotalAmount>
<cbc:ChargeTotalAmount currencyID="EUR">20.00</cbc:ChargeTotalAmount>
<cbc:TaxExclusiveAmount currencyID="EUR">970.00</cbc:TaxExclusiveAmount>
...
</cac:LegalMonetaryTotal>
In an InvoiceXML create request the field is totals.taxBasisTotalAmount, and the reliable fix is to omit invoice.totals entirely: the API derives the whole block from lines, allowances and charges server-side.
The raw rejection vs the InvoiceXML finding
The Schematron report hands you the equation and nothing else:
<svrl:failed-assert id="BR-CO-13" flag="fatal"
location="/*:Invoice[namespace-uri()='urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'][1]">
<svrl:text>[BR-CO-13]-Invoice total amount without VAT (BT-109) =
Σ Invoice line net amount (BT-131) - Sum of allowances on document
level (BT-107) + Sum of charges on document level (BT-108).</svrl:text>
</svrl:failed-assert>
The InvoiceXML finding for the same failure:
{
"rule": "BR-CO-13",
"layer": "en16931",
"line": null,
"message": "The total amount without VAT must equal the sum of line net amounts minus document level allowances plus document level charges. Check totals.",
"btCodes": ["BT-109", "BT-131", "BT-107", "BT-108"],
"fields": ["totals.taxBasisTotalAmount", "totals.sumOfAllowances", "totals.sumOfCharges"],
"raw": "[BR-CO-13] EN16931: Invoice total amount without VAT (BT-109) = Σ Invoice line net amount (BT-131) - Sum of allowances on document level (BT-107) + Sum of charges on document level (BT-108)."
}
The message is display-ready and fields lists the request paths involved in the equation, so your UI can highlight all of them. Localization stays a lookup by the stable rule key.
Check or generate documents with correct totals
Validate incoming files in the UBL validator or the XRechnung validator. If your own pipeline trips the chain, that first failing report is usually the argument for moving generation to the API too: POST /v1/create/ubl and POST /v1/create/facturx compute the chain server-side from your line items. The arithmetic is walked through in EN 16931 explained.