E-invoices with ZUGFeRD and Factur-X in Oicana
An invoice can have two readers. A person opens the PDF, checks the amount, and pays it. Or software extracts its data, so it can handle the invoice automatically. A regular PDF mostly serves the first reader and can make it difficult to trust automatic handling of invoices.
ZUGFeRD and Factur-X are standards used in Germany and France that solve this by putting both readers in one file: a normal PDF users can look at, with the structured invoice data embedded as XML for automation. This post explains why you would want or need that and how Oicana produces such a file from a Typst template.
Why structured invoices
Section titled “Why structured invoices”More and more countries require invoices to carry machine-readable data, not just a printed layout. The relevant ones for the standards we are looking at here are:
- Germany mandates that businesses can receive structured e-invoices for domestic B2B since 2025, with required sending of e-invoices following in phases over the next years.
- France is rolling out a Factur-X based mandate on a similar timeline.
Even where it is not yet required, structured invoices save work. The recipient’s system reads the totals, tax rates, and line items straight from the file. No manual entry, no OCR guesswork, fewer mistakes.
What ZUGFeRD / Factur-X is
Section titled “What ZUGFeRD / Factur-X is”Three things have to line up for a valid e-invoice:
- A PDF/A-3 document (the archivable, self-contained PDF profile).
- The invoice XML embedded as an associated file.
- XMP metadata in the PDF that declares the embedded XML and which profile it follows.
Get one of those wrong and validators can reject the file. This makes e-invoices fiddly to produce by hand.
How Oicana builds one
Section titled “How Oicana builds one”Oicana compiles a Typst template to PDF, and its PDF export can embed files and write custom XMP metadata. That is exactly what the three points above need.
The invoice_zugferd example template shows the full setup.
1. Export to PDF/A-3 in the manifest. You declare the standards once, next to the template:
[tool.oicana.export.pdf]standards = ["ua-1", "a-3b"]
[[tool.oicana.inputs]]type = "blob"key = "zugferd"default = { file = "factur-x.xml" }Here the invoice XML comes in as a blob input, so you can pass a different one per invoice. The a-3b standard allows embedding files to be a valid e-invoice. Adding ua-1 makes the same document more accessible through PDF/UA-1.
2. Embed the XML in the template. A single line takes the XML bytes, embeds them, and writes the matching XMP metadata:
#import "@preview/oicana:0.2.0": setup#import "@local/invoice-harness:0.1.1": *
#let read-project-file(path) = read(path, encoding: none)#let (input, oicana-image, _) = setup(read-project-file)
// Embed the invoice XML and declare it in the PDF metadata#factur-x(input.zugferd.bytes, profiles.en16931)
// ... the rest of the template renders the visible invoiceThe factur-x call handles the embedding and the XMP. The rest of the template is an ordinary invoice layout, free to look however you want.
Getting started
Section titled “Getting started”The Oicana documentation includes a guide on creating e-invoices with one of our seven integrations. You can follow it see how to generate e-invoices from Node.js, the browser, Python, Rust, Java, PHP, or C#.
With Oicana it’s easy to create e-invoices in your code.
Get started with Oicana