Factur-X: one PDF, two readers

A Factur-X invoice is a single PDF that a person can read and a machine can parse. Here is how the two halves fit together, which profile you are actually sending, and what has to stay in sync.

A Factur-X file drawn as one PDF holding two layers: the page a person opens, checks and approves, and factur-x.xml, the same invoice as data attached inside for software.

Factur-X solves an old tension. Accounts payable wants a document a human can look at and approve. The booking system wants structured data it can post without retyping. Factur-X gives both, in one file.

A PDF that carries its own data

A Factur-X file is a PDF/A-3 document with a structured XML invoice attached as an embedded file. The PDF is the visual invoice. The XML is the same invoice as data, following the EN 16931 semantic model in the UN/CEFACT CII syntax. Your reader opens the PDF; your software pulls the attachment.

The format is maintained jointly by FNFE-MPE in France and FeRD in Germany, and the same artifacts ship under two names: Factur-X in France, ZUGFeRD 2.x in Germany. They are the same format with two regional labels, not two formats you have to support separately.

The attachment has a name, and it matters

The embedded XML is found by filename, not by guessing. Three names are in circulation, and a receiving system has to accept all of them:

  • factur-x.xml for Factur-X, and what Beliq writes when it assembles a Factur-X hybrid
  • zugferd-invoice.xml for ZUGFeRD 2.x
  • ZUGFeRD-invoice.xml for ZUGFeRD 1.x, including the capital letters

A PDF whose attachment is called anything else is, as far as a Factur-X reader is concerned, a PDF with no invoice data in it. If you are generating hybrids yourself, this is the single easiest thing to get wrong, because the file looks perfectly fine when a person opens it.

Which profile are you actually sending

“Factur-X” is not one data set. The format ships five profiles, and they differ in how much of the invoice the XML is required to carry. Picking one is a real decision, because a receiver that needs line items cannot book a MINIMUM document however valid it is.

Profile What the XML carries
MINIMUM Header only: invoice number, dates, totals
BASIC WL Header-level data, still without invoice lines
BASIC Header data plus the essential invoice lines
EN 16931 Full EN 16931 compliance, and the usual choice
EXTENDED EN 16931 plus the EXTENDED-only fields

The document announces its own profile in GuidelineSpecifiedDocumentContextParameter/ram:ID, and that URN is what a validator keys off:

The profile URNs
minimum    urn:factur-x.eu:1p0:minimum
basicwl    urn:factur-x.eu:1p0:basicwl
basic      urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic
en16931    urn:cen.eu:en16931:2017
extended   urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended

Two of those are worth a second look. The EN 16931 profile declares the bare urn:cen.eu:en16931:2017, which is exactly what a plain EN 16931 CII document carries, so nothing in the URN says “Factur-X” at all. And France’s reform adds a sixth value on top of EXTENDED, urn:cen.eu:en16931:2017#conformant#urn.cpro.gouv.fr:1p0:extended-ctc-fr, which is the reference profile for the French B2B mandate.

What the embedded XML looks like

The attachment is a CII document. Even a trimmed view shows the shape: a context block naming the profile, a header, and a settlement block with the totals that have to reconcile.

factur-x.xml (excerpt)
<rsm:CrossIndustryInvoice>
  <rsm:ExchangedDocumentContext>
    <ram:GuidelineSpecifiedDocumentContextParameter>
      <ram:ID>urn:cen.eu:en16931:2017</ram:ID>
    </ram:GuidelineSpecifiedDocumentContextParameter>
  </rsm:ExchangedDocumentContext>
  <rsm:ExchangedDocument>
    <ram:ID>INV-2026-00481</ram:ID>
    <ram:IssueDateTime>
      <udt:DateTimeString format="102">20260901</udt:DateTimeString>
    </ram:IssueDateTime>
  </rsm:ExchangedDocument>
  <rsm:SupplyChainTradeTransaction>
    <ram:ApplicableHeaderTradeSettlement>
      <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
    </ram:ApplicableHeaderTradeSettlement>
  </rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

The nesting under ram:IssueDateTime is not decoration. BT-2 is a format-qualified date: the value sits in udt:DateTimeString with format="102", meaning YYYYMMDD. Writing the date straight into ram:IssueDateTime is invalid against the CII schema, and it is a common first attempt when hand-building a document.

Both halves have to agree

The risk with a hybrid file is drift: a total shown on the PDF that does not match the XML. Nothing in the container prevents it. The two halves are produced by different code paths in most systems, and only one of them is what your customer’s software will book.

So a Factur-X document has three distinct things that can be wrong, and they are checked in different places:

  1. Structure. Is the XML well formed and valid against the CII schema, and against the per-profile XSD subset where one applies.
  2. Semantics. Does it satisfy EN 16931 and the rules layered on top: the Schematron arm the document’s own CustomizationID selects, and France’s CTC rules when that identifier is EXTENDED-CTC-FR, when BT-23 carries a French cadre de facturation code, or when the request sets franceCtc.
  3. The container. Is the file really PDF/A-3, with the attachment present under a name a reader will look for.

Send a hybrid PDF to /v1/validate and Beliq covers the first two. It finds the embedded XML, refuses the document outright if there is none, and then validates that XML against the rules of point 2, reporting the exact rule versions it used. The third, the container, /v1/validate does not check: its answer is about the embedded XML only.

The PDFs Beliq builds itself are checked. POST /v1/generate with output: "pdf" for Factur-X or ZUGFeRD, and POST /v1/convert when it re-wraps a PDF around converted XML, run veraPDF on the finished file against its PDF/A-3b profile and return no file in which it reports a violation. A test-mode PDF is watermarked after that check, and the watermarked file does not pass the profile. A PDF that /v1/convert hands back as you sent it is not checked as a PDF.

That is the argument for generating the hybrid in one place rather than stapling a PDF to an XML file late in the process. Drift between the two halves is not a validation finding anywhere. It is a dispute six weeks later, when a person reads one number and a machine booked another.

Factur-XPDF/A-3EN 16931

Build against the real rulesets.

Generate, validate, and parse e-invoices through one API. Free tier, no card.