Automation MCP Server Features Blog Pricing Contact
Sample files Factur-X 1.0 / ZUGFeRD 2.x

Factur-X sample files

One hybrid PDF and its embedded CII XML for each of the five Factur-X profiles, plus fixtures that are broken on purpose. Every file is generated by the InvoiceXML API and validated against its declared profile before it is published.

Factur-X is a hybrid invoice: a normal PDF/A-3 that a person can read, with a machine-readable CII XML file attached inside it. The tricky part when you implement it is that the standard is not one format but five nested profiles, each with its own rulebook, and a file that passes one will not necessarily pass another.

Below is one valid file per profile, in both forms: the hybrid PDF as you would receive it, and the CII XML extracted from it so you can start on the XML side before wiring up attachment extraction. Everything on this page was produced by our own API, so there are no licence terms to read and nothing to attribute.

What is in the set

ProfileBT-24 identifierInvoice linesEN 16931 compliant
MINIMUMurn:factur-x.eu:1p0:minimumNoNo
BASIC WLurn:factur-x.eu:1p0:basicwlNoNo
BASICurn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basicYesYes
EN 16931 (COMFORT)urn:cen.eu:en16931:2017YesYes
EXTENDEDurn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extendedYesSuperset

All five carry the same underlying invoice, so you can diff them against each other and see exactly what each rung adds. It is a three-line services invoice from a German seller to a French buyer, with a document-level discount, a freight charge, a line-level surcharge, an invoicing period, and payment by SEPA credit transfer, which is enough to exercise the parts of a parser that a two-line toy invoice never reaches.

MINIMUM

The smallest rung: an accounting hint rather than an invoice. The XML carries the invoice number and date, the seller with its VAT and legal registration, the buyer's name, the currency, and four totals. There are no line items, no VAT breakdown per rate, and no payment instructions, because the PDF page is the invoice and the XML exists only to save the receiving system some typing.

Test against it if you receive from French suppliers, where MINIMUM is still common. It is also the fastest way to find out whether your parser assumes invoice lines exist.

Identifier detail: urn:factur-x.eu:1p0:minimum

BASIC WL

BASIC without lines. Everything a payment and booking process needs at document level, so the VAT breakdown per rate, document-level allowances and charges, payment means with the IBAN, payment terms, the delivery date and the invoicing period all appear. What is still missing is the line items, which is why it cannot claim EN 16931 compliance either.

Useful as the boundary case in a test suite: it looks complete until you go looking for what you were going to reconcile against.

Identifier detail: urn:factur-x.eu:1p0:basicwl

BASIC

The first rung that is a real EN 16931 invoice. BASIC WL plus the invoice lines, each with quantity, unit, net price, item name and VAT category, which is what makes it a subset of the European core model rather than a booking aid.

If you only have time to test one profile, make it this one. It is the smallest profile that satisfies the German B2B mandate, so it is the realistic floor for what you will be sent, and anything that reads BASIC will read EN 16931 with only small additions.

Identifier detail: urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic

EN 16931 (COMFORT)

The complete European core data set. Against the BASIC file, this one adds the seller's contact details, per-line item descriptions and the seller's own article identifiers, which is the practical difference you will notice most: BASIC's restricted schema rejects those elements outright rather than ignoring them.

The profile is named EN 16931 in the specification and COMFORT in ZUGFeRD's own documentation and in most tooling. They are the same thing, and the file declares the plain urn:cen.eu:en16931:2017 identifier with no vendor suffix.

Identifier detail: urn:cen.eu:en16931:2017

EXTENDED

The only profile that goes beyond EN 16931 rather than carving a subset out of it, which is why its identifier uses the #conformant# keyword where the narrower profiles use #compliant#. It exists for billing that the core model cannot express: sub-invoice lines, multiple deliveries per invoice, richer party and reference structures.

The file below is a valid EXTENDED document that carries the EN 16931 element set. Because EXTENDED is a superset, that is conformant, and it is representative of most EXTENDED traffic in practice. It is not a showcase of the extension elements themselves, so if you are specifically testing sub-invoice lines you will need a fixture built for that.

Identifier detail: urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended

Files that are wrong on purpose

Valid samples only prove that your happy path works. These two exist to prove that your error path does, and each fails in a specific, documented way rather than being generically corrupt.

