ZUGFeRD API — Generate & Validate Factur-X Invoices

Add ZUGFeRD to your software without implementing PDF/A-3 packaging, embedded CII XML, profile rules, and validation logic yourself. Generate and validate compliant hybrid invoices through one API — for developers integrating German e-invoicing.

  • PDF + XML in one file
  • 6 profiles
  • One POST

No credit card required · 500 free trial invoices, 30-day expiry.

Get an API key instantly and generate your first ZUGFeRD PDF in under a minute.

ZUGFeRD profiles
6
Container format
PDF/A-3
Embedded XML
EN 16931
Data retention
0

JSON Input

Canonical invoice data

InvoiceSpec Engine

Maps to EN 16931 & validates

Compliant Output

PDF/A-3

One file, two readers, same data

The document below is a real ZUGFeRD PDF/A-3 generated by the engine from a single canonical JSON invoice. The PDF page is what a person reads; the XML is what software reads — extracted from inside that exact PDF.

Human viewPDF/A-3 page
Real generated ZUGFeRD PDF/A-3 invoice — page 1
Machine viewEN 16931 CII XML embedded inside
Extracted from the PDF → application/xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<rsm:CrossIndustryInvoice xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100">
<rsm:ExchangedDocumentContext>
<ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:ID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</ram:ID>
</ram:BusinessProcessSpecifiedDocumentContextParameter>
<ram:GuidelineSpecifiedDocumentContextParameter>
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
</ram:GuidelineSpecifiedDocumentContextParameter>
</rsm:ExchangedDocumentContext>
<rsm:ExchangedDocument>
<ram:ID>INV-DEMO-001</ram:ID>
<ram:TypeCode>380</ram:TypeCode>
<ram:IssueDateTime>
<udt:DateTimeString format="102">20250701</udt:DateTimeString>
</ram:IssueDateTime>
</rsm:ExchangedDocument>
<rsm:SupplyChainTradeTransaction>
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Consulting Services</ram:Name>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>150.0</ram:ChargeAmount>
<ram:BasisQuantity>1</ram:BasisQuantity>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="C62">10</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>1500.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
<ram:ApplicableHeaderTradeAgreement>
<ram:BuyerReference>991-12345-67</ram:BuyerReference>
<ram:SellerTradeParty>
<ram:Name>Acme GmbH</ram:Name>
<ram:SpecifiedLegalOrganization>
<ram:ID>HRB98765</ram:ID>
</ram:SpecifiedLegalOrganization>
<ram:DefinedTradeContact>
<ram:PersonName>Max Mustermann</ram:PersonName>
<ram:TelephoneUniversalCommunication>
<ram:CompleteNumber>+49 30 12345678</ram:CompleteNumber>
</ram:TelephoneUniversalCommunication>
<ram:EmailURIUniversalCommunication>
<ram:URIID>billing@acme.de</ram:URIID>
</ram:EmailURIUniversalCommunication>
</ram:DefinedTradeContact>
<ram:PostalTradeAddress>
<ram:PostcodeCode>10115</ram:PostcodeCode>
<ram:LineOne>Musterstr. 1</ram:LineOne>
<ram:CityName>Berlin</ram:CityName>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="9930">DE123456789</ram:URIID>
</ram:URIUniversalCommunication>
<ram:SpecifiedTaxRegistration>
<ram:ID schemeID="VA">DE123456789</ram:ID>
</ram:SpecifiedTaxRegistration>
</ram:SellerTradeParty>
<ram:BuyerTradeParty>
<ram:Name>Example Corp</ram:Name>
<ram:PostalTradeAddress>
<ram:PostcodeCode>75001</ram:PostcodeCode>
<ram:LineOne>12 Rue de Rivoli</ram:LineOne>
<ram:CityName>Paris</ram:CityName>
<ram:CountryID>FR</ram:CountryID>
</ram:PostalTradeAddress>
<ram:URIUniversalCommunication>
<ram:URIID schemeID="9930">FR12345678901</ram:URIID>
</ram:URIUniversalCommunication>
</ram:BuyerTradeParty>
</ram:ApplicableHeaderTradeAgreement>
<ram:ApplicableHeaderTradeDelivery>
<ram:ActualDeliverySupplyChainEvent>
<ram:OccurrenceDateTime>
<udt:DateTimeString format="102">20250701</udt:DateTimeString>
</ram:OccurrenceDateTime>
</ram:ActualDeliverySupplyChainEvent>
</ram:ApplicableHeaderTradeDelivery>
<ram:ApplicableHeaderTradeSettlement>
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
<ram:SpecifiedTradeSettlementPaymentMeans>
<ram:TypeCode>30</ram:TypeCode>
<ram:PayeePartyCreditorFinancialAccount>
<ram:IBANID>DE89370400440532013000</ram:IBANID>
</ram:PayeePartyCreditorFinancialAccount>
</ram:SpecifiedTradeSettlementPaymentMeans>
<ram:ApplicableTradeTax>
<ram:CalculatedAmount>285.00</ram:CalculatedAmount>
<ram:TypeCode>VAT</ram:TypeCode>
<ram:BasisAmount>1500.00</ram:BasisAmount>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
<ram:Description>Payment due</ram:Description>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount>1500.00</ram:LineTotalAmount>
<ram:TaxBasisTotalAmount>1500.00</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount currencyID="EUR">285.00</ram:TaxTotalAmount>
<ram:GrandTotalAmount>1785.00</ram:GrandTotalAmount>
<ram:DuePayableAmount>1785.00</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
</rsm:CrossIndustryInvoice>

