What an e-invoice is
An e-invoice carries the invoice as structured data that software can book. A plain PDF is a picture of an invoice; an e-invoice is the invoice itself.
For years an emailed PDF was a perfectly good invoice. The buyer read it, typed the numbers into their accounting system and paid. EU law now calls that a paper-like format. An electronic invoice in the legal sense is a file in a structured format that follows the European standard EN 16931.
There are two ways to deliver that structure. The first is the XML on its own, which is what XRechnung is. The second is a hybrid: a normal PDF that people read, with the same invoice attached inside it as XML. ZUGFeRD in Germany and Factur-X in France are the hybrid formats, and since ZUGFeRD 2.1 they are technically the same file.
- Your billingan invoice is final
- e_invoice JSONparties, lines, VAT
- CastPDFchecks and computes
- PDF/A-3 + XMLor the XRechnung XML
- Your customerbooks it without typing
In a hybrid invoice the XML is the part that counts legally. The German tax authority says so explicitly. That is why the numbers on the page and in the XML must never differ, and why CastPDF builds both from one calculation.
ZUGFeRD, XRechnung or Factur-X?
Selling to German businesses: ZUGFeRD. Selling to German public buyers: XRechnung. Selling in France: Factur-X. All three come from the same request.
| ZUGFeRD | XRechnung | Factur-X | |
|---|---|---|---|
| Where it is used | Germany, business to business | Germany, public buyers (and many businesses) | France, and German readers of ZUGFeRD |
| What the file is | PDF/A-3 with factur-x.xml inside | XML only (CII or UBL syntax) | PDF/A-3 with factur-x.xml inside |
| People can read it | Yes, it is a PDF | Only with a viewer, or a readable copy | Yes, it is a PDF |
| Extra data required | None beyond EN 16931 | Leitweg-ID, seller contact, electronic addresses | None beyond EN 16931 |
The standard to send | zugferd | xrechnung-cii or xrechnung-ubl | factur-x |
The usual question is ZUGFeRD vs XRechnung. Public authorities in Germany expect XRechnung, usually through a portal, and tell you whether they take CII or UBL. Businesses mostly prefer ZUGFeRD, because their staff can still open and read the PDF. Both count as e-invoices under the German rules. Our ZUGFeRD page and XRechnung page go deeper into each one.
Profiles: how much data the XML carries
| Profile | Invoice lines | A full e-invoice in Germany | The `profile` to send |
|---|---|---|---|
| MINIMUM | No, header and totals only | No | minimum |
| BASIC WL | No, header and totals only | No | basic-wl |
| BASIC | Yes | Yes | basic |
| EN 16931 (once called COMFORT) | Yes, the full European standard | Yes | en16931 (the default) |
| EXTENDED | Yes, with extra fields | Yes | extended |
| XRECHNUNG (ZUGFeRD only) | Yes, with the XRechnung rules | Yes | xrechnung |
Use en16931 unless your customer asks for something else. It carries the whole invoice, and it is what most receiving software expects. The two smallest profiles carry no lines, so the German rules do not accept them as invoices.
The German e-invoicing mandate, 2025 to 2028
Every German business must already be able to receive e-invoices. Sending them becomes mandatory in two steps: 2027 for larger businesses, 2028 for everyone.
- 1 January 2025In forceEveryone must receiveEvery business in Germany must be able to receive and process e-invoices from other businesses.
- Until 31 December 2026NowTransition for sendersYou may still send paper, or with the buyer’s consent a plain PDF or another electronic format.
- 1 January 2027ComingLarger businesses must sendBusinesses with more than EUR 800,000 turnover in the previous year must issue e-invoices.
- 1 January 2028ComingEveryone must sendThe transition ends for all businesses. Domestic B2B invoices must be e-invoices.
The rules come from the Growth Opportunities Act (Wachstumschancengesetz) and the Federal Ministry of Finance letters that explain it. Invoices to consumers are out of scope, and so are small invoices up to EUR 250 and travel tickets. The ministry’s FAQ has the details in German.
- XRechnung counts as an e-invoice.
- ZUGFeRD from version 2.0.1 counts, except the MINIMUM and BASIC WL profiles.
- A plain PDF is no longer an e-invoice, even if you send it by email.
- In a hybrid ZUGFeRD file, the XML wins if it differs from the page.
Public buyers are a separate, older story. Suppliers to the federal administration have had to send e-invoices since November 2020, and XRechnung is the format those buyers expect. Several federal states have similar rules. Each public buyer gives you a Leitweg-ID, which goes into the invoice as the buyer reference.
E-invoicing in France: Factur-X and the 2026 reform
France is moving every domestic B2B invoice onto approved platforms. Factur-X is one of the formats those platforms accept, and CastPDF creates it.
France chose a different model from Germany. Invoices between French businesses will travel through approved platforms (plateformes agréées), which also report the data to the tax administration. The French finance laws set two dates, and the first one has already passed.
| From | Receiving e-invoices | Sending e-invoices |
|---|---|---|
| 1 September 2026 | Every business | Large and mid-sized businesses |
| 1 September 2027 | Every business | Small and micro businesses too |
The platforms accept three base formats: Factur-X, CII and UBL. Factur-X is the popular one, because it stays a readable PDF. CastPDF makes the Factur-X file; your approved platform carries it to the buyer and reports it. CastPDF is not a platform and does not transmit invoices. Ask your platform which Factur-X profile it wants, and check the current dates with it, because French deadlines have moved before.
Our Factur-X page shows a French invoice request and the fields French invoices need.
One request, from JSON to e-invoice
Put the invoice in e_invoice on the normal POST /v1/pdf request. You need no template: the built-in invoice template renders the page. Change standard to switch formats; the invoice stays the same.
{
"e_invoice": {
"standard": "zugferd",
"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 } }
]
}
}
}curl https://api.castpdf.com/v1/pdf \
-H "Authorization: Bearer $CASTPDF_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: invoice-RE-2026-0815" \
-d @RE-2026-0815.json \
-o RE-2026-0815.pdfimport { readFile, writeFile } from 'node:fs/promises';
const body = await readFile('RE-2026-0815.json', 'utf8');
const res = await fetch('https://api.castpdf.com/v1/pdf', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CASTPDF_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'invoice-RE-2026-0815',
},
body,
});
if (!res.ok) {
const { error } = await res.json();
// invalid_e_invoice lists every problem in error.details.issues
throw new Error(`${error.code}: ${error.message}`);
}
await writeFile('RE-2026-0815.pdf', Buffer.from(await res.arrayBuffer()));import json
import os
import requests
with open("RE-2026-0815.json", encoding="utf-8") as f:
body = json.load(f)
res = requests.post(
"https://api.castpdf.com/v1/pdf",
headers={
"Authorization": f"Bearer {os.environ['CASTPDF_API_KEY']}",
"Idempotency-Key": "invoice-RE-2026-0815",
},
json=body,
timeout=60,
)
if not res.ok:
error = res.json()["error"]
raise RuntimeError(f"{error['code']}: {error['message']}")
with open("RE-2026-0815.pdf", "wb") as f:
f.write(res.content)HTTP/1.1 200 OK
content-type: application/pdf
content-disposition: attachment; filename="RE-2026-0815.pdf"
x-e-invoice: zugferd/en16931
x-pages: 1Change standard to xrechnung-ubl and the same request returns the XRechnung XML instead, once the invoice has the extra XRechnung fields. The API reference lists every field, and the ZUGFeRD and XRechnung guide covers credit notes, reverse charge and exempt sales.
Totals computed once, printed twice
The most common reason an e-invoice is rejected is a total that is a cent off. We compute every total ourselves, with the rules the validators use.
- Each line is quantity times net price, rounded to cents, then line discounts and charges.
- VAT is computed once per category and rate, not per line, and rounded half away from zero.
- Exact decimals throughout: no floating point, so 0.1 plus 0.2 is 0.30.
- Send your own
totalsif you like; any field that differs is reported with our value. - Reverse charge, intra-EU supplies and exports get the standard exemption text and code.
Many billing systems round VAT on every line. EN 16931 rounds it once per rate, which can differ by a cent. If you send your totals, the API tells you exactly which one is off and why, before anything is rendered or counted.
What we validated, and how
Every claim here names the tool, the version and the result. No authority has reviewed CastPDF, and we do not claim one has.
| Check | Tool | Result |
|---|---|---|
| XML structure, every profile | The official XSD schemas, in our test suite | Every generated XML passes |
| Business rules | Official Schematron: CEN EN 16931 1.3.16, Factur-X 1.09, KoSIT XRechnung 3.0.2 | No failed rule in our test suite |
| PDF/A-3b | veraPDF 1.30.3, run on 10 October 2026 | 16 of 16 sample PDFs compliant, 0 failed checks |
| XRechnung and EN 16931 | KoSIT validator 1.6.3 with the XRechnung 3.0.2 configuration | All 14 files accepted, 0 failed assertions |
The samples cover six invoice shapes: two VAT rates with discounts and charges, reverse charge, an exempt sale, a credit note, an intra-EU supply and a 40-line rounding test. They also cover logos, test watermarks and right-to-left and Chinese text in the PDF.
The KoSIT configuration has no scenario for the Factur-X MINIMUM, BASIC and EXTENDED profiles; the Factur-X Schematron in our tests covers those. veraPDF checks PDF/A, not the match between the PDF metadata and the XML. Your receiver may have its own extra rules, so send them a test invoice first.
Check or create an e-invoice for free
Two free tools use the same engine as the API, without an account. The e-invoice validator reads an XRechnung XML or a ZUGFeRD or Factur-X PDF and checks the fields and the totals. The e-invoice generator turns a short form into a ZUGFeRD PDF or an XRechnung XML.
Both are rate limited and stamp a small CastPDF footer on generated PDFs. When you need e-invoices from your own system, the API does the same work without the footer on paid plans.
What an e-invoice costs
An e-invoice counts on your plan exactly like any other PDF. The Free plan includes 100 documents a month, and paid plans start at $19 a month for 2,500. Test keys make unlimited watermarked e-invoices while you build, and a request that fails validation is never counted. See pricing for every plan.
Common questions
Is a ZUGFeRD PDF a valid e-invoice in Germany?
Do I need XRechnung or ZUGFeRD?
Does CastPDF send e-invoices over Peppol or a French platform?
Who checked that CastPDF e-invoices are correct?
Can an e-invoice use my own layout?
What happens if my invoice data is incomplete?
Does an e-invoice cost extra?
Everything on the E-invoicing API
Every guide, template and example that builds on this page. Each one answers a narrower question in more depth.