Skip to content

BR-CO-23: Add a reason to each allowance on an invoice line

An allowance attached to an invoice or credit note line must name its reason with a code, text or both. The price discount inside cac:Price is not covered.

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

The short answer

BR-CO-23 fails when a cac:AllowanceCharge inside cac:InvoiceLine (or cac:CreditNoteLine) has cbc:ChargeIndicator of false and carries neither cbc:AllowanceChargeReasonCode nor cbc:AllowanceChargeReason. Give the line discount its reason: a UNTDID 5189 code, a description, or both.

The same allowance is also reported as BR-42, a second EN 16931 rule with an identical test. Adding the reason once satisfies both.

What the rule checks

The rule looks at each cac:AllowanceCharge that is a direct child of a line and reads as an allowance. The allowance is accepted as soon as either reason element exists in it.

Every allowance is judged on its own, so a line with two allowances needs a reason on each, and each line in the document is visited.

The price discount inside cac:Price is a different element and is outside this rule. The recorded price-discount example has no reason on its price-level allowance and validates cleanly.

Line charges are outside it too. The rich invoice has a line charge with reason text and no code, which is enough for its own rule, BR-CO-24.

An element that exists satisfies the rule even with no content. When tried, an empty cbc:AllowanceChargeReason on the line allowance passed BR-CO-23 and was reported by PEPPOL-EN16931-R008 instead.

TermMeaningUBL element
BG-27Invoice line allowancescac:InvoiceLine/cac:AllowanceCharge[cbc:ChargeIndicator = false] (cac:CreditNoteLine/cac:AllowanceCharge in a credit note)
BT-139Invoice line allowance reasoncac:InvoiceLine/cac:AllowanceCharge/cbc:AllowanceChargeReason
BT-140Invoice line allowance 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 customer or volume discount is applied per line by a pricing engine that records the percentage and amount but not the discount type.
  • Line allowances are generated from the difference between list price and selling price, which leaves no reason to attach.
  • The reason is mapped for document-level allowances, but the line-level mapping was written separately and omits it.
  • The reason text is trimmed or sanitised to nothing, and the element is then left out.

How to fix it

  1. Find the line and the allowance in the finding location, for example cac:InvoiceLine[1]/cac:AllowanceCharge[1]. The second index counts every cac:AllowanceCharge on that line, charges included.
  2. Carry the discount type through from the pricing record that produced the allowance.
  3. Where the type matches a UNTDID 5189 entry, write that code in cbc:AllowanceChargeReasonCode (95 for a plain discount). Add cbc:AllowanceChargeReason with the description, or send the text alone when no code fits.
  4. Keep the elements in UBL order, straight after cbc:ChargeIndicator and before cbc:MultiplierFactorNumeric and cbc:Amount. No amount on the line needs recalculating.

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 5 per cent allowance on line 1 has no reason, the line charge beside it has one

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <!-- note, quantity, line net amount, accounting cost and order line reference omitted from this fragment -->
  <cac:AllowanceCharge>
    <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
    <cbc:MultiplierFactorNumeric>5</cbc:MultiplierFactorNumeric>
    <cbc:Amount currencyID="GBP">2.00</cbc:Amount>
    <cbc:BaseAmount currencyID="GBP">40.00</cbc:BaseAmount>
  </cac:AllowanceCharge>
  <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>

Fragment of the corrected invoice: the line allowance carries reason code 95 and a reason text

<cac:InvoiceLine>
  <cbc:ID>1</cbc:ID>
  <!-- note, quantity, line net amount, accounting cost 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>

On line 1 the corrected invoice has reason code 95 and the text Example discount on the 5 per cent allowance; the failing invoice has neither, and nothing else changes. The failing document also reports BR-42, which applies the same test as BR-CO-23 to the same allowance, so the one edit clears both. The line charge next to it already had reason text and was 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. The credit note version of the recorded example reported BR-42 and BR-CO-23 at cac:CreditNoteLine[1]/cac:AllowanceCharge[1] when tried.
  • Only the EN 16931 layer reports a missing reason. When a code is present, the Peppol layer checks it against the allowance list as PEPPOL-EN16931-CL002, and the EN 16931 layer as BR-CL-19.
  • A line allowance amount is part of the line net amount calculation, but adding a reason changes no figure.

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-CO-23 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.