The short answer
BR-CL-19 fails when cbc:AllowanceChargeReasonCode on an allowance (cbc:ChargeIndicator of false) is not one of the 19 codes in the UNTDID 5189 subset: 41, 42, 60, 62 to 68, 70, 71, 88, 95, 100 and 102 to 105. Replace the value with the code that describes the allowance, or remove the code and describe the allowance in cbc:AllowanceChargeReason.
The Peppol layer repeats the check as PEPPOL-EN16931-CL002, so an unknown code fails both layers. A plain discount is 95; the recorded example had the word DISCOUNT in its place.
What the rule checks
Every cbc:AllowanceChargeReasonCode inside a cac:AllowanceCharge that reads as an allowance is checked, wherever it sits: at document level, on a line, and, when tried, inside cac:Price as well.
Leading and trailing whitespace is ignored, and the remaining value must equal a listed code exactly. When tried, 95 with spaces around it passed.
Only the allowance list counts. A charge code such as CG, valid on a charge, was rejected on the document allowance when tried.
The permitted set is a Peppol subset of UNTDID 5189, so a code that exists in the full UNTDID list but not in the subset still fails.
An empty code element matches nothing and fails, together with PEPPOL-EN16931-R008 for the empty element.
The text beside the code is free and is not compared with it. When tried, code 95 next to the text Freight was accepted, because BR-CO-05, the agreement check, always passes in this release.
| Term | Meaning | UBL element |
|---|---|---|
| BT-98 | Document level allowance reason code | cac:AllowanceCharge/cbc:AllowanceChargeReasonCode |
| BT-140 | Invoice line allowance reason code | cac:InvoiceLine/cac:AllowanceCharge/cbc:AllowanceChargeReasonCode (cac:CreditNoteLine in a credit note) |
How an integration ends up here
Possible causes, from the shape of the rule rather than from measured usage:
- The integration writes its own discount type name, such as
DISCOUNTorPROMO, into the code element instead of a UNTDID code. - A charge code is reused for an allowance, or allowance and charge codes share one lookup table.
- The code comes from an internal numbering that also uses numbers, so a value such as
1or10looks plausible but is not on the list. - A code is added to every allowance, including ones whose source has no reason type, and a placeholder fills the gap.
How to fix it
- Read the finding location to see which allowance holds the code: one under the root, one on a line, or the price discount.
- Decide what the allowance is from its source record and find the matching entry in the UNTDID 5189 subset that Peppol publishes for BIS Billing 3.0.
95is Discount and100is Special rebate. - Write that code in
cbc:AllowanceChargeReasonCode. Keep your own label, if you want it on the document, incbc:AllowanceChargeReason. - If no code fits, remove
cbc:AllowanceChargeReasonCodeand keep the text. An allowance with text alone is valid; one with neither failsBR-CO-21orBR-CO-23. - Keep the mapping from your discount types to UNTDID codes as a table in the integration, separate from the charge mapping.
Validate your corrected invoice
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 document allowance has the word DISCOUNT as its reason code
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>DISCOUNT</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example document discount</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="GBP">1.00</cbc:Amount>
<!-- tax category omitted from this fragment -->
</cac:AllowanceCharge>Fragment of the corrected invoice: the reason code is 95, Discount
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>95</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example document discount</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="GBP">1.00</cbc:Amount>
<!-- tax category omitted from this fragment -->
</cac:AllowanceCharge>The failing invoice has DISCOUNT in the document allowance reason code; the corrected one has 95, the UNTDID 5189 code for Discount. The failing document also reports PEPPOL-EN16931-CL002, the Peppol copy of this code list check, at the same element, and the one correction clears both findings. The reason text is identical in the two documents.
What the validator reported
- The failing invoice reports BR-CL-19 and
PEPPOL-EN16931-CL002. The corrected document passes every layer with no findings.Download the failing XMLDownload the corrected 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
InvoiceandCreditNote, and to allowances oncac:InvoiceLineandcac:CreditNoteLine. When tried,DISCOUNTon the line allowance, and on the document allowance of a credit note, reported this rule andPEPPOL-EN16931-CL002together. - A reason code on the price discount inside
cac:Priceis checked too, but even a valid one there drew the warningsUBL-CR-633andUBL-CR-669when tried. A price discount is better sent without a code. - Charges use a different list, UNTDID 7161, which
BR-CL-20checks. Which list applies followscbc:ChargeIndicator.
Related rules
- BR-CL-20 is the code list check for charge reason codes
- BR-CO-21 requires a document-level allowance to have a reason code or text in the first place
- BR-CO-23 requires the same of allowances on a line
- Browse every rule in the reference
- Background: Understanding EN 16931 validation errors
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-24.1: source checked 2026-09-24, explanation last updated 2026-09-24.
The official definition of BR-CL-19 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.
