Skip to content
CastPDF
ZUGFeRD and XRechnung guide

ZUGFeRD, Factur-X and XRechnung with CastPDF

Send the invoice as structured JSON in e_invoice on POST /v1/pdf, the request behind our e-invoicing API. For Factur-X and ZUGFeRD you get a PDF/A-3 file with the invoice XML embedded. For XRechnung you get the XML itself. The totals follow the EN 16931 rules, so the PDF and the XML always agree.

  • Updated
  • 4 minute read
  • 100 free PDFs a month

Which format do you need?

An e-invoice carries the invoice as machine-readable data. The receiver can book it without typing anything. Three formats matter in Germany and France, and they share one data model, EN 16931.

The formats and what the API returns
FormatUse it forWhat you get
Factur-X (France) and ZUGFeRD (Germany)Business customers who want a readable PDF and the dataA PDF/A-3 file with factur-x.xml inside
XRechnung, CII or UBL syntaxGerman public buyers and their portalsThe XML file only
ZUGFeRD with the XRechnung profileA readable copy of an XRechnungA PDF/A-3 file with xrechnung.xml inside

Factur-X and ZUGFeRD are the same standard under two names. Profiles set how much data the XML carries. Use en16931 unless your customer asks for another one. It is the default.

Send the invoice

Put the invoice in e_invoice.invoice. You do not need a template: the built-in invoice template renders it. You can still pass your own template_id. It then receives the same data, with every amount already computed.

A Factur-X invoice with curl
curl https://api.castpdf.com/v1/pdf \
  -H "Authorization: Bearer $CASTPDF_KEY" \
  -H "Content-Type: application/json" \
  -o RE-2026-0815.pdf \
  -d '{
    "e_invoice": {
      "standard": "factur-x",
      "profile": "en16931",
      "invoice": {
        "number": "RE-2026-0815",
        "issue_date": "2026-10-10",
        "currency": "EUR",
        "seller": {
          "name": "Lindqvist Software GmbH",
          "vat_id": "DE123456789",
          "address": { "line1": "Kastanienallee 12", "city": "Berlin", "postal_code": "10435", "country_code": "DE" }
        },
        "buyer": {
          "name": "Brightwater Kaffee GmbH",
          "address": { "city": "Hamburg", "postal_code": "20457", "country_code": "DE" }
        },
        "payment": { "iban": "DE89370400440532013000", "due_date": "2026-11-09" },
        "lines": [
          { "name": "Software licence", "quantity": 1, "unit_price": "4800.00", "vat": { "category": "S", "rate": 19 } },
          { "name": "Printed handbook", "quantity": 3, "unit_price": "24.90", "vat": { "category": "S", "rate": 7 } }
        ]
      }
    }
  }'

Send amounts as strings like "24.90" if you want to avoid any doubt about decimals. Numbers work too. Unit codes follow UN/ECE Recommendation 20, for example C62 for a piece and HUR for an hour.

How the totals are computed

  1. Each line is quantity times net price, rounded to cents. Line discounts and charges come off or on after that.
  2. Document discounts and charges apply to the sum of the lines.
  3. VAT is computed once per category and rate on the taxable amount, then rounded to cents.
  4. The amount due is the total minus any prepaid amount, plus any rounding amount.

Many systems round VAT per line. That can differ by a cent from the EN 16931 result. If you send your own totals in invoice.totals, we compare each one. A difference is a 400 error that names the field, our value and the reason.

XRechnung for public buyers

Use xrechnung-cii or xrechnung-ubl. Ask the buyer which syntax their portal takes. The response is the XML file, not a PDF. XRechnung needs more data than a normal invoice:

  • buyer_reference: the Leitweg-ID the public buyer gave you.
  • A seller contact with name, phone and email.
  • Electronic addresses for seller and buyer. For a public buyer this is usually the Leitweg-ID with scheme 0204.
  • Payment details, for example an IBAN for a bank transfer.