The first is the more interesting one. It is structurally perfect, so an XSD check passes it and a naive integration will accept it and book a wrong amount. Only the Schematron layer catches it, with the message [BR-CO-15]-Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110). If your validator returns green on this file, it is not running Schematron. See BR-CO-15 for what the rule checks and why it is the one that catches most rounding bugs.

It declares the EN 16931 profile, so it is otherwise identical to the valid EN 16931 sample above and the broken total is the only thing wrong with it. That also means it carries the item descriptions and article identifiers that BASIC's schema rejects, so do not feed it to a BASIC-only parser expecting a clean single failure: use it against EN 16931 or EXTENDED.

One thing worth knowing if you hit the same defect on a MINIMUM, BASIC WL or BASIC file: the official Factur-X profile rule sets number their checks by serial, so most tools report this as FX-SCH-A-000121 rather than BR-CO-15. It is the same rule. Our validator resolves the serial back to the EN identifier, so you get a searchable rule name whichever profile you send.

The second is the case every extractor meets in production: a PDF that looks like an invoice and is not a Factur-X file at all. Your code should say so clearly instead of throwing a null reference.

How these files were generated

Each one is a single API call. The same invoice JSON goes to the same endpoint for every profile, and the profile is one field in the request, which is worth knowing if you are weighing how much of this you want to build yourself:

curl -X POST https://api.invoicexml.com/v1/create/facturx \
  -H "Authorization: Bearer $INVOICEXML_API_KEY" \
  -H "Content-Type: application/json" \
  -d @invoice.json \
  --output facturx-basic.pdf

The XML files are the attachments pulled back out of those PDFs with /v1/extract/xml. Before publishing, every file is run through the validator against its declared profile, which is how we know the valid ones are valid and the broken one breaks on exactly one rule.

If you want to produce your own fixtures with your own party data instead of ours, the Factur-X create endpoint is the same call shown above, and the validator takes a file upload directly.

Why sample files go stale

These were generated on 6 August 2026, against Factur-X Schematron 1.0.9 and the EN 16931 CII rules 1.3.16. That version stamp matters more than it looks: the profile Schematron, the EN 16931 rule set and the country CIUS rules are each maintained by different bodies on their own release cycles, and a rule set bump can turn a file that validated last year into one that does not.

That is the part of Factur-X that is genuinely tedious to own. Writing a CII builder is a finite project you can finish in a few weeks. Keeping it correct means tracking FNFE-MPE, FeRD and KoSIT releases indefinitely, re-vendoring artefacts, re-running your corpus and shipping an update every time, for as long as you send invoices.

The alternative is not writing less code, it is not owning that cycle. On the InvoiceXML API the current artefacts are simply what you get: no SDK to upgrade, no redeploy when a rule set changes, no version matrix to reason about. If you would rather spend the time on your product than on the specification, start with the free trial, or read how the Factur-X API handles the profile ladder end to end.

Frequently asked questions

Are these Factur-X sample files free to use?

Yes. They are our own output, not a copy of the FNFE-MPE or FeRD sample packages, so there are no licence terms attached. Use them in test suites, demos, CI fixtures or documentation without asking. They contain fictional parties and amounts and are not valid commercial invoices.

What is the difference between a Factur-X and a ZUGFeRD sample file?

At the file level, very little. Factur-X and ZUGFeRD are the same Franco-German standard published under two names, so the CII XML is identical and the profile URNs are shared. The differences are the attachment name inside the PDF and the legacy urn:zugferd.de:2p0:* identifiers that older ZUGFeRD 2.0 documents still declare.

Which profile should I test against?

BASIC if you only need one. It is the smallest profile that is EN 16931 compliant, so it is the realistic floor for German and French B2B, and anything that reads BASIC will read EN 16931 with minor additions. Add MINIMUM if you receive files from French suppliers, because it carries no line items at all and breaks parsers that assume they exist.

Why does the MINIMUM sample have no invoice lines?

Because the profile has none. MINIMUM and BASIC WL are booking aids: the XML carries header data and totals, and the line detail exists only in the human-readable PDF page. A parser that requires ram:IncludedSupplyChainTradeLineItem will fail on both, which is exactly why they are worth testing against.

Can I open the embedded XML without a Factur-X library?

Yes. The XML is a standard PDF file attachment, so any PDF library that can list embedded files can pull out factur-x.xml. We publish the extracted XML alongside each PDF so you can start on the XML side before wiring up extraction.