On this page
The short answer
PEPPOL-EN16931-CL002 fails when cbc:AllowanceChargeReasonCode in an allowance whose cbc:ChargeIndicator reads exactly false is not one of the 19 codes on the Peppol UNTDID 5189 list. In the recorded example the line discount was sent as 095; the code is 95, with no padding.
The Peppol list and the one BR-CL-19 checks on the EN 16931 layer are identical, so a wrong code is normally reported by both. They differ in which allowances they look at: this rule only sees an indicator written as the exact text false.
What the rule checks
The allowance is recognised by the text of cbc:ChargeIndicator, compared exactly with false. When tried, false with spaces around it, which the schema accepts, took the allowance out of this rule: a bad code there was reported by BR-CL-19 alone.
An indicator of 0 is a valid schema boolean too, but not the text false. When tried with the code 095, it reported BR-CL-19 and PEPPOL-EN16931-R043, which accepts only true or false, and not this rule.
The code is trimmed before the comparison, and what remains must equal a listed code exactly; a leading zero makes a different value, as 095 shows.
The finding location says which allowance holds the code: in the recorded example the first cac:AllowanceCharge of the first invoice line.
| 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:
- Codes are formatted to a fixed width of three digits so that
100to105line up with the rest, which turns95into095. - Codes are stored as numbers and written out with a display format that pads them.
- A charge code or an internal discount type is written on an allowance.
- A lookup shared by allowances and charges hands a UNTDID 7161 code to a discount.
How to fix it
- Use the finding location to find the allowance and the discount it came from.
- Take the code from the Peppol list for UNTDID 5189 and write it as text without leading zeros:
95Discount,100Special rebate,41Bonus for works ahead of schedule. - Write
cbc:ChargeIndicatoras the plain textfalseon every allowance, so that both layers apply the same checks. - If no code fits, send
cbc:AllowanceChargeReasonalone.
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 line allowance reason code is padded to 095
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<!-- note, quantity, amounts and order line reference omitted from this fragment -->
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>095</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example discount</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>5</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="GBP">2.00</cbc:Amount>
<cbc:BaseAmount currencyID="GBP">40.00</cbc:BaseAmount>
</cac:AllowanceCharge>
<!-- line charge, item and price omitted from this fragment -->
</cac:InvoiceLine>Fragment of the corrected invoice: the reason code is 95, Discount
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<!-- note, quantity, amounts and order line reference omitted from this fragment -->
<cac:AllowanceCharge>
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>95</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example discount</cbc:AllowanceChargeReason>
<cbc:MultiplierFactorNumeric>5</cbc:MultiplierFactorNumeric>
<cbc:Amount currencyID="GBP">2.00</cbc:Amount>
<cbc:BaseAmount currencyID="GBP">40.00</cbc:BaseAmount>
</cac:AllowanceCharge>
<!-- line charge, item and price omitted from this fragment -->
</cac:InvoiceLine>Only the reason code of the line allowance differs: 095 in the failing invoice, 95 in the corrected one. The failing document also reports BR-CL-19, the EN 16931 check of the same code against the same list, at the same element.
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; when tried,095on a credit note line allowance reported this rule andBR-CL-19. - A Peppol BIS Billing 3.0 rule. With the indicator written as
falseit never fires withoutBR-CL-19, since the lists match, whileBR-CL-19can fire alone when the indicator is spelt another way. - Charges are checked against UNTDID 7161 by
PEPPOL-EN16931-CL003, the matching rule for an indicator oftrue.
Related rules
- BR-CL-19 checks allowance reason codes against the same list on the EN 16931 layer
- PEPPOL-EN16931-CL003 is the Peppol check for charge reason codes
- PEPPOL-EN16931-R043 requires the indicator to read true or false
- Browse every rule in the reference
- Background: How Peppol invoice validation actually works
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-28.1: source checked 2026-09-28, explanation last updated 2026-09-28.
The official definition of PEPPOL-EN16931-CL002 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.

