Guide for developers

Create ZUGFeRD: profiles, differences, and API example

ZUGFeRD combines machine-readable XML with a human-readable PDF in one document. This guide explains the profiles, the difference from XRechnung UBL, and how to generate ZUGFeRD invoices through a REST API.

Need to check a single invoice?

Use the web validator for quick browser-based checks with XML or ZUGFeRD PDF files.

Open validator

Need to automate e-invoicing?

Use the API for recurring validation, generation, and retrieval inside your software.

Open developer page

What is ZUGFeRD?

ZUGFeRD is a hybrid format: a PDF/A-3 file contains an embedded XML file based on the Cross Industry Invoice (CII) standard. The result is readable for people and processable for software at the same time.

The format is based on EN 16931 and therefore works beyond Germany as well. Factur-X, the French equivalent, is technically the same format.

ZUGFeRD profiles at a glance

ZUGFeRD 2.x defines multiple profiles with increasing data depth:

  • MINIMUM - only legally required fields. Useful for basic internal scenarios, but not EN 16931 compliant.
  • BASIC WL - an extended minimum profile without full line-item detail.
  • BASIC - line-level data included and suitable as a lighter starting point.
  • EN 16931 - the standard business profile for compliant B2B exchange.
  • EXTENDED - extra fields beyond EN 16931 for industry-specific needs.
  • XRECHNUNG - the German XRechnung profile in CII syntax instead of UBL.

For German public-sector invoicing, either XRechnung UBL or the XRECHNUNG profile in CII syntax is typically required.

The XInvoice API can generate ZUGFeRD documents in EN16931 or XRECHNUNG profile mode.

ZUGFeRD vs. XRechnung UBL - which one to choose?

XRechnung UBL is pure XML without a PDF wrapper. ZUGFeRD with the XRECHNUNG profile carries equivalent invoice information inside a PDF/A-3 document.

For B2B, ZUGFeRD is often more flexible because the recipient can still read a normal PDF while the embedded XML remains available for automation.

Generate ZUGFeRD via API - example

The XInvoice API generates ZUGFeRD invoices with a single POST request. Invoice data is sent as JSON, while format and profile are controlled through the payload:

curl -X POST https://api.xinvoice.net/v1/invoices/generate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "document_format": "zugferd",
    "document_profile": "EN16931",
    "seller": {
      "name": "Example GmbH",
      "street": "Example Street 1",
      "postal_code": "10115",
      "city": "Berlin",
      "country_code": "DE",
      "tax_number": "12/345/67890",
      "vat_id": "DE123456789"
    },
    "buyer": {
      "name": "Customer AG",
      "street": "Customer Lane 5",
      "postal_code": "20095",
      "city": "Hamburg",
      "country_code": "DE"
    },
    "invoice_number": "2025-0042",
    "issue_date": "2025-04-01",
    "due_date": "2025-04-30",
    "currency": "EUR",
    "items": [
      { "name": "Consulting April", "quantity": 8, "unit_code": "HUR", "price": 150.00, "tax_rate": 19 }
    ]
  }'
Generate a ZUGFeRD EN16931 invoice via API

The API returns an `invoice_id`. You can then download the finished PDF with embedded ZUGFeRD XML from the download endpoint.

If you want the PDF data directly inside the status response, append `?include_pdf_data=1` when polling the invoice endpoint.

Asynchronous generation for larger volumes

For higher invoice volumes, use the asynchronous workflow: the POST request returns quickly with an `invoice_id`, then your system polls until the document is generated.

That keeps invoice generation decoupled from your request-response cycle and scales much better than waiting on every request.