What BR-DE-18 checks
BR-DE-18 validates the format of Skonto (cash discount) entries in the payment terms, BT-20. Any line in the payment terms note that begins with # is treated as a Skonto declaration and must match the KoSIT pattern exactly: #SKONTO#TAGE=n#PROZENT=n.nn#, optionally extended by #BASISBETRAG=n.nn# when the discount applies to a partial base, written in upper case, ending with a line break, with no extra whitespace. The receiving portals parse these entries to schedule discounted payment, which is why "2% Skonto bei Zahlung binnen 14 Tagen" as prose satisfies a human but not the rule's regular expression.
Layer and formats
The finding carries "layer": "cius" and fires when validating against the XRechnung profile, in UBL and CII alike, including hybrids declaring the XRechnung CustomizationID. It is a fatal rule: a malformed Skonto line fails validation outright.
Why it fails in practice
- Free-text discount wording. The ERP's payment terms text mentions Skonto in prose, or mixes prose onto the same line as a structured entry.
- Format drift. Lower-case
#skonto#, a comma instead of the decimal dot, one decimal instead of two, a missing trailing#, or a missing final line break. - Multiple entries glued together. Staggered terms written on one line instead of one entry per line, each closed by a line break.
How to fix it
Emit each Skonto tier as its own strictly formatted line in the first payment terms note:
<cac:PaymentTerms>
<cbc:Note>#SKONTO#TAGE=14#PROZENT=2.00#
#SKONTO#TAGE=30#PROZENT=1.00#
</cbc:Note>
</cac:PaymentTerms>
In an InvoiceXML create request the value is invoice.paymentDetails.paymentTerms; put the formatted entries there, one per line. Keep any human-readable terms in separate lines that do not start with #.
The raw rejection vs the InvoiceXML finding
The Schematron report answers with a regular expression and a paragraph of German formatting law (abbreviated here; the original runs well past a hundred words):
<svrl:failed-assert id="BR-DE-18" flag="fatal"
location="/*:Invoice[namespace-uri()='urn:oasis:names:specification:ubl:schema:xsd:Invoice-2'][1]">
<svrl:text>[BR-DE-18] Skonto Zeilen in ubl:Invoice müssen diesem
regulärem Ausdruck entsprechen: #(SKONTO)#TAGE=([0-9]+
#PROZENT=[0-9]+\.[0-9]{2})(#BASISBETRAG=-?[0-9]+\.[0-9]{2})?#$ ...
Die Informationen zur Gewährung von Skonto müssen wie folgt im
Element "Payment terms" (BT-20) übermittelt werden: Anzugeben ist
im ersten Segment "SKONTO", im zweiten "TAGE=n", im dritten
"PROZENT=n". ... Alle Angaben zur Gewährung von Skonto müssen in
Großbuchstaben gemacht werden.</svrl:text>
</svrl:failed-assert>
The InvoiceXML finding compresses that into one actionable sentence:
{
"rule": "BR-DE-18",
"layer": "cius",
"line": null,
"message": "A Skonto (cash discount) entry in the payment terms does not match the required XRechnung format. Each entry must be an upper-case line like #SKONTO#TAGE=n#PROZENT=n.nn#, ending with a line break.",
"btCodes": ["BT-20"],
"fields": ["paymentDetails.paymentTerms"],
"raw": "[BR-DE-18] CIUS: Skonto Zeilen in ubl:Invoice müssen diesem regulärem Ausdruck entsprechen: ..."
}
Your end customer sees the expected shape immediately, your UI highlights the payment terms input via fields, and the full German original stays in raw for the curious. Clients localize by the stable rule key.
Check or generate XRechnung documents
Validate Skonto-carrying documents in the XRechnung validator, or generate with POST /v1/create/xrechnung and pass the formatted entries in paymentDetails.paymentTerms; the document is validated against the full KoSIT rule set before delivery. The XRechnung API toolkit covers the wider integration.
Related rules and identifiers
- BR-DE-1, the payment instructions requirement the terms belong to
- BR-DE-17, the neighbouring restriction on invoice type codes
- BR-DE-15, the mandatory buyer reference (Leitweg-ID)
- The XRechnung 3.0 CustomizationID, the identifier that activates the BR-DE rules