You shouldn't have to maintain PDF/A-3 and ZUGFeRD internals

Your application sends structured invoice data. InvoiceSpec handles the supported profile, embedded XML, PDF/A-3 packaging, and validation underneath — and keeps that implementation current as ZUGFeRD and EN 16931 evolve.

Generate ZUGFeRD

Send a canonical JSON invoice; receive a ZUGFeRD PDF/A-3 document with the EN 16931 CII XML embedded inside it (Content-Type: application/pdf). The example below uses a real minimal invoice body and the default EN16931 (COMFORT) profile — swap in your API key and it runs.

Request — curl
curl -X POST https://api.invoicespec.com/v1/invoice/zugferd \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
--output invoice-zugferd.pdf \
-d '{"invoice":{"invoiceNumber":"INV-DEMO-001","issueDate":"2025-07-01","invoiceTypeCode":"380","currencyCode":"EUR","buyerReference":"991-12345-67","seller":{"name":"Acme GmbH","legalRegistrationIdentifier":"HRB98765","vatIdentifier":"DE123456789","electronicAddress":"DE123456789","electronicAddressSchemeId":"9930","postalAddress":{"addressLine1":"Musterstr. 1","city":"Berlin","postcode":"10115","countryCode":"DE"},"contact":{"contactPoint":"Max Mustermann","telephone":"+49 30 12345678","email":"billing@acme.de"}},"buyer":{"name":"Example Corp","electronicAddress":"FR12345678901","electronicAddressSchemeId":"9930","postalAddress":{"addressLine1":"12 Rue de Rivoli","city":"Paris","postcode":"75001","countryCode":"FR"}},"deliveryInformation":{"actualDeliveryDate":"2025-07-01"},"paymentInstructions":{"meansCode":"30","creditTransfer":{"accountIdentifier":"DE89370400440532013000"}},"documentTotals":{},"vatBreakdowns":[{"vatCategoryCode":"S","vatCategoryRate":19}],"invoiceLines":[{"lineIdentifier":"1","quantity":10,"unitCode":"C62","priceDetails":{"netPrice":150},"lineVatInformation":{"vatCategoryCode":"S","vatRate":19},"itemInformation":{"name":"Consulting Services"}}]},"config":{"spec":"zugferd","syntax":"cii","profile":"EN16931"}}'

The response is the real PDF/A-3 shown in the demo above — a styled, human-readable invoice page with the EN 16931 CII XML embedded as the ZUGFeRD AF attachment.

Validate ZUGFeRD

Check an existing ZUGFeRD PDF against PDF/A-3 conformance and the embedded CII XML's ZUGFeRD profile rules before you send it. Upload the PDF and an optional version; the validator extracts the embedded XML, checks conformance, and returns a structured validation report.

Request — curl
curl -X POST https://api.invoicespec.com/v1/invoice/zugferd/validate \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@invoice-zugferd.pdf" \
-F 'request={"version":"2.5.2"}'
Response — application/json
{
"valid": false,
"version": "2.5.2",
"syntax": "CII",
"summary": { "errors": 1, "warnings": 0, "information": 0 },
"issues": [
{
"severity": "ERROR",
"code": "BR-DE-15",
"message": "An electronic address (BT-34) of the Seller is required."
}
],
"requestId": "req_01HXYZ..."
}

A failed validation is not an HTTP error — the endpoint returns 200 OK with valid: false and a structured issue list.

Try the free ZUGFeRD validator →

No signup required — upload a ZUGFeRD PDF and validate it directly in the browser.

Validation-error handling

Validation errors are returned as data, not as HTTP failures, so you can handle them programmatically. Each issue carries a normalized severity (ERROR, WARNING, INFORMATION), the official rule code (e.g. BR-DE-15), and a human-readable message. Inspect the issues array, map each finding back to the offending invoice field, and re-run generation or validation once corrected.