If something is missing, the API answers with 400 invalid_e_invoice and lists every problem with its path. Fix the fields and send the request again. Nothing is counted for a rejected request.

Credit notes, reverse charge and exempt sales

Most invoices use the standard VAT category S with a rate. A few common cases need one more field.

Special cases and the fields they need
CaseWhat to send
Credit notetype_code: "381" and preceding_invoice with the number of the original invoice
Reverse charge in the EUVAT category AE on the lines and the buyer's vat_id
Goods to another EU countryCategory K, the buyer's vat_id, a delivery date and the delivery country
Exempt serviceCategory E and a reason in tax_exemptions.E
Export outside the EUCategory G

For reverse charge, intra-EU supplies and exports we add the standard exemption text and code for you. For exempt services you name the legal reason yourself, because it differs from case to case.

Reading the error response

A rejected invoice comes back with status 400 and the code invalid_e_invoice. The field details.issues holds one entry per problem. Each entry has a path and a message.

An error with two problems
{
  "error": {
    "code": "invalid_e_invoice",
    "message": "The e-invoice has 2 problems. The first: e_invoice.invoice.buyer_reference: is required for XRechnung: the buyer reference, which for German public buyers is the Leitweg-ID (for example 04011000-12345-67).",
    "details": {
      "issues": [
        { "path": "e_invoice.invoice.buyer_reference", "message": "is required for XRechnung: the buyer reference, which for German public buyers is the Leitweg-ID (for example 04011000-12345-67)." },
        { "path": "e_invoice.invoice.totals.tax_total", "message": "is 917.24, but it should be 917.23 (the VAT of each rate rounded to cents (19% of 4800.00 = 912.00; 7% of 74.70 = 5.23)). EN 16931 rounds each line to cents and the VAT once per rate, not per line." }
      ]
    }
  }
}

Show the messages to the person who keeps the invoice data, or map the paths back to your own form fields. Each message says what is wrong and what a valid value looks like.

What we check, and what you should check

Before anything is rendered we validate the invoice and compute the totals. Our tests run the generated XML through the official XSD schemas and Schematron rules: EN 16931, the Factur-X profiles and XRechnung. The PDF is converted to PDF/A-3b with the XML attached as an associated file.

We also ran the two reference tools by hand on 10 October 2026. The PDF/A checker veraPDF 1.30.3 found all 16 sample PDFs compliant with PDF/A-3b. The KoSIT validator 1.6.3 with the XRechnung 3.0.2 configuration accepted all 14 EN 16931 and XRechnung files. No authority has reviewed CastPDF itself, and your receiver may still have rules of its own.

Already have an e-invoice from another system? Our free e-invoice validator reads the XML, or the XML inside a PDF, and checks the fields and the EN 16931 totals. It says plainly what it does not check.

Test with your receiver

Send a test invoice to your customer or their portal before you go live. Test keys add a watermark, so use a live key for that final check.

Common questions

Does CastPDF send the e-invoice to my customer?

It can email a Factur-X or ZUGFeRD PDF with deliver.email. CastPDF does not send invoices over Peppol or to a French approved platform. You hand the file to the channel your customer or the law asks for.

Does an e-invoice cost more than a normal PDF?

No. One request counts as one document, for Factur-X, ZUGFeRD and XRechnung alike.

Can I use my own invoice design?

Yes. Pass template_id with e_invoice. Your template receives the invoice data with every amount computed, so the page shows the same numbers as the XML.

Which profile should I choose?

Use en16931 unless your customer asks for another profile. MINIMUM and BASIC WL carry no invoice lines and are not full invoices in Germany.

Can I get a PDF for an XRechnung?

Use standard zugferd with profile xrechnung. You get a PDF/A-3 with the XRechnung data inside. Public portals usually want the plain XML, so send them that.
All guides

Your first PDF in five minutes.

Pick a template, create a free test key and send one request. 100 PDFs a month are free, and you never need a card to start.