The shape of an EU e-invoice (and why it’s two formats stacked)
A modern EU e-invoice is two documents wrapped in one file:
- A PDF/A-3 that a human can read — invoice number, line items, totals, supplier branding. The PDF/A-3 spec (ISO 19005-3) is the only PDF/A variant that allows arbitrary file attachments inside the archival wrapper.
- An EN 16931 CII XML attachment inside that PDF — the same invoice expressed as structured data that AP automation, ERP imports and tax-authority systems can parse without OCR.
Factur-X (France) and ZUGFeRD (Germany) are the same idea, different national labels. Both attach an EN 16931 Cross-Industry Invoice (CII) XML to a PDF/A-3 wrapper. ZUGFeRD has been mandatory for German B2B invoice receipt since 2025; Factur-X is phasing into mandatory B2B issuance in France through 2026–2027.
If you’re sending invoices to French or German customers in 2026, one of these two formats is no longer optional.
Why generating it from scratch is painful — and why gPdf is one endpoint
Stitching this together from scratch involves:
- Generating PDF bytes (typesetting, fonts, layout).
- Generating the CII XML separately, matching EN 16931.
- Setting the PDF/A-3 XMP namespace correctly (
urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#for Factur-X; the ZUGFeRD 2.x namespace differs). - Embedding the XML with
AFRelationship="Alternative"per spec. - Marking the embedded file in PDF/A-3’s
/AFarray correctly. - Validating the result with veraPDF (PDF/A side) AND Mustang (CII XML side) — both must pass.
A typical team gets this wrong twice before it passes both engines. The gPdf API collapses all six steps into a single POST /api/v1/e-invoice/render call. You provide:
settings.e_invoice.standard—factur_xorzugferdsettings.e_invoice.xml.content— your CII XMLpages[]— the visible invoice layout- everything else is auto-emitted with the correct PDF/A-3 metadata.
See §5 of the E-Invoice API reference for the full request schema, validation modes (basic vs strict), and async job lifecycle for strict-validation runs.
Verifying the output — the audit pattern
A vendor saying “yes our PDF passes PDF/A-3” is worth nothing if the audit auditor uses the reference engines. The audit-grade pattern is:
- Generate the e-invoice via
POST /api/v1/e-invoice/render. - Drop the resulting PDF into validator — runs:
- veraPDF: the official reference implementation maintained by the PDF Association. PDF/A-3 conformance.
- Mustang: open-source German project (mustangproject.org) that is the de-facto Factur-X / ZUGFeRD reference checker — extracts the embedded CII XML, validates against EN 16931 Schematron, reports field-by-field.
- Both reports return side-by-side in the same UI. Both must show “Pass” before you ship to production AP automation.
This pattern matters because:
- A PDF that passes veraPDF but fails Mustang means the wrapper is conformant but the XML inside is malformed — the AP system rejects the invoice on receipt.
- A PDF that passes Mustang but fails veraPDF means the XML is fine but the archival wrapper doesn’t satisfy PDF/A-3 — long-term archival rejected.
- Either failure breaks the end-to-end flow. Both must pass.
The validator is free, requires no login, and produces JSON reports you can attach to your QA evidence. It’s the same dual-engine pattern Big-Four audit firms use internally — gPdf just hosts it publicly.
Beyond Factur-X / ZUGFeRD
If you’re also working with:
- FatturaPA (Italy, mandatory since 2019) — already on the validator roadmap.
- Peppol BIS 3.0 UBL (Nordic / Benelux / increasingly cross-border) — roadmap.
- KSeF (Poland, mandatory 2026) — roadmap.
gPdf’s e-invoice endpoint will extend coverage as each format graduates from “early roadmap” to “live in the validator and the renderer”. The shape is the same: one JSON request, the right XMP namespace and AFRelationship handled internally, both engines verify before you ship.
TL;DR
- One API call → PDF/A-3 + embedded EN 16931 CII XML.
- Choose Factur-X or ZUGFeRD via
settings.e_invoice.standard. - Verify with validator — veraPDF + Mustang in parallel, free.
- Both engines must pass. The gPdf API is built so they do; the validator is the public receipt.