Supported ZUGFeRD profiles

ZUGFeRD (Factur-X) profiles are layers on top of the EN 16931 semantic model. All six profiles — MINIMUM, BASICWL, BASIC, EN16931 (COMFORT, the default), XRECHNUNG, and EXTENDED — are generated from the same canonical invoice data.

MINIMUM

Generatable

Factur-X MINIMUM — a below-EN16931 booking aid. The embedded XML carries only header-level data (seller, buyer, totals); line items are suppressed from the XML but still rendered on the visual PDF page.

BASICWL

Generatable

Factur-X BASIC WL (Without Lines) — same as MINIMUM but allows a buyer reference. Line items are suppressed from the embedded XML; the PDF still shows full line data.

BASIC

Generatable

Factur-X BASIC — a subset of EN 16931 with no data loss. Suitable when the recipient only needs the core invoice data.

EN16931 (COMFORT)

Generatable · default

Factur-X EN16931 / COMFORT — the default profile. Matches the EN 16931 semantic model exactly, so the generated PDF carries the full invoice fidelity the DTO provides.

XRECHNUNG

Generatable

Factur-X XRECHNUNG — EN 16931 plus the German CIUS rules. Use when the recipient expects a ZUGFeRD container that also satisfies the XRechnung conformance level.

EXTENDED

Generatable

Factur-X EXTENDED output is supported for the currently modeled invoice fields. The EXTENDED URN is stamped, but ZUGFeRD-specific BT-X extension fields (logistics service fees, line-level ship-to parties, sales agents, etc.) are not yet exposed by the InvoiceSpec input model.

Typical integration workflow

From structured invoice data to a compliant ZUGFeRD PDF/A-3 ready for your existing delivery workflow — the engine handles the PDF rendering, XML embedding, and rule checking.

  1. 1

    Send structured invoice data

    POST a canonical JSON invoice to /v1/invoice/zugferd. No PDF or XML hand-authoring — the engine maps your data to the EN 16931 model and selects the ZUGFeRD profile from your config (default EN16931 / COMFORT).

  2. 2

    Engine generates and validates

    InvoiceSpec maps your data to EN 16931, serializes it as CII D16B XML, renders a styled, human-readable invoice page to PDF/A-3, and embeds the CII XML as the ZUGFeRD AF attachment.

  3. 3

    Validate before you send

    POST an existing ZUGFeRD PDF to /v1/invoice/zugferd/validate. The validator extracts the embedded CII XML, checks PDF/A-3 conformance, and validates the XML against the ZUGFeRD profile rules.

  4. 4

    Handle the result

    A valid generation comes back as a PDF/A-3 binary; a failed validation returns 200 OK with a structured issue list you can act on programmatically.

Frequently asked questions

What is a ZUGFeRD invoice?

ZUGFeRD (Factur-X) is the German hybrid e-invoice format: a PDF/A-3 document that carries a human-readable invoice page and the machine-readable EN 16931 CII XML embedded as an attachment. One file serves both a person reading it and software consuming it — the structure required for German e-invoicing compliance.

Which ZUGFeRD profiles can I generate?

MINIMUM, BASICWL, BASIC, EN16931 (COMFORT, the default), XRECHNUNG, and EXTENDED. All six are generated from the same canonical EN 16931 invoice data. MINIMUM and BASICWL suppress line items from the embedded XML (the PDF still shows full line data); EXTENDED stamps the URN but does not model extension-only fields.

How are validation errors returned?

Validation failures are not HTTP errors. The endpoint returns 200 OK with valid: false and a structured issues array (severity, code, message), so you can surface and fix each finding programmatically. The validator checks PDF/A-3 conformance and the embedded CII XML against the ZUGFeRD profile rules.

What is the relationship between the PDF and the XML?

The PDF/A-3 container is the deliverable; the EN 16931 CII XML is embedded inside it as the ZUGFeRD/Factur-X Associated File (AF) attachment, with XMP metadata declaring the relationship. The XML is the authoritative machine-readable invoice; the visible PDF page is the human-readable view of the same data. The engine generates both from a single canonical invoice so they never diverge.

Is this only for German invoices?

InvoiceSpec currently focuses on German e-invoicing. ZUGFeRD is the German hybrid PDF format built on the European EN 16931 semantic model, which is also available as a first-class capability with its own endpoints. XRechnung, the German XML-only format, has its own dedicated landing page and endpoints. Additional countries and delivery networks would only be listed here once they are actually supported.

Start with 500 free trial invoices

Generate and validate ZUGFeRD invoices against the real API — no credit card required to get started.

  • PDF + XML in one file
  • 6 profiles
  • One POST

API key in seconds — first ZUGFeRD PDF in under a minute.