Skip to content

BR-CL-04Use an ISO 4217 alphabetic code for the invoice currency

cbc:DocumentCurrencyCode must be a current three-letter ISO 4217 code in upper case, such as GBP. Names, symbols, numeric codes and lower case fail.

EN 16931Fatal: the document is invalidCode listsCore fields

The short answer

BR-CL-04 fails when the value of cbc:DocumentCurrencyCode is not on the ISO 4217 alphabetic code list that ships with the validation artefacts. Send the three-letter code for the currency the invoice is actually issued in, in upper case: GBP, not gbp, 826, Pound sterling or a currency symbol.

The same wrong value is usually copied into every currencyID attribute, so expect this rule to arrive with a finding per amount from the rules that check those attributes.

What the rule checks

The rule compares the element text with a fixed list of ISO 4217 alphabetic codes. The match is exact and case-sensitive: gbp and Gbp both fail. So do the ISO numeric code, a country code such as GB, a currency name and a symbol.

The list is the snapshot published with the pinned EN 16931 artefacts, not the full history of ISO 4217. Codes that have been withdrawn are not on it; HRK and BGN are both rejected. A system that still holds an old code for a currency that has since been replaced needs its reference data updating.

Whitespace around the code does not fail this rule, but it does not help the document either. The amounts are matched to the document currency by exact comparison, so a padded code that passes here is still reported by BR-CO-15 and by the Peppol rule PEPPOL-EN16931-R051 on every amount. Trim the value.

Missing versus empty: cbc:DocumentCurrencyCode is optional in the UBL schema, so leaving it out passes the XSD layer. This rule has nothing to test in that case and stays silent; the missing currency is reported by BR-05 instead. An element that is present but empty reports BR-05, BR-CL-04 and PEPPOL-EN16931-R008 together.

TermMeaningUBL element
BT-5Invoice currency codecbc:DocumentCurrencyCode

How an integration ends up here

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

  • The source system stores a display value, a name or a symbol, and the mapping passes it through without translating it to a code.
  • Codes are stored or normalised in lower case.
  • The accounting package uses numeric ISO codes or its own internal currency keys.
  • The currency table predates a changeover and still carries a withdrawn code.
  • A filler value such as ZZZ is written when the currency on the source document is null.
  • A country code is used where a currency code is expected, because both come from the same customer record.

How to fix it

  1. Establish which currency the invoice amounts are really in. That is a fact about the transaction; do not pick a different valid code just because it validates.
  2. Translate it to the ISO 4217 alphabetic code, upper case and trimmed, and write it to cbc:DocumentCurrencyCode.
  3. Write the same code to the currencyID attribute of every amount in the document currency. The one exception is the second cac:TaxTotal that states the VAT total in the accounting currency when cbc:TaxCurrencyCode is used.
  4. Validate currency codes where they enter your system, against the current ISO 4217 list, so an unknown value is caught before an invoice is built on it.

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: ZZZ as the document currency and on every amount

<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>ZZZ</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>BUYER-REF-001</cbc:BuyerReference>
<!-- parties and tax total omitted from this fragment -->

<cac:LegalMonetaryTotal>
  <cbc:LineExtensionAmount currencyID="ZZZ">25.00</cbc:LineExtensionAmount>
  <cbc:TaxExclusiveAmount currencyID="ZZZ">25.00</cbc:TaxExclusiveAmount>
  <cbc:TaxInclusiveAmount currencyID="ZZZ">30.00</cbc:TaxInclusiveAmount>
  <!-- allowance, charge, prepaid and rounding totals omitted; they carry the same currencyID -->
  <cbc:PayableAmount currencyID="ZZZ">30.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>

Fragment of the corrected invoice: GBP throughout

<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:DocumentCurrencyCode>GBP</cbc:DocumentCurrencyCode>
<cbc:BuyerReference>BUYER-REF-001</cbc:BuyerReference>
<!-- parties and tax total omitted from this fragment -->

<cac:LegalMonetaryTotal>
  <cbc:LineExtensionAmount currencyID="GBP">25.00</cbc:LineExtensionAmount>
  <cbc:TaxExclusiveAmount currencyID="GBP">25.00</cbc:TaxExclusiveAmount>
  <cbc:TaxInclusiveAmount currencyID="GBP">30.00</cbc:TaxInclusiveAmount>
  <!-- allowance, charge, prepaid and rounding totals omitted; they carry the same currencyID -->
  <cbc:PayableAmount currencyID="GBP">30.00</cbc:PayableAmount>
</cac:LegalMonetaryTotal>

The failing invoice has ZZZ in cbc:DocumentCurrencyCode and in the currencyID of all thirteen amounts, in the tax total, the monetary totals and the line; the corrected one has GBP in each place. BR-CL-04 is reported once, for the element. The failing document also reports BR-CL-03 and PEPPOL-EN16931-CL007 thirteen times each: they are the EN 16931 and Peppol code list checks for the currencyID attribute, and each fires on every amount. Had only the element been wrong and the attributes still said GBP, the report would instead be BR-CL-04 with BR-CO-15 and one PEPPOL-EN16931-R051 per amount, because the amounts would no longer match the document currency.

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 UBL Invoice and CreditNote alike; the element has the same name in both, and the recorded credit note with ZZZ reports the same three rules.
  • The rule reads cbc:DocumentCurrencyCode only. cbc:TaxCurrencyCode, the VAT accounting currency, has its own code list rule, BR-CL-05.
  • The element needs no attributes. Adding a listID draws the warning UBL-CR-657 and nothing else.

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-20.1: source checked 2026-09-20, explanation last updated 2026-09-20.

The official definition of BR-CL-04 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.