XRechnung Extension — when the stricter rules apply
The Extension is a variant of XRechnung with additional structures — sub invoice lines above all. If you do not use it, you never see these rules.
15 rules · 15 explained · Rule set v2026-08-31
Two variants, one rule set
XRechnung has the CIUS, which restricts the European norm, and the Extension, which extends it. Which applies is decided by the specification identifier (BT-24): carry the Extension identifier and the BR-DEX rules apply on top.
That is the commonest confusion here. A BR-DEX error on an invoice that was never meant to be an Extension almost always means a wrong BT-24 — see BR-DE-21.
What the Extension adds
Sub invoice lines, mostly: a line may contain subordinate lines, which the ordinary CIUS does not permit. Most BR-DEX rules hang off that — that a sub line carries its own VAT information, that sub line amounts add up to the parent line.
Use the Extension only where you genuinely need those structures. It narrows the set of recipients able to process the invoice, and the rules above arrive on top with nothing given back.
And it exists in UBL only. The sub line rules — BR-DEX-02 and BR-DEX-03 — are written for UBL and absent from CII altogether; instead BR-DEX-15 reports, on a CII file carrying ram:ParentLineID, that XRechnung does not know the concept there. Need sub invoice lines and you cannot deliver as CII, which means you cannot deliver as ZUGFeRD either.
One thing is gained in return, and it has nothing to do with lines: BR-DEX-01 allows the Extension a seventh MIME type for embedded attachments, application/xml, which the CIUS refuses through BR-CL-24. Both lists are printed below, each under its own rule.
Two of the fifteen are warnings rather than errors: BR-DEX-02, whose text says “should” and not “must”, and BR-DEX-15. Neither refuses the invoice — the report carries them and the recipient decides.
All Extension rules
The field each rule guards, and beneath it the official rule text.
BR-DEX-01
MIME type of the embedded attachment (BT-125)
Das Element […] "Attached Document" (BT-125) benutzt einen nicht zulässigen MIME-Code: […]. Im Falle einer Extension darf zusätzlich zu der Liste der mime codes (definiert in Abschnitt 8.2, "Binary Object") der MIME-Code application/xml genutzt werden.
7 permitted values · application/pdf, application/vnd.oasis.opendocument.spreadsheet, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/xml, image/jpeg, image/png, text/csv
- What the rule requires
- On an invoice carrying the Extension identifier, every embedded attachment (BT-125) must have one of seven MIME types: the six from BR-CL-24 — application/pdf, image/png, image/jpeg, text/csv and the .xlsx and .ods spreadsheet formats — plus application/xml. The comparison is character for character; “application/PDF” fails. Unlike BR-CL-24, the rule also checks an attachment with no mimeCode at all — in CII, where the schema does not require the attribute, such an attachment is caught only here.
- Why it fires
- The MIME type is usually taken over unchecked — from the file extension, or from whatever library reads the file. For XML, text/xml is common, but only application/xml is accepted; image/jpg instead of image/jpeg fails the same way, as does the generic application/octet-stream. Word documents, ZIP archives and old .xls files are not on the list at all.
- How to fix it
- Set mimeCode to exactly one of the seven values, spelled as on the list — in UBL on cac:AdditionalDocumentReference/cac:Attachment/cbc:EmbeddedDocumentBinaryObject, in CII on ram:AdditionalReferencedDocument/ram:AttachmentBinaryObject. Convert other formats to PDF before embedding them. The value application/xml is valid only with the Extension identifier in BT-24: on a CIUS invoice BR-CL-24 rejects the same attachment. In the Extension BR-CL-24 still reports it but no longer decides acceptance — the KoSIT configuration lowers the rule to a notice for the Extension.
- What the validator checks
UBL.[@mimeCode = 'application/pdf' or @mimeCode = 'image/png' or @mimeCode = 'image/jpeg' or @mimeCode = 'text/csv' or @mimeCode = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' or @mimeCode = 'application/vnd.oasis.opendocument.spreadsheet' or @mimeCode = 'application/xml']CII.[@mimeCode = 'application/pdf' or @mimeCode = 'image/png' or @mimeCode = 'image/jpeg' or @mimeCode = 'text/csv' or @mimeCode = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' or @mimeCode = 'application/vnd.oasis.opendocument.spreadsheet' or @mimeCode = 'application/xml']
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0#conformant#urn:xeinkauf.de:kosit:extension:xrechnung_3.0</cbc:CustomizationID> <cac:AdditionalDocumentReference> <cbc:ID>ANL-1</cbc:ID> <cac:Attachment> <cbc:EmbeddedDocumentBinaryObject mimeCode="text/xml" filename="stueckliste.xml">PD94bWwgdmVyc2lvbj0iMS4wIj8+</cbc:EmbeddedDocumentBinaryObject> </cac:Attachment> </cac:AdditionalDocumentReference>Fixed <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0#conformant#urn:xeinkauf.de:kosit:extension:xrechnung_3.0</cbc:CustomizationID> <cac:AdditionalDocumentReference> <cbc:ID>ANL-1</cbc:ID> <cac:Attachment> <cbc:EmbeddedDocumentBinaryObject mimeCode="application/xml" filename="stueckliste.xml">PD94bWwgdmVyc2lvbj0iMS4wIj8+</cbc:EmbeddedDocumentBinaryObject> </cac:Attachment> </cac:AdditionalDocumentReference>BR-DEX-02
Line net amount from its sub lines (BT-131)
Der Wert von "Invoice line net amount" (BT-131) einer "INVOICE LINE" (BG-25) oder einer "SUB INVOICE LINE" (BG-DEX-01) soll der Summe der "Invoice line net amount" (BT-131) der direkt darunterliegenden "SUB INVOICE LINE" (BG-DEX-01) entsprechen.Warning
- What the rule requires
- Where an invoice line has sub invoice lines (BG-DEX-01), its net amount (BT-131) should equal exactly the sum of the net amounts of the sub lines directly beneath it — at every level, including sub lines that have sub lines of their own. The comparison is exact, with no rounding tolerance. The rule only warns, and it reports once for the whole invoice: the location it gives is the document, not the line that fails to add up.
- Why it fires
- A package or bundle price is the usual case: the parent line carries the package price, the sub lines list the parts at their individual prices, and the sum differs. The same warning appears when the sub lines describe a single unit while the line charges three, or when a discount sits on the parent line only. Sub lines rounded one by one are enough on their own: three times 33.33 is 99.99, not 100.00.
- How to fix it
- Derive the sub lines from the parent amount: spread the package price and any discount across the parts, scale the quantities up to the line’s full quantity, and put the rounding remainder on one sub line. Only the parent cac:InvoiceLine counts toward the sum of line net amounts (BT-106) — BR-CO-10 does not include cac:SubInvoiceLine — so when in doubt, correct the sub lines. Sub invoice lines exist in UBL only (cac:InvoiceLine/cac:SubInvoiceLine/cbc:LineExtensionAmount); a CII file carrying ram:ParentLineID gets BR-DEX-15 instead.
- What the validator checks
UBL(every $invoiceline in /ubl:Invoice/cac:InvoiceLine[ exists (./cac:SubInvoiceLine) ] satisfies $invoiceline/xs:decimal(cbc:LineExtensionAmount) = sum($invoiceline/cac:SubInvoiceLine/xs:decimal(cbc:LineExtensionAmount))) and (count( //cac:SubInvoiceLine [count(cac:SubInvoiceLine) > 0 and xs:decimal(cbc:LineExtensionAmount) = sum(cac:SubInvoiceLine/xs:decimal(cbc:LineExtensionAmount))]) = count(//cac:SubInvoiceLine [count(cac:SubInvoiceLine) > 0]))
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:InvoiceLine> <cbc:ID>1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">1200.00</cbc:LineExtensionAmount> <cac:SubInvoiceLine> <cbc:ID>1.1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">899.00</cbc:LineExtensionAmount> </cac:SubInvoiceLine> <cac:SubInvoiceLine> <cbc:ID>1.2</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">398.00</cbc:LineExtensionAmount> </cac:SubInvoiceLine> </cac:InvoiceLine>Fixed <cac:InvoiceLine> <cbc:ID>1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">1200.00</cbc:LineExtensionAmount> <cac:SubInvoiceLine> <cbc:ID>1.1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">840.00</cbc:LineExtensionAmount> </cac:SubInvoiceLine> <cac:SubInvoiceLine> <cbc:ID>1.2</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">2</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">360.00</cbc:LineExtensionAmount> </cac:SubInvoiceLine> </cac:InvoiceLine>BR-DEX-03
VAT information per sub line (BG-DEX-06)
Eine Sub Invoice Line (BG-DEX-01) muss genau eine "SUB INVOICE LINE VAT INFORMATION" (BG-DEX-06) enthalten.
- What the rule requires
- Every sub invoice line (BG-DEX-01) must carry exactly one VAT information group, BG-DEX-06, in its item — one cac:ClassifiedTaxCategory, not none and not two. That holds at every level, sub lines of sub lines included. Only the element is counted: BR-DEX-03 does not look at the category, rate or tax scheme inside it. As with BR-DEX-02, the location given is the invoice as a whole, not the sub line concerned.
- Why it fires
- The sub lines are generated as a plain breakdown — name, quantity, amount — because the VAT information already sits on the parent line. The Extension wants it on every single sub line regardless. An item into which the mapping writes two categories fails as well, say the parent line’s and its own.
- How to fix it
- Give every cac:SubInvoiceLine exactly one cac:ClassifiedTaxCategory in cac:Item, with the category (cbc:ID), the rate (cbc:Percent) and cac:TaxScheme/cbc:ID set to VAT — after the name, identifiers and classification, before cac:AdditionalItemProperty. Each sub line carries the category and rate that apply to its own part. CII has no sub invoice lines; a CII file carrying ram:ParentLineID gets BR-DEX-15 instead.
- What the validator checks
UBLnot(exists(//cac:SubInvoiceLine/cac:Item[ count ( cac:ClassifiedTaxCategory) != 1]))
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:SubInvoiceLine> <cbc:ID>1.1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">840.00</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>Notebook</cbc:Name> </cac:Item> </cac:SubInvoiceLine>Fixed <cac:SubInvoiceLine> <cbc:ID>1.1</cbc:ID> <cbc:InvoicedQuantity unitCode="C62">1</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="EUR">840.00</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>Notebook</cbc:Name> <cac:ClassifiedTaxCategory> <cbc:ID>S</cbc:ID> <cbc:Percent>19</cbc:Percent> <cac:TaxScheme><cbc:ID>VAT</cbc:ID></cac:TaxScheme> </cac:ClassifiedTaxCategory> </cac:Item> </cac:SubInvoiceLine>BR-DEX-04
Party identifier scheme (BT-29, BT-46, BT-60)
Any scheme identifier in […] MUST be coded using one of the ISO 6523 ICD list.
- What the rule requires
- Where a party identifier — the seller’s (BT-29), the buyer’s (BT-46) or the payee’s (BT-60) — carries a scheme attribute, on an Extension invoice its value must come from the ISO 6523 ICD list: the same one as for BR-CL-10, plus three codes only XRechnung knows: XR01, XR02 and XR03. To let those three through, the KoSIT configuration lowers BR-CL-10 to a notice for the Extension; acceptance is decided there by BR-DEX-04. Identifiers without a schemeID are not checked, and UBL also accepts SEPA — but only for the seller and the payee, where the creditor identifier (BT-90) sits in the same element.
- Why it fires
- Usually the attribute holds an abbreviation instead of the code: “GLN” for 0088, “DUNS” for 0060, or the number without its leading zeros (“88”). Lower-case sepa fails as well, and so does SEPA on the buyer. An empty schemeID="" on the other hand gets through BR-DEX-04: the list is built from two strings, the join leaves two spaces side by side, and that is exactly what the comparison looks for. BR-CL-10 does object to the empty value, but it has no say in the Extension.
- How to fix it
- Enter the code from the list, 0088 for a GLN — in UBL as the schemeID on cac:PartyIdentification/cbc:ID, in CII on ram:GlobalID of the party concerned (ram:SellerTradeParty, ram:BuyerTradeParty, ram:PayeeTradeParty). If the identifier has no scheme on the list, leave the attribute out; in CII it then belongs in ram:ID rather than ram:GlobalID. The SEPA exception exists in UBL only: in CII the creditor identifier lives not in ram:GlobalID but in ram:CreditorReferenceID.
- What the validator checks
UBL((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' ')))) or ((not(contains(normalize-space(@schemeID), ' ')) and contains(' SEPA ', concat(' ', normalize-space(@schemeID), ' '))) and ((ancestor::cac:AccountingSupplierParty) or (ancestor::cac:PayeeParty)))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
CII((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cac:AccountingSupplierParty> <cac:Party> <cac:PartyIdentification> <cbc:ID schemeID="GLN">4012345000009</cbc:ID> </cac:PartyIdentification> <cac:PartyName> <cbc:Name>Muster GmbH</cbc:Name> </cac:PartyName> </cac:Party> </cac:AccountingSupplierParty>Fixed <cac:AccountingSupplierParty> <cac:Party> <cac:PartyIdentification> <cbc:ID schemeID="0088">4012345000009</cbc:ID> </cac:PartyIdentification> <cac:PartyName> <cbc:Name>Muster GmbH</cbc:Name> </cac:PartyName> </cac:Party> </cac:AccountingSupplierParty>BR-DEX-05
Legal registration identifier scheme (BT-30, BT-47, BT-61)
Any scheme identifier in […] MUST be coded using one of the ISO 6523 ICD list.
- What the rule requires
- Where a legal registration identifier — the seller’s (BT-30), the buyer’s (BT-47) or the payee’s (BT-61) — carries a scheme attribute, on an Extension invoice its value must come from the ISO 6523 ICD list: the same one as for BR-CL-11, plus three codes only XRechnung knows: XR01, XR02 and XR03; BR-CL-11 itself is lowered to a notice for the Extension by the KoSIT configuration. Without a schemeID nothing is checked. In CII the rule reaches further than its field suggests, as BR-CL-11 does: it checks every ram:ID carrying a schemeID, except tax registrations (ram:SpecifiedTaxRegistration).
- Why it fires
- The typical case is the commercial register number with a home-made scheme such as schemeID="HRB" — not a code on the list. CII adds a second source: if a party or delivery location identifier with a scheme sits in ram:ID instead of ram:GlobalID, a wrong code there is reported as BR-DEX-05, not as BR-DEX-04 or BR-DEX-08. An empty schemeID="" on the other hand gets through, because the join of the assembled list leaves two spaces side by side; BR-CL-11 objects to it but has no say in the Extension.
- How to fix it
- Send the commercial register number without a schemeID — in UBL as cac:PartyLegalEntity/cbc:CompanyID, in CII as ram:SpecifiedLegalOrganization/ram:ID; the rule checks only identifiers that carry a scheme. Set a schemeID only where the identifier genuinely belongs to a code on the list. In CII a party identifier with a scheme belongs in ram:GlobalID, one without in ram:ID.
- What the validator checks
UBL((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
CII((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cac:PartyLegalEntity> <cbc:RegistrationName>Muster GmbH</cbc:RegistrationName> <cbc:CompanyID schemeID="HRB">HRB 12345</cbc:CompanyID> </cac:PartyLegalEntity>Fixed <cac:PartyLegalEntity> <cbc:RegistrationName>Muster GmbH</cbc:RegistrationName> <cbc:CompanyID>HRB 12345</cbc:CompanyID> </cac:PartyLegalEntity>BR-DEX-06
Item standard identifier scheme (BT-157)
Any scheme identifier in […] MUST be coded using one of the ISO 6523 ICD list.
- What the rule requires
- Where the item standard identifier (BT-157) carries a scheme attribute, on an Extension invoice its value must come from the ISO 6523 ICD list — the same one as for BR-CL-21, plus three codes only XRechnung knows: XR01, XR02 and XR03. Without a schemeID the rule checks nothing. Here the Extension is stricter than the CIUS: there a wrong scheme does not prevent acceptance, because the KoSIT configuration has lowered BR-CL-21 to a warning — in the Extension BR-CL-21 is only a notice, but BR-DEX-06 is an error that gets the invoice rejected.
- Why it fires
- Usually the attribute holds the name of the numbering system rather than its code: “GTIN” or “EAN” instead of 0160. If you move from the CIUS to the Extension you may therefore see this error for the first time — the same identifier did not stop the invoice being accepted there. An empty schemeID="" on the other hand gets through BR-DEX-06, because the join of the assembled list leaves two spaces side by side — and BR-CL-21, which objects to the empty value, has no say in the Extension.
- How to fix it
- Set the code of the numbering system, 0160 for a GTIN — in UBL as the schemeID on cac:Item/cac:StandardItemIdentification/cbc:ID, in CII on ram:SpecifiedTradeProduct/ram:GlobalID. An in-house article number is not a standard identifier: it belongs, without a scheme, in the seller’s item identifier (BT-155) — cac:SellersItemIdentification/cbc:ID in UBL, ram:SellerAssignedID in CII.
- What the validator checks
UBL((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
CII((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cac:Item> <cbc:Name>Laserdrucker</cbc:Name> <cac:StandardItemIdentification> <cbc:ID schemeID="GTIN">04012345678901</cbc:ID> </cac:StandardItemIdentification> </cac:Item>Fixed <cac:Item> <cbc:Name>Laserdrucker</cbc:Name> <cac:StandardItemIdentification> <cbc:ID schemeID="0160">04012345678901</cbc:ID> </cac:StandardItemIdentification> </cac:Item>BR-DEX-07
Electronic address scheme (BT-34, BT-49)
Any scheme identifier for an Endpoint Identifier in […] MUST belong to the CEF EAS code list.
- What the rule requires
- The scheme attribute of the electronic address — the seller’s (BT-34) or the buyer’s (BT-49) — must carry a code from the CEF EAS list on an Extension invoice: the same list as for BR-CL-25, plus three codes only XRechnung knows: XR01, XR02 and XR03; BR-CL-25 itself is lowered to a notice for the Extension by the KoSIT configuration. Only an address that carries a schemeID is checked; that it carries one is required by BR-62 and BR-63. The comparison is exact: EM passes, “em” and “EMAIL” do not.
- Why it fires
- For the Leitweg-ID used as an address, the scheme 9958 is in circulation — it is not on this rule set’s list, which has 0204 instead; 9958 fails in the CIUS too, there on BR-CL-25. For email addresses it is the spelling: “EMAIL”, “email” or “SMTP” instead of EM. An empty schemeID="" on the other hand gets through, because the join of the assembled list leaves two spaces side by side; BR-CL-25 objects to it but has no say in the Extension.
- How to fix it
- Set the code from the EAS list — in UBL as the schemeID on cbc:EndpointID under cac:AccountingSupplierParty/cac:Party or cac:AccountingCustomerParty/cac:Party, in CII on ram:URIUniversalCommunication/ram:URIID under ram:SellerTradeParty or ram:BuyerTradeParty. For an email address that is EM, for the Leitweg-ID 0204. Case matters.
- What the validator checks
UBL((not(contains(normalize-space(@schemeID), ' ')) and contains($CEF-EAS-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $CEF-EAS-EXT-CODES
- concat($DIGA-CODES, $CEF-EAS-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $CEF-EAS-CODES
- '0002 0007 0009 0037 0060 0088 0096 0097 0106 0130 …'104 values
CII((not(contains(normalize-space(@schemeID), ' ')) and contains($CEF-EAS-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $CEF-EAS-EXT-CODES
- concat($DIGA-CODES, $CEF-EAS-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $CEF-EAS-CODES
- '0002 0007 0009 0037 0060 0088 0096 0097 0106 0130 …'104 values
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cac:AccountingCustomerParty> <cac:Party> <cbc:EndpointID schemeID="9958">04011000-12345-03</cbc:EndpointID> <cac:PartyName> <cbc:Name>Stadtverwaltung Musterstadt</cbc:Name> </cac:PartyName> </cac:Party> </cac:AccountingCustomerParty>Fixed <cac:AccountingCustomerParty> <cac:Party> <cbc:EndpointID schemeID="0204">04011000-12345-03</cbc:EndpointID> <cac:PartyName> <cbc:Name>Stadtverwaltung Musterstadt</cbc:Name> </cac:PartyName> </cac:Party> </cac:AccountingCustomerParty>BR-DEX-08
Delivery location identifier scheme (BT-71)
Any scheme identifier for a Delivery location identifier in […] MUST be coded using one of the ISO 6523 ICD list.
- What the rule requires
- Where the delivery location identifier (BT-71) carries a scheme attribute, on an Extension invoice its value must come from the ISO 6523 ICD list — the same one as for BR-CL-26, plus three codes only XRechnung knows: XR01, XR02 and XR03; BR-CL-26 itself is lowered to a notice for the Extension by the KoSIT configuration. Without a schemeID the rule checks nothing. In CII it looks only at ram:GlobalID of the delivery location at header level, that is under ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty.
- Why it fires
- Usually it is the GLN of a warehouse or branch whose scheme reads “GLN” instead of 0088: the delivery location often has no scheme field of its own in the source system, and the mapping fills the attribute with the name of the number. An empty schemeID="" on the other hand gets through, because the join of the assembled list leaves two spaces side by side; BR-CL-26 objects to it but has no say in the Extension.
- How to fix it
- Set the code from the list, 0088 for a GLN — in UBL as the schemeID on cac:Delivery/cac:DeliveryLocation/cbc:ID, in CII on ram:ApplicableHeaderTradeDelivery/ram:ShipToTradeParty/ram:GlobalID. Without a scheme the identifier belongs in ram:ShipToTradeParty/ram:ID in CII; if that element carries a schemeID anyway, BR-DEX-05 is the rule that checks it, not BR-DEX-08.
- What the validator checks
UBL((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
CII((not(contains(normalize-space(@schemeID), ' ')) and contains($ISO-6523-ICD-EXT-CODES, concat(' ', normalize-space(@schemeID), ' '))))Variables in it
- $ISO-6523-ICD-EXT-CODES
- concat($DIGA-CODES, $ISO-6523-ICD-CODES)
- $DIGA-CODES
- ' XR01 XR02 XR03 '
- $ISO-6523-ICD-CODES
- '0002 0003 0004 0005 0006 0007 0008 0009 0010 0011 …'243 values
In the XML
A UBL fragment. The CII path is named above — same change, different element names.
Fails <cac:Delivery> <cbc:ActualDeliveryDate>2026-08-24</cbc:ActualDeliveryDate> <cac:DeliveryLocation> <cbc:ID schemeID="GLN">4012345000016</cbc:ID> </cac:DeliveryLocation> </cac:Delivery>Fixed <cac:Delivery> <cbc:ActualDeliveryDate>2026-08-24</cbc:ActualDeliveryDate> <cac:DeliveryLocation> <cbc:ID schemeID="0088">4012345000016</cbc:ID> </cac:DeliveryLocation> </cac:Delivery>BR-DEX-09
Amount due including third-party payments (BT-115)
Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114) + Σ Third party payment amount (BT-DEX-002).
- What the rule requires
- On an Extension invoice the amount due for payment (BT-115) has to add up like this: total with VAT (BT-112) minus the amount already paid (BT-113) plus the rounding amount (BT-114) plus the amounts of all third-party payments (BG-DEX-09, each BT-DEX-002). Third-party payments raise the amount due — they are added, not deducted. Every cac:PrepaidPayment in the invoice goes into the sum.
- Why it fires
- The UBL name cac:PrepaidPayment sounds like a prepayment. Treat the group as one, deducting the amount from the amount due instead of adding it, and the invoice ends up out by twice the amount. Put a prepayment by the buyer there while also deducting it as BT-113, and the two entries cancel, so BR-DEX-09 expects the amount due as if nothing had been paid; bill the third-party claim as an invoice line as well, and it is already inside BT-112 and counts twice. BR-CO-16 keeps running on the Extension, knows nothing of BT-DEX-002 and fires as soon as the third-party amounts sum to anything but zero — the KoSIT configuration downgrades it to information there. With no third-party payments both check the same sum, and a wrong amount due shows up under both codes.
- How to fix it
- Derive BT-115 from the other amounts: BT-112 − BT-113 + BT-114 + the sum of all BT-DEX-002. The amount due sits in cac:LegalMonetaryTotal/cbc:PayableAmount, the third-party amounts in cac:PrepaidPayment/cbc:PaidAmount directly under the root element; a prepayment by the buyer belongs in cbc:PrepaidAmount (BT-113) alone, and the third-party claim itself does not belong among the lines. BR-CO-16 cannot be met alongside while the third-party amounts sum to anything but zero — the two formulas then exclude each other. The rule exists in UBL only: in CII the Extension provides no third-party payments, and BR-CO-16 remains an error there.
- What the validator checks
UBL(round((xs:decimal(cbc:PayableAmount) - $payableroundingamount) * 10 * 10) div 100) = (round((xs:decimal(cbc:TaxInclusiveAmount) - $prepaidamount + $thirdpartyprepaidamount) * 10 * 10) div 100)Variables in it
- $payableroundingamount
- if (exists(cbc:PayableRoundingAmount)) then (xs:decimal(cbc:PayableRoundingAmount)) else (0)
- $prepaidamount
- if (exists(cbc:PrepaidAmount)) then (xs:decimal(cbc:PrepaidAmount)) else (0)
- $thirdpartyprepaidamount
- if (exists(../cac:PrepaidPayment/cbc:PaidAmount[boolean(normalize-space(xs:string(.)))])) then (sum(../cac:PrepaidPayment/xs:decimal(cbc:PaidAmount))) else (0)
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment> <cac:LegalMonetaryTotal> <cbc:TaxInclusiveAmount currencyID="EUR">1190.00</cbc:TaxInclusiveAmount> <cbc:PayableAmount currencyID="EUR">1170.00</cbc:PayableAmount> </cac:LegalMonetaryTotal>Fixed <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment> <cac:LegalMonetaryTotal> <cbc:TaxInclusiveAmount currencyID="EUR">1190.00</cbc:TaxInclusiveAmount> <cbc:PayableAmount currencyID="EUR">1210.00</cbc:PayableAmount> </cac:LegalMonetaryTotal>BR-DEX-10
Third party payment type (BT-DEX-001)
Das Element "Third party payment type" BT-DEX-001 muss übermittelt werden, wenn die Gruppe "THIRD PARTY PAYMENT" (BG-DEX-09) übermittelt wird.
- What the rule requires
- Every third-party payment (group BG-DEX-09, cac:PrepaidPayment in UBL) has to state its type: BT-DEX-001, mapped onto cac:PrepaidPayment/cbc:ID. All that is checked is that the element is present and holds more than whitespace; which type it names, the expression does not examine. The rule applies only where BT-24 declares the Extension.
- Why it fires
- The UBL schema allows every child of cac:PrepaidPayment to be left out; only the Extension turns the group into a third-party claim with three mandatory fields. A generator that treats cac:PrepaidPayment as an ordinary prepayment — which is what the name suggests — writes only the amount into it. Nothing in the element name says that cbc:ID is where the type of claim goes. An empty cbc:ID draws PEPPOL-EN16931-R008, which forbids empty elements outright, alongside BR-DEX-10.
- How to fix it
- Put the type of the third-party claim into cac:PrepaidPayment/cbc:ID, the first child of the group, before cbc:PaidAmount. The check wants a non-empty value, not a particular one; which wording your recipient expects is something to settle with them. If the amount is really a prepayment by the buyer, it does not belong in cac:PrepaidPayment at all but in cac:LegalMonetaryTotal/cbc:PrepaidAmount as BT-113 — and BR-DEX-10 to BR-DEX-14 then fall away entirely. The rule exists in UBL only.
- What the validator checks
UBLcbc:ID[boolean(normalize-space(xs:string(.)))]
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:PrepaidPayment> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>Fixed <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>BR-DEX-11
Third party payment amount (BT-DEX-002)
Das Element "Third party payment amount" BT-DEX-002 muss übermittelt werden, wenn die Gruppe "THIRD PARTY PAYMENT" (BG-DEX-09) übermittelt wird.
- What the rule requires
- Every third-party payment (BG-DEX-09) has to state its amount: BT-DEX-002 in cac:PrepaidPayment/cbc:PaidAmount. The check is that the element is present and not empty — in practice, that it is present, because an empty cbc:PaidAmount already fails the schema, which wants a decimal number there.
- Why it fires
- The group gets created while the amount is kept somewhere else — as an invoice line of its own, say — or the serialiser drops the element because there is no value. Without cbc:PaidAmount its currencyID attribute is missing too, so BR-DEX-14 reports alongside: the currency comparison with BT-5 finds nothing to compare. An amount of 0.00, on the other hand, passes.
- How to fix it
- Write the gross amount of the claim into cac:PrepaidPayment/cbc:PaidAmount, between cbc:ID and cbc:InstructionID, with a currencyID in the invoice currency (BR-DEX-14) and no more than two decimals (BR-DEX-13). Include it in the amount due BT-115, as BR-DEX-09 requires. If there is no third-party claim, leave out the whole group rather than just its amount. The rule exists in UBL only.
- What the validator checks
UBLcbc:PaidAmount[boolean(normalize-space(xs:string(.)))]
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>Fixed <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>BR-DEX-12
Third party payment description (BT-DEX-003)
Das Element "Third party payment description" BT-DEX-003 muss übermittelt werden, wenn die Gruppe "THIRD PARTY PAYMENT" (BG-DEX-09) übermittelt wird.
- What the rule requires
- Every third-party payment (BG-DEX-09) needs a description: BT-DEX-003, mapped onto cac:PrepaidPayment/cbc:InstructionID. All that is checked is that the element is present and holds more than whitespace; whether two groups carry the same description, the expression does not examine.
- Why it fires
- Nothing in the name InstructionID suggests that a description goes there, and cac:PrepaidPayment has no element called Description or Note to point the way, so the description gets left behind in the mapping. An empty cbc:InstructionID draws PEPPOL-EN16931-R008 alongside BR-DEX-12.
- How to fix it
- Write a short description into cac:PrepaidPayment/cbc:InstructionID — the last of the three fields, after cbc:PaidAmount, or the schema already rejects the order. With several third-party claims, give each one its own description, even though the check does not enforce it. The rule exists in UBL only.
- What the validator checks
UBLcbc:InstructionID[boolean(normalize-space(xs:string(.)))]
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> </cac:PrepaidPayment>Fixed <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>BR-DEX-13
Decimals of that amount (BT-DEX-002)
Die maximale Anzahl zulässiger Nachkommastellen für das Element "Third party payment amount" (BT-DEX-002) ist 2.
- What the rule requires
- The amount of a third-party payment (BT-DEX-002, cac:PrepaidPayment/cbc:PaidAmount) may carry at most two decimals. The count works as in the BR-DEC rules: characters after the point, not the value — 100.000 fails although it is exactly one hundred.
- Why it fires
- BT-DEX-002 is not among the twenty-one amounts covered by the BR-DEC rules, so the Extension brings a rule of its own. Surplus places come from arithmetic, or from a formatter that writes amounts with three or four places. Whitespace counts too: a value written indented on a line of its own passes the schema and fails here. In UBL the CEN rule UBL-DT-01 fires at the same time — it applies the same count to every amount element except prices — so three decimals show up under two codes.
- How to fix it
- Round the amount to two decimals when writing it — 19.96 rather than 19.955 — and write it without surrounding whitespace. Derive the amount due BT-115 from the rounded value: BR-DEX-09 calculates with the amount that stands in the document. The rule exists in UBL only.
- What the validator checks
UBLstring-length(substring-after(cbc:PaidAmount, '.')) <= 2
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">19.955</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>Fixed <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">19.96</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>BR-DEX-14
Currency of that amount (BT-DEX-002)
Die Währungsangabe von "Third party payment amount" BT-DEX-002 muss BT-5 ("Invoice currency code") entsprechen.
- What the rule requires
- The amount of a third-party payment (BT-DEX-002) must be stated in the invoice currency: the currencyID attribute on cac:PrepaidPayment/cbc:PaidAmount has to equal the invoice currency code (BT-5, cbc:DocumentCurrencyCode). The comparison is character by character — "eur" is not "EUR".
- Why it fires
- The currency is hard-coded on the amount — EUR, say — while the invoice runs in another currency, or it is copied across with the amount from the third party’s data. If cbc:PaidAmount is missing altogether, BR-DEX-14 reports together with BR-DEX-11: no element means no attribute, and the comparison with BT-5 fails.
- How to fix it
- Set currencyID on cac:PrepaidPayment/cbc:PaidAmount to the same code as cbc:DocumentCurrencyCode. If the third party’s claim is in another currency, convert it into the invoice currency first — the check allows no second currency for BT-DEX-002. The rule exists in UBL only.
- What the validator checks
UBLcbc:PaidAmount/@currencyID = parent::node()/cbc:DocumentCurrencyCode
In the XML
A UBL fragment — the rule applies to that syntax only.
Fails <cbc:DocumentCurrencyCode>CHF</cbc:DocumentCurrencyCode> <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="EUR">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>Fixed <cbc:DocumentCurrencyCode>CHF</cbc:DocumentCurrencyCode> <cac:PrepaidPayment> <cbc:ID>Drittanbieterleistung</cbc:ID> <cbc:PaidAmount currencyID="CHF">20.00</cbc:PaidAmount> <cbc:InstructionID>Drittanbieter-Abo August 2026</cbc:InstructionID> </cac:PrepaidPayment>BR-DEX-15
Sub invoice lines in CII, which XRechnung does not have
This CII file might use the concept of Sub Invoice Lines. However XRechnung does not support this.Warning
- What the rule requires
- A CII invoice whose BT-24 declares the Extension should contain no ram:ParentLineID — the element through which one line points to a parent line. The Extension has sub invoice lines in UBL only — BR-DEX-02 and BR-DEX-03 exist there alone. BR-DEX-15 is a warning, so the invoice is not rejected for it.
- Why it fires
- The likely source is a generator built for ZUGFeRD/Factur-X EXTENDED, where ram:ParentLineID together with ram:LineStatusReasonCode (GROUP, DETAIL, INFORMATION) links lines into a hierarchy, and which writes the same structure into the XRechnung. The expression checks per line but searches the whole document with //ram:ParentLineID: a single reference puts the warning on every line of the invoice, including those without one. On an ordinary XRechnung in CII, by contrast, no rule reports the element at all — the CEN rule CII-SR-036 looks for it directly under the line, where the schema does not allow it, and so never fires.
- How to fix it
- If you need sub invoice lines, deliver the Extension as UBL: there cac:InvoiceLine carries subordinate cac:SubInvoiceLine groups, governed by BR-DEX-02 and BR-DEX-03. To stay with CII, remove ram:ParentLineID from ram:AssociatedDocumentLineDocument — to XRechnung the lines are peers anyway, and BR-CO-10 sums every one of them. Numbering such as 1.1 in the line identifier (BT-126) may stay; only the reference has to go.
- What the validator checks
CIInot(exists(//ram:ParentLineID))
In the XML
A CII fragment — the rule applies to that syntax only.
Fails <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument> <ram:LineID>1</ram:LineID> </ram:AssociatedDocumentLineDocument> </ram:IncludedSupplyChainTradeLineItem> <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument> <ram:LineID>1.1</ram:LineID> <ram:ParentLineID>1</ram:ParentLineID> </ram:AssociatedDocumentLineDocument> </ram:IncludedSupplyChainTradeLineItem>Fixed <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument> <ram:LineID>1</ram:LineID> </ram:AssociatedDocumentLineDocument> </ram:IncludedSupplyChainTradeLineItem> <ram:IncludedSupplyChainTradeLineItem> <ram:AssociatedDocumentLineDocument> <ram:LineID>1.1</ram:LineID> </ram:AssociatedDocumentLineDocument> </ram:IncludedSupplyChainTradeLineItem>
NormAPI provides technical validation, not tax or legal advice.