Generate and send a ZUGFeRD PDF

Your customer wants a PDF invoice that is machine-readable at the same time.

Steps

  1. 1

    Build the invoice data as for XRechnung and add bank details and the payment term — ZUGFeRD carries them in the embedded XML.

  2. 2

    The response is base64-encoded; decode it and save as .pdf or attach it directly.

  3. 3

    Send by email. The recipient sees a normal PDF; their system reads the embedded XML.

The call

POST /api/v1/invoice/DE/zugferd/generate

bash
1curl -X POST https://api.invoice-api.xhub.io/api/v1/invoice/DE/zugferd/generate \
2 -H "X-API-Key: $INVOICE_API_KEY" \
3 -H "Content-Type: application/json" \
4 -d '{
5 "invoice": {
6 "invoiceNumber": "RE-2025-002",
7 "type": "invoice",
8 "issueDate": "2025-01-15",
9 "dueDate": "2025-02-15",
10 "currency": "EUR",
11 "seller": {
12 "name": "Muster GmbH",
13 "vatId": "DE811128135",
14 "street": "Musterstraße 1",
15 "postalCode": "10115",
16 "city": "Berlin",
17 "countryCode": "DE",
18 "email": "info@muster.de",
19 "phone": "+49 30 12345678",
20 "bankAccount": {
21 "iban": "DE89370400440532013000",
22 "bic": "COBADEFFXXX"
23 }
24 },
25 "buyer": {
26 "name": "Beispiel AG",
27 "vatId": "DE136695976",
28 "street": "Beispielweg 42",
29 "postalCode": "80331",
30 "city": "München",
31 "countryCode": "DE"
32 },
33 "items": [
34 {
35 "position": 1,
36 "description": "Beratungsleistung",
37 "quantity": 10,
38 "unit": "HUR",
39 "unitPrice": 150,
40 "taxRate": 19,
41 "netAmount": 1500,
42 "taxAmount": 285,
43 "grossAmount": 1785
44 }
45 ],
46 "taxSummary": [
47 {
48 "taxRate": 19,
49 "netAmount": 1500,
50 "taxAmount": 285
51 }
52 ],
53 "subtotal": 1500,
54 "total": 1785,
55 "paymentTerms": {
56 "dueDays": 30,
57 "description": "Zahlbar innerhalb von 30 Tagen"
58 }
59 }
60}'

Where this goes wrong

Two traps: ZUGFeRD is not a PDF with an attachment but a PDF/A-3 with conformant embedded XML — XML bolted on afterwards is not found by recipient systems. And unlike XRechnung, IBAN, BIC and the payment term are mandatory; without them generation fails.