ZUGFeRD mit Python: Bibliotheken und Einstieg
Letzte Aktualisierung: 1. Mai 2026
python-drafthorse (von pretix, Low-Level-Kontrolle)
und factur-x (PyPI, höherwertig, einfachere API). Beide sind Open Source.
Welche Bibliothek für welchen Zweck?
| Bibliothek | Maintainer | Stärken | Einschränkungen |
|---|---|---|---|
python-drafthorse | pretix (rami.io) | Vollständige XML-Kontrolle, alle Profile, aktiv gepflegt | Kein eingebautes PDF-Embedding — du brauchst zusätzlich PyPDF2 o. ä. |
factur-x | Akretion (Frankreich) | Erzeugt vollständige PDF/A-3 mit eingebettetem XML, einfachere API | Benötigt eine bestehende PDF als Basis; hauptsächlich auf Factur-X fokussiert |
python-drafthorse: Installation und Konzept
pip install drafthorse python-drafthorse erzeugt das ZUGFeRD-XML als Python-Objekte —
du baust die Struktur Schritt für Schritt auf. Das gibt dir vollständige
Kontrolle über alle Felder, erfordert aber Verständnis der CII-Struktur
(siehe ZUGFeRD XML-Struktur).
from drafthorse.models.document import Document
from drafthorse.models.accounting import ApplicableTradeTax
from drafthorse.models.party import TradeParty
from drafthorse.models.payment import PaymentTerms
from decimal import Decimal
import datetime
# Dokument initialisieren
doc = Document()
doc.context.guideline_id.value = (
"urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:en16931"
)
doc.header.id.value = "RE-2025-001"
doc.header.type_code.value = "380" # 380 = Rechnung
doc.header.issue_date_time.value = datetime.date(2025, 3, 15)
# Aussteller
doc.trade.agreement.seller.name.value = "Muster GmbH"
doc.trade.agreement.seller.address.country_id.value = "DE"
doc.trade.agreement.seller.tax_registrations.add(
id="DE123456789", scheme_id="VA"
)
# Empfänger
doc.trade.agreement.buyer.name.value = "Kunde AG"
doc.trade.agreement.buyer.address.country_id.value = "DE"
# Währung
doc.trade.settlement.currency_code.value = "EUR"
# Gesamtbeträge
doc.trade.settlement.monetary_summation.line_total.amount = Decimal("500.00")
doc.trade.settlement.monetary_summation.tax_basis_total.amount = Decimal("500.00")
doc.trade.settlement.monetary_summation.tax_total.amount = Decimal("95.00")
doc.trade.settlement.monetary_summation.grand_total.amount = Decimal("595.00")
doc.trade.settlement.monetary_summation.due_payable.amount = Decimal("595.00")
# XML exportieren
xml_bytes = doc.serialize()
print(xml_bytes.decode("utf-8")) python-drafthorse
kann sich zwischen Versionen ändern. Prüfe immer die aktuelle Dokumentation
auf GitHub: github.com/pretix/python-drafthorse XML in eine PDF einbetten mit python-drafthorse
python-drafthorse erzeugt nur das XML. Um eine vollständige
ZUGFeRD-PDF zu erstellen, musst du das XML in eine bestehende PDF einbetten.
Das geht zum Beispiel mit pypdf oder pikepdf,
aber das korrekte Einbetten gemäß PDF/A-3-Standard ist anspruchsvoll.
Einfacher: python-drafthorse mit factur-x kombinieren
(letzteres übernimmt das Embedding).
factur-x: Installation und Konzept
pip install factur-x
Die factur-x-Bibliothek nimmt eine bestehende PDF (deine
Rechnungsvorlage, erzeugt z. B. mit ReportLab oder WeasyPrint) und bettet
das ZUGFeRD-XML darin ein — fertig ist die PDF/A-3-Datei.
from facturx import generate_facturx_from_file
# Ausgangsmaterial: eine normale PDF und eine XML-Datei
generate_facturx_from_file(
"rechnung_vorlage.pdf", # Deine visuelle Rechnung als PDF
"rechnung.xml", # Das ZUGFeRD-XML (z.B. von python-drafthorse erzeugt)
output_pdf_file="rechnung_zugferd.pdf",
facturx_level="en16931", # Profil: minimum, basicwl, basic, en16931, extended
) Typischer Workflow: Beide Bibliotheken kombinieren
- Rechnungs-PDF mit ReportLab, WeasyPrint oder einem Template erzeugen
- ZUGFeRD-XML mit
python-drafthorseerzeugen - Beides mit
factur-xzusammenführen → fertige ZUGFeRD-PDF - Validierung mit Mustangproject-CLI oder FeRD-Validator
Valide Testdaten erzeugen
Zum Testen deiner Implementierung eignen sich die offiziellen Mustangproject-Testdateien von mustangproject.org. Die Bibliothek selbst stellt auch Unit-Tests bereit, die zeigen, wie korrekte Dokumente aussehen.
Häufige Fehler
- Falsche Profil-URN: Die URN im
GuidelineSpecifiedDocumentContextParametermuss exakt zum tatsächlichen Inhalt passen. Profilmismatch führt zu Validierungsfehlern. - Dezimaltrennzeichen: Im XML immer Punkt (
595.00), nie Komma (595,00). Python'sDecimal-Typ gibt standardmäßig den Punkt aus. - Datumsformat: Immer
YYYYMMDD(format="102"), nicht ISO 8601. - Betragssummen inkonsistent:
GrandTotalAmountmuss exaktLineTotalAmount + TaxTotalAmountergeben. Rundungsfehler bei Float vermeiden — immerDecimalnutzen.
Häufige Fragen
Gibt es eine aktiv gepflegte Alternative zu diesen beiden Bibliotheken?
Stand 2026: python-drafthorse und factur-x sind
die bekanntesten. Es gibt vereinzelt weitere Projekte auf GitHub (z. B. horstoeko
für PHP), aber für Python sind diese beiden der Standard.
Kann ich ZUGFeRD-Dateien auch lesen (parsen), nicht nur erzeugen?
Ja — beide Bibliotheken können auch vorhandene XML-Daten aus PDFs extrahieren
und parsen. factur-x hat dafür eine einfache API:
get_facturx_xml_from_pdf().
Was ist der Unterschied zwischen ZUGFeRD 1.x und 2.x in Python?
ZUGFeRD 1.x nutzt ein anderes Root-Element (CrossIndustryDocument)
und eine ältere Schema-Version. Neue Implementierungen sollten immer ZUGFeRD 2.x
(alias Factur-X) nutzen. python-drafthorse unterstützt nur 2.x.
Weiterführend: X-Ray-Viewer — ZUGFeRD-XML direkt im Browser prüfen · ZUGFeRD XML-Struktur im Detail