How to Validate XRechnung Against EN 16931 Reliably
Generating an XML file does not make it an accepted e-invoice. Validating XRechnung against EN 16931 means proving, before the invoice goes out, that the invoice data, the calculation logic, and the national requirements fit together. For B2B SaaS companies this check is a control point between the billing engine, tax logic, the accounts receivable process, and the public-sector buyer, so it cannot wait for a final QA pass.
If you only validate once a customer rejects an invoice, you usually already have a data model problem. For example, purchase order references are missing, a Leitweg-ID was not passed on, or the VAT shown contradicts the tax reason used. PDF rendering and manual spot checks do not catch errors like these reliably.
What gets checked in XRechnung under EN 16931
EN 16931 defines the European core for electronic invoices. It describes which business information an invoice may or must contain and how that information relates semantically. Examples include seller and buyer data, invoice number, invoice date, service period, payment terms, tax categories, amounts, and payment information.
XRechnung specifies this core for German public administration. The format is usually transmitted as UBL or as UN/CEFACT Cross Industry Invoice (CII). Both syntaxes can express the same business invoice. For engineering teams this has a direct consequence: switching from CII to UBL must not change the tax calculation, the rounding logic, or the mapping of product, contract, and usage data.
Reliable validation works on several levels. First, the document must be valid against the schema of the chosen syntax. Second, it must meet the business rules from EN 16931 and the XRechnung profile. Third, the invoice must be deliverable to the specific recipient. These levels are often confused.
An XML file can be syntactically valid and still fail on business or operational grounds. It can, for example, contain a tax breakdown whose totals don't match the invoice total. It can also carry a buyer reference in a technically permitted field and still lack the Leitweg-ID the recipient requires.
Validating XRechnung against EN 16931 starts in the data model
The most common architecture mistake happens before any XML is generated. Billing systems treat invoices as a rendered end product, although an invoice is a structured record that drives accounting entries. Once subscriptions, seats, minimum commitments, usage-based fees, credits, and promotions come together on one invoice, a simple sum of line items no longer works.
Here is an example. In March, a customer's invoice includes a platform fee of €500, 2,400 API events at a variable price, and a contractual discount. It also shows a correction for February usage that was overbilled. For the XRechnung to stay valid, net line amounts, discounts, tax rates, tax amounts, and document totals all have to be derivable without ambiguity. A discount cannot exist only as a visual deduction on the PDF. It needs a traceable representation in the structured invoice data.
The same applies to the service period. For recurring services, the invoice date is not automatically the date of supply. With usage-based billing, the billing period has to be derivable from the underlying events. For credit notes and cancellation invoices, it must be clear which original document they refer to. Without this information a validator may let individual rules pass, but finance has no reliable basis for receivables, accruals, or revenue recognition.
The right order is to model the product catalog and contract data, document the tax decision, calculate the invoice draft, and validate against the EN 16931 rules. Only then do you deliver and post the invoice. Price changes without a deploy only work if price and tax data are versioned and each invoice can be traced back to one specific configuration.
Which rules most often lead to rejections
Many errors come from fields that rarely show up in ordinary B2B invoicing but can be mandatory in the public sector. The buyer reference, which often holds the Leitweg-ID, is one of them. The recipient uses it to assign incoming invoices automatically. If it is missing, the invoice is unusable for the recipient's process, even when the amounts are correct.
Payment data matters just as much. If you include payment terms, IBAN, payment reference, or SEPA details, they have to be consistent with the payment method. On an invoice that has already been collected, a payment instruction can mislead the customer. When the customer pays on invoice, the payment reference has to be set so that accounts receivable can match the incoming payment automatically.
Tax cases are the second big source of errors. A tax amount of zero does not give the reason on its own. Depending on the case, the tax category and the exemption or reverse charge note have to fit together. SaaS providers with EU customers in particular should not try to put tax wording only as free text on the PDF version. The tax treatment has to follow from the structured data, the place of supply, and the customer's status.
Rounding is the third classic. Line amounts, tax base, tax amount, and grand total have to add up mathematically. With high quantities and small usage prices, differences appear quickly when rounding happens at different points. Whether you round per event, per line, per tax rate, or only at document level should not be left to whoever writes the code. The rule has to be defined, tested, and applied the same way across all output channels.
Build validation into the release process
A web validator is useful for debugging, but you cannot run production on it. It validates a single document after the fact and leaves no auditable process behind. In a growing billing stack, the check should run automatically as part of document generation.
A split between a business pre-check and a formal document check works well in practice. The pre-check covers data that is not yet XML-specific. Does a public-sector customer have a valid buyer reference? Is a purchase order number required? Is the service period present? Was the tax case determined correctly from country, VAT ID (USt-IdNr.), type of service, and customer type? If data is missing here, the invoice should get the status blocked instead of producing faulty XML.
The formal check runs after the transformation into CII or UBL. It covers the schema and Schematron rules of the intended XRechnung release. Store the validation report per rule, field, and invoice ID. That record is what lets you answer a query later: which rule version the document was checked against, and which input data belonged to the invoice.
For engineering, this means validator versions belong in the release process. XRechnung specifications keep evolving. A deployment that rolls out a new mapping for payment terms or reference fields needs test invoices for standard cases, credit notes, reverse charge, tax-exempt services, multiple tax rates, and rounding edge cases. A green unit test for the XML serializer is not enough.
Delivery is a separate checkpoint
A valid XRechnung has not necessarily been delivered. Federal authorities, the states, and municipal buyers can use different submission routes, portals, or Peppol endpoints. That makes recipient master data part of the billing infrastructure.
For each customer, store at least the invoice format, preferred syntax, buyer reference, routing information, whether a purchase order reference is required, and the delivery channel. This data must not live in one-off engineering exceptions or in a finance spreadsheet. Keep it versioned on the customer account, and make sure it can be retrieved before the invoice is approved.
Status models need to stay precise as well. generated, validated, submitted, accepted, rejected, paid, and credited are distinct states. If you treat sent as the final state, you lose sight of operational errors. If you don't separate accepted from the receipt of payment, receivables management and invoice delivery get mixed up.
A practical control standard for SaaS teams
Before an XRechnung goes out, four pieces of evidence should be in place:
- The document passes schema and business rule validation for the chosen XRechnung version.
- Totals, tax base, and tax amounts can be reproduced from the billed contract, price, and usage data.
- The buyer reference, purchase order reference, payment method, and routing data meet the requirements of the specific recipient.
- The validation report, original XML, invoice PDF, and ledger entry are stored under the same immutable invoice ID.
Kontier models this chain as part of a European billing and revenue operations architecture, from versioned pricing rules and tax decisions through XRechnung and payment collection to DATEV-ready ledger data. Besides fewer rejections, the operational gain is that finance and engineering work from the same auditable invoice history.
Good validation stops a faulty invoice before it is sent and shows the team exactly which source data to correct before month-end close.