Skip to content

Ironfang Finance - XRechnung

Validating and viewing XRechnung

What is checked, against which release, how to call the API, how to read a result, and what the viewer shows.

Ironfang Finance validates XRechnung invoices and credit notes in both of its syntaxes, UBL 2.1 and UN/CEFACT CII, against the official XRechnung validator configuration, and reads them as documents. Try it without an account in the XRechnung validator and the XRechnung viewer, also in German.

What is checked

A document passes through these layers in order. A layer that fails stops the ones after it, and the result says each layer was not reached rather than passed.

LayerWhat it checks
inputThe size and framing of the request, before anything is parsed.
xmlWell-formed XML within the limits, with no DTD, entities beyond the predefined five, or XInclude.
xsdThe XML schema of the document's syntax: UBL 2.1, or UN/CEFACT CII D16B, the edition XRechnung uses.
en16931The European standard's business rules, in the edition the XRechnung bundle pins.
xrechnungThe XRechnung rules (BR-DE-* and the Peppol-derived rules XRechnung includes).

The rules are the official configuration run byte for byte, with the levels it sets. That configuration lowers some rules from their own flag, so a finding carries both: severity, which decides the outcome, and rule_flag, the rule's own. Only fatal findings fail a document; warning and information never do.

Versions and variants

Validate with the API

POST /finance/v2/einvoices/validate takes the XML as the body. Name the family, as this script does, so that a document which declares no family is still checked as XRechnung and one which declares another is refused with what it declares. The script keeps the result in result.json and derives the Idempotency-Key from the file, so a retry returns the first result and is not charged again.

#!/usr/bin/env bash
# Validate one XRechnung with the Ironfang Finance API and keep the result.
#
#   IRONFANG_API_KEY=... ./validate-xrechnung.sh invoice.xml
#
# The result is written to result.json. A retry with the same file sends
# the same Idempotency-Key, so it returns the first result and is not
# charged again.
set -euo pipefail
file="$1"
base="${IRONFANG_FINANCE_API:-https://api.ironfang.uk/finance}"
key="xr-$(sha256sum "$file" | cut -c1-40)"

curl --fail-with-body --silent --show-error \
  "$base/v2/einvoices/validate?family=xrechnung" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: $key" \
  --data-binary "@$file" \
  --output result.json

grep -o '"outcome":"[a-z]*"' result.json | head -n 1
Query parameterMeaning
familyxrechnung. Without it the family is read from the document's specification identifier.
variantcore, the default for XRechnung.
document_typeinvoice, credit_note or auto (the default: read from the document).
rulesetlatest (the default) or an exact release id from GET /finance/v2/einvoices/rulesets. An exact release names the whole selection; a selector that contradicts it is selection_conflict.

Without an API key the same request is anonymous: nothing is stored and tighter rate limits apply. With a key, a completed validation is one operation from your Finance allowance, charged once the schema check reaches a verdict, and the result is kept for 30 days at GET /finance/v2/einvoices/results/{id}. The full contract is the V2 OpenAPI document.

Reading a result

outcome is valid or invalid for a completed validation; anything that stopped a verdict, such as a timeout, is a Problem with outcome: indeterminate and nothing charged. coverage says what the result establishes: at XML scope, the XML document and nothing about a PDF. Each finding has its rule id unchanged, a fixed message for its layer, and an XPath location; the official rule texts are not repeated, because they can carry invoice values. next_actions includes view when the document can be opened in the viewer.

Explained rules

These rules have a reviewed explanation, in English and German, which the tools show beside the finding. Each was checked against the official validator with a fixture that breaks it.

RuleLevelWhat it means
BR-DE-1fatalPayment instructions are missing
BR-DE-2fatalThe seller contact is missing
BR-DE-3fatalThe seller's city is missing
BR-DE-4fatalThe seller's post code is missing
BR-DE-6fatalThe seller contact's telephone number is missing
BR-DE-7fatalThe seller contact's email address is missing
BR-DE-8fatalThe buyer's city is missing
BR-DE-9fatalThe buyer's post code is missing
BR-DE-15fatalThe buyer reference (Leitweg-ID) is missing
BR-DE-16fatalThe seller's VAT identifier or tax number is missing
BR-DE-19warningThe payment account is not a valid IBAN
BR-DE-23-afatalA credit transfer names no account
BR-DE-27warningThe contact telephone number has fewer than three digits
BR-DE-TMP-32informationNo delivery date or service period is given

Viewing

POST /tools/v2/invoice/view reads a UBL or CII document into the invoice-view/2 model: the document's parties, lines, VAT breakdown, totals and payment details, each value the exact source string with its XML path and line. CII dates are read from their format code; a date in a format that cannot be read safely is kept as written, with a notice. An amount without its own currency has none: the document currency is never assumed. Anything the model does not show is counted in unshown_elements and the first few are named in notices, so a partial reading says so. Viewing never validates.

Problems

CodeWhen
family_mismatchThe document declares another family than the one named; detected says what it declares.
family_undetectedNo family was named and the document declares none Ironfang recognises.
unsupported_variantThe XRechnung Extension or CVD.
unsupported_document_typeNot an invoice or credit note, or a type that contradicts the one named.
scope_unavailableA PDF, or a hybrid scope asked for XML.
payload_too_largeXML over 5 MiB.
idempotency_conflictThe Idempotency-Key was used for different bytes or a different selection.
validator_unavailable, validation_timeout, internal_errorNo verdict: indeterminate and not charged. Retry.