Skip to content

Ironfang Finance - Rule reference

BR-CO-24: Give each line charge a reason code or reason text

A charge on an invoice or credit note line needs cbc:AllowanceChargeReasonCode, cbc:AllowanceChargeReason or both. BR-44 reports the same gap.

EN 16931Fatal: the document is invalidAllowances and chargesLines and prices

On this page

The short answer

BR-CO-24 fails when a line cac:AllowanceCharge with cbc:ChargeIndicator of true holds neither cbc:AllowanceChargeReasonCode nor cbc:AllowanceChargeReason. Say why the line costs more: a code from UNTDID 7161, a text, or both.

A failing document reports BR-44 as well. That EN 16931 rule makes exactly the same test on the same charge, so the two always appear together, and one reason clears both.

What the rule checks

Each cac:AllowanceCharge directly inside a line that reads as a charge is checked on its own. A line carrying a discount and a surcharge is judged element by element, and the discount is left to BR-CO-23.

Either element is enough, and only its presence counts. When tried, the charge with nothing but cbc:AllowanceChargeReasonCode ABL passed every layer, while an empty <cbc:AllowanceChargeReason/> passed BR-CO-24 and BR-44 and was rejected by PEPPOL-EN16931-R008.

Charge codes come from a different list from discount codes. When tried, code 95, which names a discount, on the line charge reported BR-CL-20 and PEPPOL-EN16931-CL003.

Charges directly under the document root are outside this rule. When tried, a document-level charge stripped of its reason reported BR-CO-22 and BR-38 instead.

TermMeaningUBL element
BG-28Invoice line chargescac:InvoiceLine/cac:AllowanceCharge[cbc:ChargeIndicator = true] (cac:CreditNoteLine/cac:AllowanceCharge in a credit note)
BT-144Invoice line charge reasoncac:InvoiceLine/cac:AllowanceCharge/cbc:AllowanceChargeReason
BT-145Invoice line charge reason codecac:InvoiceLine/cac:AllowanceCharge/cbc:AllowanceChargeReasonCode

How an integration ends up here

Possible causes, from the shape of the rule rather than from measured usage:

  • A surcharge such as a small-order or rush fee is added per line by a pricing rule that stores only the amount.
  • The line charge mapping was copied from the line discount mapping, and the reason fields were not carried across.
  • The reason text is optional in the source, and when it is empty no code is written in its place.
  • A sanitiser strips the reason text down to nothing, and the element is then omitted.

How to fix it

  1. Locate the charge from the finding, for example cac:InvoiceLine[1]/cac:AllowanceCharge[2]. The second index counts every cac:AllowanceCharge on the line, including the discount in front of it.
  2. Carry the charge type through from the pricing record that created it.
  3. Where the type matches an entry in UNTDID 7161, write that code to cbc:AllowanceChargeReasonCode. Add cbc:AllowanceChargeReason with a description, or send the text on its own when no code fits.
  4. Place the reason elements straight after cbc:ChargeIndicator, before cbc:MultiplierFactorNumeric and cbc:Amount. The charge amount and the line net amount stay as they are.

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 0.01 charge on line 1 has an amount and nothing to say what it is for

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <!-- note, quantity, line net amount, accounting cost, order line reference and line allowance omitted from this fragment -->
  <cac:AllowanceCharge>
    <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
    <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 line charge carries the reason text Example charge

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <!-- note, quantity, line net amount, accounting cost, order line reference and line allowance omitted from this fragment -->
  <cac:AllowanceCharge>
    <cbc:ChargeIndicator>true</cbc:ChargeIndicator>
    <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>

On line 1 the corrected invoice gives the 0.01 charge the reason text Example charge; the failing invoice has no reason on it and is otherwise the same. The failing document reports BR-44 together with BR-CO-24, both at cac:InvoiceLine[1]/cac:AllowanceCharge[2], because the two rules share one test. The line allowance before the charge keeps its code 95 and is not reported.

What the validator reported

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 cac:InvoiceLine in an Invoice and cac:CreditNoteLine in a CreditNote. When tried, the credit note version of the example reported BR-44 and BR-CO-24 at cac:CreditNoteLine[1]/cac:AllowanceCharge[2].
  • Both rules sit on the EN 16931 layer, and the Peppol layer has nothing to say about a missing reason. When a code is present, Peppol checks it against the charge list as PEPPOL-EN16931-CL003.
  • BR-44 has no page of its own in this reference; everything here applies to it unchanged.
  • A line charge has no VAT category of its own. It is part of the line net amount and is taxed with the line.

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 BR-CO-24 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.