# Your own PDF design as ZUGFeRD/Factur-X

> https://billhorse.com/en/guides/custom-pdf-design-zugferd/

Many teams have a carefully designed invoice PDF — logo, brand typography, a footer with payment terms — and now face the task of turning it into an e-invoice without giving up the design. That is exactly what ZUGFeRD and Factur-X were built for: hybrid invoices that look to humans like they always did, while carrying a structured XML for machines. The path is well specified, yet in practice it regularly fails on a handful of details.

## Anatomy: PDF/A-3 plus embedded CII XML

A ZUGFeRD/Factur-X invoice consists of three layers:

**The container is a PDF/A-3.** Not PDF 1.4, not PDF 1.7, but the archival standard ISO 19005-3 — the only PDF/A flavour that permits arbitrary file attachments. PDF/A-3 also forbids encryption, JavaScript and external dependencies such as non-embedded fonts.

**The embedded XML** is a UN/CEFACT CII file with a normative filename that depends on standard and version: `factur-x.xml` for ZUGFeRD 2.1+ and Factur-X (`xrechnung.xml` in the XRECHNUNG profile), `zugferd-invoice.xml` for ZUGFeRD 2.0, `ZUGFeRD-invoice.xml` for the legacy ZUGFeRD 1.0. The attachment needs an `AFRelationship` entry — typically `Alternative` for the full profiles (the XML is an alternative representation of the same invoice), but `Data` or `Source` for the reduced MINIMUM and BASIC WL profiles.

**The PDF's XMP metadata** declare, via the Factur-X extension schema, what is embedded: `DocumentType` (INVOICE), `DocumentFileName` (exactly the attachment name), `Version` and `ConformanceLevel` — that is, the profile, from MINIMUM to EXTENDED. Receiving systems read this declaration before they ever touch the XML.

## The classic pitfalls

Almost every broken hybrid invoice falls into one of these patterns:

- **A plain PDF instead of PDF/A-3.** The invoice renderer produces PDF 1.4/1.7 and the XML gets attached "somehow". Some recipients extract it anyway; conformant checks reject it.
- **Missing or wrong XMP declaration.** The XML is there, but the XMP metadata are absent or name a different file — to strict recipients, that is not a ZUGFeRD/Factur-X invoice.
- **Wrong attachment filename.** `invoice.xml` or `rechnung.xml` instead of `factur-x.xml`. The content may be perfect; it won't be found everywhere.
- **Profile mismatch.** The XML declares the EN 16931 profile via the CustomizationID ([BT-24](/en/terms/bt-24/)) while the XMP says BASIC — two truths that recipients believe to different degrees. Which profiles count as e-invoices at all is covered in the [profiles guide](/en/guides/zugferd-profiles/); MINIMUM and BASIC WL are flagged by the validator as [BH-PROFILE-01](/en/rules/bh-profile-01/).
- **Encrypted PDFs.** Password protection sounds like security but makes the embedded XML unreadable — and is forbidden in PDF/A-3 anyway. Billhorse reports this explicitly as [BH-PDF-02](/en/rules/bh-pdf-02/).

## Tooling paths

Nobody needs to reinvent the wheel. In the Java world, mustangproject and PDFBox are established ways to convert an existing PDF to PDF/A-3 and attach the XML with `AFRelationship` and XMP; comparable libraries exist for .NET and Python. The principle is always the same: render the designed PDF as before, then in a second step convert the container, embed the XML, write the XMP.

One priority should be clear throughout: the machine-readable part is what recipients actually process — the design is only for the eye. The care belongs in the XML: correct totals arithmetic, complete mandatory fields, the right profile. A beautiful PDF with broken XML is not an e-invoice; a plain PDF with clean XML is.

## Verification workflow: cross-check the result

Before anything ships, the generated PDF belongs in the [Billhorse validator](/en/zugferd-validator/): it extracts the embedded XML straight from the PDF container and validates it against EN 16931 and the profile-specific rules — entirely in the browser, no upload. If no invoice XML is found inside the PDF, the result is [BH-PDF-01](/en/rules/bh-pdf-01/) — the most common symptom of a generation path that simply forgot the embedding step. If the PDF is encrypted, that is reported explicitly as BH-PDF-02 rather than as a vague parse error. Test with real edge cases: an invoice with a discount, a credit note, an invoice with multiple VAT rates — that is where mapping bugs surface that the happy-path example never triggers.

## Mandatory: visible part and XML must match

One point is not a matter of style but an obligation: the visible PDF and the embedded XML must describe the same invoice. Legally, the structured part is authoritative — if the visual rendering deviates, the XML governs. Divergence almost always arises when PDF and XML are produced by separate code paths: the PDF rounds differently, the XML doesn't know about the discount, a line item is missing. The robust architecture renders both representations from the same data source — one invoice model, two outputs. Build it that way from the start and consistency never needs manual checking again.
