ZUGFeRD API for Developers

Generate and validate ZUGFeRD (Factur-X) invoices with one API. Each generated document is a PDF/A-3 with the EN 16931 CII XML embedded inside it — German e-invoicing infrastructure for developers.

50 free trial credits — no credit card required.

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:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType: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>

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://invoice-spec.onrender.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","version":"2.5","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://invoice-spec.onrender.com/v1/invoice/zugferd/validate \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "file=@invoice-zugferd.pdf" \
-F 'request={"version":"2.5"}'
Response — application/json
{
"valid": false,
"version": "2.5",
"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.

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. Generation supports BASIC, EN16931 (COMFORT, the default), and XRECHNUNG; EXTENDED is validate-only.

BASIC

Generatable

Factur-X BASIC — a subset of EN 16931 with no data loss. The lightest ZUGFeRD profile; 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

Validate-only

Factur-X EXTENDED — extends EN 16931 with additional business terms (logistics service fees, line-level ship-to parties, sales agents, etc.) that the invoice DTO does not model, so EXTENDED invoices cannot be generated. An existing EXTENDED PDF can still be validated — the validator reads the profile from the PDF's XMP metadata.

Typical integration workflow

From structured invoice data to a delivered, compliant ZUGFeRD PDF/A-3 — 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 in one pass.

  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?

BASIC, EN16931 (COMFORT, the default), and XRECHNUNG. All three are compatible with the EN 16931 semantic model the API's invoice payload carries. EXTENDED is validate-only — the invoice payload does not model the extended-only business terms, so EXTENDED invoices cannot be generated, but an existing EXTENDED PDF can be validated.

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 in one pass.

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 is German e-invoicing infrastructure for developers. 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.

Start with 50 free trial credits

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