On this page
The short answer
PEPPOL-EN16931-CL003 fails when cbc:AllowanceChargeReasonCode in a charge whose cbc:ChargeIndicator reads exactly true is not on the Peppol UNTDID 7161 list. The recorded line charge was coded DEL; the code for a delivery charge is DL.
DEL looks plausible because it is a real code on another list: the UNTDID 4451 note subjects that BR-CL-08 checks. Charge reasons come only from UNTDID 7161, and BR-CL-20 applies that same list on the EN 16931 layer, so both rules report the value.
What the rule checks
Only charges whose indicator is the exact text true are in scope. When tried, true with spaces and 1, both valid booleans to the schema, kept a DEL code away from this rule: BR-CL-20 reported it in both cases, and PEPPOL-EN16931-R043 added a finding for 1.
The code is trimmed and then compared case-sensitively with the 178 codes of the list, which are the same as those of BR-CL-20.
Document and line charges are both covered. In the recorded example the finding points at cac:InvoiceLine[1]/cac:AllowanceCharge[2]/cbc:AllowanceChargeReasonCode[1].
The code is not compared with the charge text: in the corrected invoice, DL beside the text Example charge passed.
| Term | Meaning | UBL element |
|---|---|---|
| BT-105 | Document level charge reason code | cac:AllowanceCharge/cbc:AllowanceChargeReasonCode |
| BT-145 | Invoice line charge 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:
- A code from another UN/EDIFACT list is used because it reads like the service, such as
DELfrom the note subject list for a delivery charge. - Abbreviations from the source system, such as
FRTfor freight, are written as codes. - An allowance code is sent on a charge because one mapping serves both.
- Codes are held in lower case and written unchanged.
How to fix it
- Find the charge from the finding location: a document charge under the root or a charge inside a line.
- Look the service up in the Peppol UNTDID 7161 list:
DLDelivery,FCFreight service,PCPacking,ABLAdditional packaging. - Write the code in upper case in
cbc:AllowanceChargeReasonCode, and writecbc:ChargeIndicatorastrue, so both layers see the charge. - Keep charge codes in a table of their own, apart from allowance codes and note subject codes.
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 charge reason code is DEL
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<!-- note, quantity, amounts, order line reference and line allowance omitted from this fragment -->
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>DEL</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example charge</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="GBP">0.01</cbc:Amount>
</cac:AllowanceCharge>
<!-- item and price omitted from this fragment -->
</cac:InvoiceLine>Fragment of the corrected invoice: the reason code is DL, Delivery
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<!-- note, quantity, amounts, order line reference and line allowance omitted from this fragment -->
<cac:AllowanceCharge>
<cbc:ChargeIndicator>true</cbc:ChargeIndicator>
<cbc:AllowanceChargeReasonCode>DL</cbc:AllowanceChargeReasonCode>
<cbc:AllowanceChargeReason>Example charge</cbc:AllowanceChargeReason>
<cbc:Amount currencyID="GBP">0.01</cbc:Amount>
</cac:AllowanceCharge>
<!-- item and price omitted from this fragment -->
</cac:InvoiceLine>Only the reason code of the line charge differs: DEL in the failing invoice, DL in the corrected one. The failing document also reports BR-CL-20, which applies the same UNTDID 7161 list on the EN 16931 layer, at the same element.
What the validator reported
- The failing invoice reports BR-CL-20 and PEPPOL-EN16931-CL003. 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;DELon a credit note line charge reported this rule andBR-CL-20when tried. - A Peppol BIS Billing 3.0 rule. Allowances are checked against UNTDID 5189 by
PEPPOL-EN16931-CL002instead. - Whether a charge needs a reason at all is decided elsewhere, by
BR-CO-22for document charges andBR-CO-24for line charges.
Related rules
- BR-CL-20 checks charge reason codes against the same list on the EN 16931 layer
- PEPPOL-EN16931-CL002 is the Peppol check for allowance reason codes
- BR-CL-08 is where UNTDID 4451 subject codes such as DEL belong, in the invoice note
- PEPPOL-EN16931-R043 rejects an indicator written as 1 or 0
- 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-CL003 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.

