How to Validate E-Invoices Programmatically
Three approaches to e-invoice validation in your pipeline: build your own, use open-source tools, or call an API. Code examples for each.
You have an invoice pipeline. Invoices come out of your ERP as XML. They need to be valid EN 16931 before they hit a Peppol Access Point or government portal. How do you validate them programmatically?
Three approaches, each with trade-offs.
The Four Validation Layers
Before choosing a tool, understand what "valid" means. Every EU e-invoice passes through four layers:
| Layer | What It Checks | Rule Format | |-------|---------------|-------------| | 1. XML Schema | Well-formed XML, correct namespaces, valid data types | XSD (XML Schema Definition) | | 2. EN 16931 Business Rules | Required fields, amount calculations, VAT consistency | Schematron | | 3. Format Rules | Peppol BIS, XRechnung, Factur-X-specific requirements | Schematron | | 4. Country CIUS | Germany (BR-DE-), Belgium (BEvCIUS), France (FR-R-) | Schematron |
Most validation failures happen at layers 2-4. Layer 1 catches malformed XML. Layers 2-4 catch business logic issues: missing buyer references, VAT mismatches, wrong identifier schemes.
Approach 1: Build Your Own
Download the validation artifacts and run them locally.
What You Need
- EN 16931 Schematron rules: Available from CEN TC 434
- Peppol validation artifacts: Available from Peppol
- Country CIUS rules: XRechnung from KoSIT GitHub, others vary
- A Schematron processor: Saxon (Java), libxml2 (C), or lxml (Python)
Example: Java with KoSIT Validator
KoSIT provides an open-source validator that handles all four layers for German invoices:
// Using KoSIT validator library
Configuration config = Configuration.load(
URI.create("scenarios.xml")
);
Validator validator = new Validator(config);
Result result = validator.validate(inputFile);
if (result.isAcceptable()) {
// Invoice passes all rules
} else {
// result.getReport() contains detailed error information
}
Pros and Cons
Pros: Full control, no external dependencies, no per-invoice cost, works offline.
Cons: You maintain the validation artifacts. When EN 16931 updates (annually), when Peppol releases new rules (2-3x/year), when country CIUS changes — you update. For one country, this is manageable. For 10+ countries, it's a maintenance burden.
Approach 2: Open-Source Validators
Use hosted open-source validation services.
Options
KoSIT Validator — Java-based, supports XRechnung and EN 16931. Can be deployed as a local service. The German reference implementation — if your invoice passes KoSIT, it's accepted by German government portals.
Peppol Practical (Helger) — Web service for Peppol validation. Supports Peppol BIS 3.0 and various country profiles. Can be self-hosted.
EU Commission ITB Validator — The EU's reference validator. Web interface and REST API. Covers EN 16931 base rules.
Example: EU Commission ITB REST API
curl -X POST "https://www.itb.ec.europa.eu/api/validation" \
-H "Content-Type: multipart/form-data" \
-F "file=@invoice.xml" \
-F "type=ubl" \
-F "domain=einvoice"
Pros and Cons
Pros: No artifact maintenance, community-supported, free.
Cons: Limited to validation (no remediation), no error classification, API availability varies, may not support all country CIUS rules.
Approach 3: Validation API with Remediation
Use an API that validates, classifies errors, and optionally remediates.
Example: Invoice Navigator API
import { InvoiceNavigator } from '@invoice-navigator/sdk';
const client = new InvoiceNavigator({
apiKey: process.env.INVOICE_NAVIGATOR_API_KEY
});
// Validate an invoice
const result = await client.validate({
invoice: fs.readFileSync('invoice.xml'),
format: 'auto' // auto-detect format
});
console.log(result.valid); // boolean
console.log(result.errors); // classified error list
console.log(result.fixable); // count of auto-fixable errors
console.log(result.inputRequired); // fields needing manual input
console.log(result.blocked); // financial field issues
from invoice_navigator import Client
client = Client(api_key=os.environ["INVOICE_NAVIGATOR_API_KEY"])
result = client.validate(
invoice=open("invoice.xml", "rb"),
format="auto"
)
for error in result.errors:
print(f"{error.code}: {error.message} [{error.fix_type}]")
curl -X POST "https://api.invoicenavigator.eu/v1/validate" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/xml" \
-d @invoice.xml
With Remediation
// Validate + auto-remediate in one call
const result = await client.process({
invoice: fs.readFileSync('invoice.xml'),
remediate: true // auto-fix structural issues
});
if (result.status === 'compliant') {
// result.invoice contains the remediated invoice
// result.evidencePack contains the audit trail
fs.writeFileSync('invoice-fixed.xml', result.invoice);
}
Pros and Cons
Pros: All four layers covered, automatic rule updates, error classification (auto-fix / input-required / blocked), remediation pipeline, Evidence Pack generation, multi-country support from one integration.
Cons: Per-invoice cost, external dependency, requires API key.
Integration Patterns
Pattern 1: Pre-Submission Gate (Synchronous)
ERP export → Invoice Navigator API → [valid?] → Access Point → Peppol
→ [invalid?] → Error queue
Your ERP generates the invoice XML, calls the validation API, and only sends to the Access Point if the invoice passes. Invalid invoices go to an error queue for review or auto-remediation.
Pattern 2: Batch Validation (Async)
ERP export → Queue → Invoice Navigator batch API → Results → Process/Send
Collect invoices during the day. Run batch validation overnight or hourly. Process results and route valid invoices to the Access Point, flag invalid ones for review.
Pattern 3: CI/CD Pipeline Check
Template change → Generate test invoice → Validate → Pass/Fail build
When your ERP export template changes, generate a test invoice and validate it as part of your build pipeline. Catch template regressions before they hit production.
Choosing Your Approach
| Factor | Build Your Own | Open-Source | API | |--------|---------------|-------------|-----| | Setup time | Days-weeks | Hours | Minutes | | Maintenance | You update rules | Community updates | Provider updates | | Country coverage | What you implement | Varies by tool | Multi-country | | Error classification | You build it | Basic pass/fail | Built-in | | Remediation | You build it | Not available | Built-in | | Cost | Dev time | Free | Per-invoice | | Best for | Single-country, high-volume, full control | Testing, one-off validation | Multi-country pipelines, production use |
For most ERP vendors serving multiple EU markets, an API covers the broadest set of requirements with the least maintenance. For single-country deployments with in-house expertise, building on KoSIT or helger makes sense.
FAQ
How many validation rules are there?
EN 16931 defines ~65 base business rules (BR-01 through BR-65). Peppol adds ~80 rules. Each country CIUS adds more — Germany's XRechnung has 26 additional rules (BR-DE-01 through BR-DE-26). A Peppol BIS invoice for a German receiver must pass all three sets.
How often do validation rules change?
EN 16931 releases updates annually. Peppol publishes rule updates 2-3 times per year. Country CIUS rules update on their own schedules. Germany's XRechnung typically releases a major version annually.
Can I validate Factur-X/ZUGFeRD PDFs via API?
Yes. Upload the PDF — the API extracts the embedded XML and validates both the PDF/A-3 conformance and the CII data. Try the validator →
What's the difference between validation and remediation?
Validation checks rules and reports errors. Remediation classifies errors and fixes the safe ones (structural issues that don't change commercial meaning). Financial fields are never modified. Read more →
Check Your Compliance Status
Find out exactly what your business needs to do for e-invoicing compliance.
Use Obligation FinderRelated Articles
Integrating E-Invoice Compliance Into Your ERP
How to add a compliance layer to your ERP product: architecture, integration patterns, code examples, and the Evidence Pack workflow.
E-Invoice Validation Rules Explained
EN 16931 defines ~65 business rules, Peppol adds ~80, and each country CIUS adds more. Here's how the four validation layers work, what they check, and which errors you'll see most.
The Real Cost of E-Invoice Rejections
When a Peppol invoice gets rejected, the cost isn't just the error fix. It's the payment delay, the support calls, and the trust erosion. Here's the full picture.