ZUGFeRD / XRechnung
MCP Validation Server
MCP-Server zur automatisierten Validierung von E-Rechnungen in den Formaten ZUGFeRD, Factur-X und XRechnung. Gibt strukturierte JSON-Ergebnisse mit konkreten Korrekturvorschlägen zurück.
1. Übersicht
Der Server stellt drei Tools und eine Resource bereit, die von KI-Agenten über das Model Context Protocol aufgerufen werden können.
| Szenario | Tool / Resource |
|---|---|
| Rechnung vor dem Versand prüfen | validate_invoice |
| XML-Daten aus ZUGFeRD-PDF lesen | extract_xml |
| Prüfen ob PDF und XML übereinstimmen | check_consistency |
| Verfügbare Formate und Regelsets abfragen | validation://rules |
2. Architektur & Datenfluss
Ablauf für validate_invoice
3. Validierungsengines
Jede Anfrage wird von zwei Engines gleichzeitig geprüft. Die Ergebnisse werden konsolidiert und dedupliziert zurückgegeben.
| Engine | Version | Abgedeckte Formate |
|---|---|---|
| Mustang Project | v2.26.0 | ZUGFeRD 1.0–2.4, Factur-X 1.0, XRechnung (allgemein) |
| KoSIT Validierungstool | v1.6.3 | XRechnung 3.0.2 (CII + UBL), EN 16931 CII/UBL (plain), Factur-X 1.07.3 / 1.08 (alle Profile) |
errors-Liste. Duplikate (gleiche Regel-ID + Meldung) werden automatisch entfernt. KoSIT-Fehler fließen nur ein, wenn ein passendes Validierungsszenario erkannt wurde — bei unbekannten GuidelineIDs übernimmt Mustang allein.
4. Installation & Konfiguration
# Kostenlos registrieren:
https://zugferd-validator.de/portal
npm install -g zugferd-mcp-client
// mcp_config.json (je nach Client abweichender Pfad) { "mcpServers": { "zugferd": { "command": "zugferd-mcp-client", "env": { "ZUGFERD_API_KEY": "zv_dein_key_hier" } } } }
Direkte REST API
Die API kann auch direkt ohne MCP-Client angesprochen werden:
# Beispiel: Validierung per curl curl -X POST https://api.zugferd-validator.de/v1/validate \ -H "Content-Type: application/json" \ -H "X-Api-Key: zv_dein_key_hier" \ -d '{"file_content":"<base64>","file_type":"xml"}'
Umgebungsvariablen (MCP-Client)
| Variable | Beschreibung | Standard |
|---|---|---|
ZUGFERD_API_KEY | API-Key vom Portal | – (Pflicht) |
ZUGFERD_API_URL | API-Basis-URL | https://api.zugferd-validator.de |
5. Tools
Validiert eine E-Rechnung (ZUGFeRD/Factur-X PDF oder XRechnung XML) gegen EN 16931 und die deutschen Erweiterungen. Gibt strukturierte Fehler, Warnungen und Korrekturvorschläge zurück.
Input-Schema
data:application/pdf;base64,…) werden automatisch entfernt.
"pdf" für ZUGFeRD/Factur-X-PDFs · "xml" für reine XRechnung/CII-XML-Dateien
rule_id: "PROFILE_MISMATCH" erzeugt.Werte:
minimum · basic_wl · basic · en16931 · extended · xrechnung
Output-Schema
{
"valid": true,
"format": "ZUGFeRD 2.x",
"profile": "EN16931",
"container": "pdf",
"syntax": "CII",
"summary": "Keine Probleme gefunden",
"errors": [],
"warnings": [],
"notices": [],
"metadata": {
"invoice_number": "RE-2026-001",
"issue_date": "2026-04-01",
"seller": "Musterfirma GmbH",
"buyer": "Beispiel AG",
"total_amount": "1190.00",
"currency": "EUR"
}
}
{
"valid": false,
"format": "XRechnung 3.0",
"profile": "XRECHNUNG",
"summary": "1 Fehler, 1 Warnung gefunden",
"errors": [
{
"severity": "error",
"rule_id": "BR-DE-15",
"field": "BT-10",
"message": "Die Käuferreferenz / Leitweg-ID (BT-10) muss übermittelt werden.",
"fix_suggestion": "Füge die Käuferreferenz / Leitweg-ID (BT-10) in 'ram:ApplicableHeaderTradeAgreement/ram:BuyerReference' ein.",
"xpath": "//ram:ApplicableHeaderTradeAgreement/ram:BuyerReference"
}
],
"warnings": [
{
"severity": "warning",
"rule_id": "BR-DE-17",
"field": "BT-3",
"message": "Mit dem Element \"Invoice type code\" (BT-3) sollen ausschließlich folgende Codes aus der Codeliste UNTDID 1001 übermittelt werden: 326, 380, 384, 389 …",
"fix_suggestion": "Bei einer Vorschussrechnung (386) ist die Warnung hinnehmbar: XRechnung empfiehlt den Code nicht, lässt ihn aber zu. Wer sie vermeiden will, nimmt 326 (Teilrechnung).",
"xpath": "//rsm:ExchangedDocument/ram:TypeCode"
}
]
}
Ausgabefelder
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
valid | boolean | Ja | true wenn kein einziger Fehler gefunden wurde |
not_an_einvoice | boolean | Nein | true, wenn die Datei gar keine erkannte E-Rechnung ist, etwa eine PDF ohne eingebettetes XML. Dann ist valid false, und der einzige Fehler heißt NO_EMBEDDED_XML oder NOT_AN_EINVOICE |
format | string | Nein | Erkanntes Format: "ZUGFeRD 2.x" oder "ZUGFeRD 1.0" bei PDF, sonst etwa "XRechnung 3.0", "Peppol BIS Billing 3.0" oder "EN 16931"; fehlt, wenn die Datei keine erkannte E-Rechnung ist |
profile | string | Nein | Erkanntes Profil in Großbuchstaben, etwa "EN16931", "EXTENDED" oder "XRECHNUNG"; fehlt, wenn die Datei keine erkannte E-Rechnung ist |
container | string | Nein | pdf (PDF mit eingebetteter E-Rechnung) oder xml (reine XML-Datei) |
syntax | string | Nein | CII oder UBL |
summary | string | Ja | Lesbare Zusammenfassung, z.B. "2 Fehler, 1 Warnung gefunden" |
errors | array | Ja | Validierungsfehler — machen die Rechnung ungültig |
warnings | array | Ja | Warnungen — Rechnung kann trotzdem gültig sein |
notices | array | Nein | Informative Hinweise ohne Einfluss auf die Gültigkeit |
metadata | object | Nein | Extrahierte Rechnungsdaten — bei PDFs vorhanden wenn eingebettetes XML erfolgreich gelesen wurde, bei file_type: "xml" immer |
Extrahiert das eingebettete XML-Dokument aus einer ZUGFeRD/Factur-X-PDF. Gibt den vollständigen XML-Inhalt als String zurück, zusammen mit erkanntem Format und Profil.
Input
Output
{
"xml_content": "<?xml version='1.0' encoding='UTF-8'?>\n<rsm:CrossIndustryInvoice ...>...</rsm:CrossIndustryInvoice>",
"format": "ZUGFeRD 2.x",
"profile": "EN16931"
}
xml_content kann direkt (nach Base64-Kodierung) an validate_invoice mit file_type: "xml" weitergegeben werden.Prüft, ob die für Menschen sichtbaren Daten im PDF (Rechnungsnummer, Datum, Gesamtbetrag) mit den im XML-Anhang gespeicherten Maschinendaten übereinstimmen. Deckt Manipulationen oder Erfassungsfehler auf.
Input
Output
{
"consistent": true,
"discrepancies": []
}
{
"consistent": false,
"discrepancies": [
{
"field": "total_amount",
"pdf_value": "1190.00",
"xml_value": "1180.00",
"message": "Gesamtbetrag im PDF ('1190.00') unterscheidet sich von dem im XML ('1180.00')."
}
]
}
Geprüfte Felder & Toleranzen
| Feld | Erkennungsmuster im PDF | Toleranz |
|---|---|---|
invoice_number | Rechnungsnummer:, Rechnung Nr., Invoice No. | Groß-/Kleinschreibung, Leerzeichen, Bindestriche ignoriert |
issue_date | Rechnungsdatum:, Datum:, Invoice Date: | Keiner — Datumformate werden auf ISO 8601 normiert |
total_amount | Gesamtbetrag:, Rechnungsbetrag:, Total: | ±0,01 EUR (Rundungsdifferenzen) |
Erzeugt aus strukturierten Daten eine gültige E-Rechnung, wahlweise als ZUGFeRD-PDF (PDF/A-3 mit eingebettetem EN-16931-CII-XML) oder als reine XRechnung-XML (CII mit XRechnung-3.0-CIUS und Leitweg-ID für B2G). Unterstützt mehrere Positionen, die USt-Kategorien S, Z, E, AE, K und G, durchlaufende Posten, Rabatte und Zuschläge, Leistungsdatum oder Leistungszeitraum, schon gezahlte Beträge, Bezüge auf frühere Rechnungen, Anlagen sowie Überweisung oder SEPA-Lastschrift. Zustandslos: Wir speichern nichts, auch keine Anlagen. REST: POST /v1/create. Beträge in Cent, Datum als YYYY-MM-DD.
Input (Auszug)
zugferd (PDF) oder xrechnung (XML)invoice: credit_note (Rechnungskorrektur, Storno; Beträge positiv, die PDF nennt dann keinen Zahlbetrag), corrected (korrigierte Rechnung), self_billed (Gutschriftverfahren), prepayment (Vorschuss- oder Anzahlungsrechnung; XRechnung warnt bei 386 mit BR-DE-17, die Rechnung bleibt gültig), partial (Teilrechnung), debit_note (Belastungsanzeige). Roh über type_code.[{ number, date }], höchstens 20. Ins XML kommt in beiden Formaten nur der erste als BG-3, denn das Schema der EN 16931 erlaubt nur einen; alle weiteren nennt der Hinweis (BT-22).{ number, date } (BT-25/26), etwa bei einer Rechnungskorrektur. Nicht zusammen mit preceding_invoices.seller, setzen wir das Absenderprofil deines Kontos ein.vat_category: Standard S; Z = 0 %, E = befreit, AE = Reverse Charge, K = innergemeinschaftliche Lieferung, G = Ausfuhr.vat_rate: 0, vat_category lässt du weg oder setzt E. Geht nicht zusammen mit anderen Positionen der Kategorie E (BR-E-01). Im XML zählt der Posten zum Netto (BT-109), aber nicht zur Umsatzsteuer; so verlangt es EN 16931. Zeigt deine eigene Rechnung die Summe netto ohne ihn, weichen die beiden Zahlen ab; der Gesamtbetrag stimmt.{ start, end }, das Ende nicht vor dem Anfang. Mit Zeitraum und ohne Leistungsdatum setzen wir BT-72 auf das Ende des Zeitraums. Bei einer Vorschussrechnung (prepayment) ohne beides lassen wir BT-72 weg; die ZUGFeRD-Prüfung warnt dann (PEPPOL-EN16931-R008), das ist richtig. Sonst gilt ohne beides das Rechnungsdatum.prepaid_vat_cents nennt er auch Entgelt und Steuer des Abzugs, wie § 14 Abs. 5 Satz 2 UStG es für Schlussrechnungen verlangt.xrechnung Pflichtmandate_reference (BT-89), creditor_id (BT-90, sonst aus dem Absenderprofil), debtor_iban (BT-91). Setzt die Zahlungsart 59. Bei ZUGFeRD darf die IBAN gekürzt sein (DE89**************3000), bei XRechnung nicht. Ein Empfängerkonto schreiben wir dann nicht (BR-DE-25-b). Schickst du direct_debit, brauchen wir alle drei Angaben; payment_means.type_code lässt du dann weg oder setzt 59.[{ filename, content_base64, description? }]. Erlaubt sind PDF, PNG, JPEG, CSV, XLSX und ODS (BR-CL-24), höchstens 10 Dateien, zusammen höchstens 5 MB. Dateinamen müssen eindeutig sein. Ab zwei Anlagen meldet die Prüfung die Warnung CII-SR-476 (bei zwei Beschreibungen auch CII-SR-475); die Regel zählt alle Anlagen zusammen, die Rechnung bleibt gültig. Über MCP enthält die Antwort einer ZUGFeRD-Rechnung mit Anlagen nur pdf_base64; das XML steckt in der PDF.false.Output
{
"format": "zugferd",
"profile": "EN16931",
"pdf_base64": "JVBERi0xLjc…",
"xml": "<?xml version=\"1.0\"…",
"branding": "free_footer"
}
xml kommt immer mit, außer über MCP bei einer ZUGFeRD-Rechnung mit Anlagen. Dann holt extract_xml es aus der PDF.
Anlagen
Anlagen stehen nur im XML der E-Rechnung (BT-125), nicht zusätzlich als Anhang der PDF. Jede Datei hat höchstens 5 MB, alle zusammen ebenfalls höchstens 5 MB, gemessen nach dem Dekodieren. Den Typ lesen wir an der Endung (.pdf, .png, .jpg, .jpeg, .csv, .xlsx, .ods) und prüfen ihn an den ersten Bytes der Datei; passen sie nicht zusammen, kommt 400. Ein Dateiname hat bis zu 100 Zeichen, ohne / und \ und ohne Punkt am Anfang; zwei Namen, die sich nur in Groß- und Kleinschreibung unterscheiden, gelten als gleich. description (BT-123) hat höchstens 200 Zeichen. In content_base64 steht reines Base64; einen Vorsatz data:…;base64, schneiden wir ab. Base64 macht die Dateien um ein Drittel größer: 5 MB Anlagen ergeben rund 7 MB im Aufruf, und die Antwort trägt sie noch einmal in der Rechnung. Über MCP schickst du deshalb besser nur kleine Anlagen.
Absenderprofil
Was im Aufruf fehlt, ergänzen wir aus dem Absenderprofil deines Kontos: den ganzen Verkäufer, wenn seller fehlt (die Steuernummer daraus nur, wenn das Profil keine USt-IdNr. hat), dazu IBAN, BIC, Kontoinhaber, Zahlungsbedingungen, Logo und bei einer Lastschrift die Gläubiger-ID. Was im Aufruf steht, gilt immer. Du pflegst das Profil im Konto unter „Absender“ oder über die API: GET /v1/keys/issuer liest es, PUT /v1/keys/issuer speichert es, DELETE /v1/keys/issuer löscht es. Felder: name, street, zip, city, country, vat_id, tax_number, email, phone, contact_name, iban, bic, account_name, payment_terms, logo_b64, creditor_id. PUT ändert nur die Felder, die im Aufruf stehen; eine leere Zeichenkette oder null löscht ein Feld. Eine USt-IdNr. ohne Ländercode, eine Steuernummer in falscher Form und eine ungültige Gläubiger-ID lehnt PUT mit 400 ab.
Fehler
Ungültige Eingaben beantworten wir mit 400 und { "error": "Ungültige Eingabe", "details": "…" }. Fehler im Schema nennen Pfad und Grund, mehrere durch Semikolon getrennt. Inhaltliche Probleme, etwa eine Lastschrift ohne Mandatsreferenz, stehen als ganze Sätze in details, mehrere durch Leerzeichen getrennt. Ein Datum, das nicht die Form YYYY-MM-DD hat, nennt sein Feld, etwa preceding_invoices[0].date (gezählt ab 0). Über MCP kommt bei inhaltlichen Problemen und beim Datum dasselbe Objekt als Ergebnis. Fehler im Schema meldet über MCP schon das Protokoll: Du bekommst einen Werkzeugfehler (isError: true) mit dem Text der Schemaprüfung, kein Objekt mit error und details.
validate_invoice auf das zurückgegebene pdf_base64 bzw. xml, oder du setzt self_check: true für einen einzigen Roundtrip. Branding (Footer im Prüfen-Tarif, White-Label ab Automatisieren) bestimmt der Server aus dem Tarif. Eigenes Kontingent fürs Erstellen: Prüfen 1 Rechnung im Monat; Automatisieren und Skalieren unbegrenzt, Fair Use über das Stundenlimit.zv_test_…, über GET /v1/keys/me): zum Testen der Rechnungserstellung. Erstellte Rechnungen tragen ein gekacheltes „DEMO"-Wasserzeichen auf jeder Seite plus XML-Marker — voll testbar, aber als echte Rechnung wertlos. 100/Tag, 3/Minute, getrennt vom Live-Kontingent. Prüfungen über den Sandbox-Key zählen dagegen auf dein normales Wochenkontingent: Sie rechnen dasselbe und liefern dasselbe Ergebnis.Macht aus einer bestehenden Rechnung als PDF, Word oder Excel eine E-Rechnung: ZUGFeRD in deinem bisherigen Layout oder XRechnung. Ein Sprachmodell auf unserem eigenen Server liest die Werte aus, wir rechnen sie nach und legen sie als Entwurf vor. Die E-Rechnung entsteht erst, wenn du den Entwurf bestätigst, und kommt nur zurück, wenn sie unsere Prüfung gegen EN 16931 besteht. In Automatisieren sind 20 Umwandlungen im Monat enthalten, in Skalieren 100, in Enterprise und im Testzugang so viele wie vereinbart. Darüber kostet jede weitere 3,99 € zzgl. USt mit accept_overage: true. Im Testzugang gibt es keine Mehrnutzung; ist das Kontingent aufgebraucht, antwortet /confirm mit 402 ohne overage_required. Ohne Tarif kostet jede 3,99 € zzgl. USt, bezahlt wird erst eine Datei, die die Prüfung bestanden hat. Ein vereinbartes Kontingent gilt auch im kostenlosen Tarif: Dann kommt die Datei sofort, wie mit Tarif. Ist es aufgebraucht, gibt es dort weder Mehrnutzung noch Einzelkauf: /confirm antwortet mit 402 ohne overage_required und ohne payment_required. Umwandlungen zählen nicht auf das Prüf- oder Erstellkontingent.
Ablauf
POST /v1/convertmit einer oder mehreren Dateien. Antwort sofort mit202und je Datei einem Auftrag im Statusqueued.GET /v1/convert/{id}abfragen, bis der Statusdraftist, meist nach ein bis drei Minuten je Rechnung; mehrere lesen wir nacheinander. Bei mehreren Dateien oder längerer Erkennung kommt zusätzlich eine E-Mail an die Adresse des Kontos.- Den Entwurf prüfen. Was in
uncertainsteht, sollte ein Mensch ansehen;reasonssagt je Feld, warum. POST /v1/convert/{id}/confirmmit den bestätigten Werten. Die Antwort kann länger dauern: Lass dein Programm bis zu drei Minuten warten. Mit Tarif kommt die fertige Datei als Base64 zurück, danach sind Upload und Entwurf gelöscht. Ohne Tarif erzeugen und prüfen wir sie ebenso, antworten aber mit402undpayment_required: true; der Auftrag steht dann aufawaiting_payment.- Nur ohne Tarif:
POST /v1/convert/{id}/checkoutgibt die Adresse der Zahlung zurück. Nach der Zahlung holtGET /v1/convert/{id}/filedie Datei.
Voraussetzungen
403 abgelehnt. Ohne Umwandlungen im Monat, etwa im kostenlosen Tarif ohne vereinbartes Kontingent, höchstens 5 Entwürfe am Tag.guest_token; es geht danach als Header X-Guest-Token mit. Je Internetanschluss eine offene Rechnung zur Zeit (sonst 429 mit guest_limit), höchstens drei am Tag ohne Kauf (sonst 429 mit guest_daily_limit). replace: "{id}" im Upload ersetzt die eigene offene Rechnung. Für die Anbindung an eigene Software ist ein kostenloser Schlüssel der bessere Weg.seller_from_invoice: true, und seller enthält den Absender zum Prüfen: vorbelegt aus der Rechnungsanschrift deines Kontos, sonst aus der Rechnung gelesen. Bei der Bestätigung schickst du ihn als seller mit (name, street, postal_code, city, dazu vat_id oder tax_number). Pflicht ist das nur, wenn im Konto weder ein vollständiges Absenderprofil noch eine vollständige Rechnungsanschrift steht. Für XRechnung braucht der Absender dazu Ansprechpartner, Telefon und E-Mail, bei Überweisung auch die IBAN: im Absenderprofil, wenn er von dort kommt, sonst im seller (contact, phone, email, iban). Bei einer Lastschrift (direct_debit) entfällt die IBAN. Kommt der Absender aus deinem seller, gehört own_invoice: true dazu: Damit bestätigst du, dass das deine Firma ist. Kommt er aus dem Absenderprofil oder der Rechnungsanschrift, brauchst du own_invoice: true nur, wenn er nicht auf der Rechnung steht.Hochladen: POST /v1/convert
[{ name, content }], content als Base64. Erlaubt sind PDF, DOCX, XLSX, ODT, ODS, DOC und XLS. Gescannte Rechnungen werden mit Status rejected abgelehnt. Alle Dateien einer Anfrage zusammen dürfen rund 35 MB groß sein: Base64 macht sie um ein Drittel größer, und eine Anfrage darf als JSON höchstens 50 MB haben, sonst kommt 413. Mehr Dateien verteilst du auf mehrere Aufrufe.{
"batch": "lomvuvzjtl5y94syeglx",
"jobs": [
{ "id": "5113py49uqxfatik47rn", "filename": "RE-2026-121.pdf", "format": "pdf",
"status": "queued", "reason": null,
"created_at": "2026-10-12T11:17:58.000Z", "expires_at": "2026-10-13T11:17:58.000Z" }
],
"note": "Sobald ein Entwurf zur Prüfung bereitliegt, hat er den Status „draft“. …"
}
Status eines Auftrags: queued, processing, draft, awaiting_payment (erzeugt und geprüft, wartet auf die Zahlung; dazu payment: { price_cents, paid }), done, rejected (Datei nicht umwandelbar, Grund in reason), failed. batch ist bei einer einzelnen Datei null.
Aufträge und Kontingent: GET /v1/convert
{
"jobs": [ … ],
"quota": { "limit": 20, "used": 11, "overage_cents": 399, "overage_possible": true,
"trial_until": null, "individual": false },
"blocked_reason": null,
"batch_limit": 20,
"pays_per_conversion": false,
"price_cents": 399,
"seller": { "source": "billing_details", "name": "Holzbau Weber GmbH", "street": "Lindenweg 3",
"postal_code": "72070", "city": "Tübingen", "country": "DE", "vat_id": "DE123456789",
"tax_number": null, "profile_incomplete": false }
}
Gezählt wird je Kalendermonat, in einem Firmenkonto über die Firma. overage_possible sagt, ob du über das Kontingent hinaus mit accept_overage weiter umwandeln kannst; im Testzugang nie. trial_until ist der letzte Tag eines Testzugangs (YYYY-MM-DD), sonst null. individual ist true, wenn ein vereinbartes Kontingent statt dem des Tarifs gilt. batch_limit sagt, wie viele Dateien ein Aufruf tragen darf. pays_per_conversion ist true, wenn dein Konto keine Umwandlungen im Monat hat, weder im Tarif noch vereinbart; dann kostet jede price_cents. blocked_reason ist bei Sandbox-Keys gesetzt. seller sagt, welcher Absender gilt, bevor es einen Entwurf gibt: Mit source profile ist es dein vollständiges Absenderprofil, und der Entwurf fragt nicht nach ihm. Mit billing_details ist es die Rechnungsanschrift deines Kontos, mit ihr ist der Absender im Entwurf vorbelegt. Mit invoice lesen wir ihn aus der Rechnung, die Anschrift ist dann leer. tax_number ist die Steuernummer aus dem Absenderprofil; die Rechnungsanschrift kennt keine. profile_incomplete ist true, wenn es ein Absenderprofil gibt, dem Straße, PLZ oder Ort fehlen; es zählt erst, wenn es vollständig ist.
Entwurf: GET /v1/convert/{id}
Der Auftrag wie oben, im Status draft zusätzlich mit draft. Beträge in Euro, nicht in Cent. in_progress ist true, solange eine Bestätigung für ihn läuft. GET /v1/convert/{id}/pdf liefert die hochgeladene Rechnung als PDF, solange der Entwurf besteht; danach 404.
name, street, postal_code, city, country, vat_id; seller dazu tax_number, email, phone, contact, iban, soweit bekannt. Ist dein Absenderprofil vollständig, kommt der Verkäufer von dort. Sonst ist seller_from_invoice true, und seller ist vorbelegt aus der Rechnungsanschrift deines Kontos oder, ohne sie, aus der Rechnung gelesen.seller_from_invoice ist true, wenn du den Absender im Entwurf mit bestätigst (Feld seller beim Bestätigen). seller_source sagt, woher er kommt: profile (Absenderprofil), billing_details (Rechnungsanschrift des Kontos) oder invoice (aus der Rechnung gelesen)description, quantity, unit, unit_code, unit_unknown, unit_price, net_amount, tax_rate, pass_through. unit ist der Text auf der Rechnung, unit_code der Code nach UN/ECE Rec. 20. pass_through ist true bei einem durchlaufenden Posten.type (allowance oder charge), reason, amount nettotax_rate ist der Steuersatz der Rechnung; er kann null sein.AE (Reverse Charge) oder E (steuerbefreit), wenn der Grund im Text steht, sonst null. Sind alle Positionen mit 0 % durchlaufende Posten, ist es null.invoice, prepayment (Vorschussrechnung), partial (Teilrechnung) oder credit_note (Rechnungskorrektur, Storno). Bezüge auf frühere Rechnungen: [{ number, date }], sonst []{ start, end }, sonst nullnull{ mandate_reference, creditor_id, debtor_iban, debtor_iban_masked }, sonst null. debtor_iban_masked ist true, wenn die IBAN deines Kunden auf der Rechnung gekürzt steht: Für ZUGFeRD reicht das, für XRechnung brauchst du sie ganz.totals_add_up, totals_in_text, lines_match_net, buyer_is_not_seller, seller_on_invoiceinvoice_number, issue_date, net_total, tax_total, gross_total, buyer, lines, units, quantities, tax_exemption, pass_through, seller, seller_details, allowances_charges, document_type, preceding_invoices, billing_period, prepaid_amount, direct_debit"units": "Die Einheit „Fass“ kennen wir nicht …"Bestätigen: POST /v1/convert/{id}/confirm
zugferd (deine PDF mit eingebettetem XML) oder xrechnung (nur XML)email (bei XRechnung Pflicht). vat_id ist bei Reverse Charge Pflicht.description, quantity, unit_code, unit_price, net_amount, tax_rate, pass_through. Fehlt tax_rate, gilt der Satz der Rechnung, bei pass_through: true 0 %. Ein durchlaufender Posten zählt im XML zum Netto (BT-109), auf deiner PDF oft nicht. Das ist normgerecht; der Gesamtbetrag stimmt in beiden.422 mit problems. tax_rate gilt für Positionen ohne eigenen Satz; fehlt er, nennt missing ihn. War er im Entwurf null, nimm den höchsten Satz der Positionen, so macht es die Website.AE oder E{ start, end }, beide als YYYY-MM-DD. Ohne Leistungsdatum gilt das Ende als Leistungsdatum (BT-72).credit_note) braucht einen Bezug, und ihre Beträge trägst du positiv ein. Ins XML kommt nur der erste Bezug, alle weiteren nennt der Hinweis (BT-22).prepaid_amount (schon gezahlt, brutto) ziehen wir vom Zahlbetrag ab (BT-113); prepaid_vat nennt der Hinweis zum Abzug. amount_due gleichen wir mit Gesamtbetrag minus schon gezahlt ab; ins XML kommt es nicht.{ mandate_reference, creditor_id, debtor_iban }. Fehlt creditor_id, nehmen wir die Gläubiger-ID aus deinem Absenderprofil, wenn es vollständig ist. Die IBAN deines Kunden darf bei ZUGFeRD gekürzt sein, bei XRechnung nicht. Ohne direct_debit gilt Überweisung.[{ filename, content_base64 }], Grenzen wie bei create_invoice. Eine Beschreibung schreiben wir beim Umwandeln nicht ins XML. Anlagen gehen nur mit der Bestätigung mit, nie mit dem Upload. Den Sammeldownload baut die Website im Browser; über die API holst du jede Datei einzeln. Kamen Anlagen mit, nennt note sie mit.name, street, postal_code, city, dazu vat_id oder tax_number und country, email, phone, contact, iban. Nicht nötig, wenn im Konto ein vollständiges Absenderprofil (Name, Straße, PLZ, Ort) oder eine vollständige Rechnungsanschrift steht, sonst Pflicht. Bei XRechnung sind contact, phone und email Pflicht, bei Überweisung auch iban; ohne vollständiges Absenderprofil brauchst du seller dann immer, denn in der Rechnungsanschrift stehen sie nicht.true: Ohne vollständiges Absenderprofil übernehmen wir den bestätigten seller in dein Profil. Das geschieht, sobald die E-Rechnung die Prüfung besteht, ohne Tarif also schon vor dem Kauf. Er ersetzt Name, Anschrift, USt-IdNr., Steuernummer, Kontakt und IBAN, bei einer Lastschrift auch die Gläubiger-ID aus direct_debit.creditor_id; was er nicht mitbringt, bleibt, ebenso Logo und Zahlungsbedingungen. Kommt eine andere IBAN, leeren wir BIC und Kontoinhaber. Mit false bleibt das Profil, wie es istseller, immer nötig; kommt er aus dem Absenderprofil oder der Rechnungsanschrift, nur, wenn er nicht auf der Rechnung steht. Fehlt es, kommt 422 mit own_invoice_required: true402 mit overage_required: true{
"ok": true,
"filename": "RE-2026-121.pdf",
"mime": "application/pdf",
"content": "JVBERi0xLjc…",
"note": "Die E-Rechnung ist formal gültig und von dir bestätigt. …"
}
Eine Bestätigung dauert meist nur Sekunden, kann aber länger dauern, denn wir erzeugen und prüfen die E-Rechnung dabei. Lass dein Programm bis zu drei Minuten auf die Antwort warten. Bricht die Verbindung vorher ab, schick dieselbe Bestätigung noch einmal: Wir zählen die Umwandlung und löschen Upload und Entwurf erst, wenn die Antwort hinausging. Doppelt zählt nichts. Kommt darauf 409 mit in_progress: true, läuft die erste Bestätigung noch. Warte ein paar Sekunden und frag mit GET /v1/convert/{id} den Stand ab. Steht dort in_progress: true, läuft sie noch, und du wartest weiter. Sonst gilt der Status: Bei draft schickst du die Bestätigung noch einmal, bei awaiting_payment geht es mit dem Kauf weiter. Bei done ist die Umwandlung fertig und gezählt; kam die Datei nicht bei dir an, schreib uns.
Ohne Tarif: kaufen und abholen
Ohne Tarif antwortet /confirm mit 402, sobald die Datei erzeugt ist und die Prüfung bestanden hat: { payment_required: true, price_cents: 399, prefill: { email, company, country, vat_id } }. Sie liegt dann bis zu 25 Stunden bereit.
{ plan, interval, company, country, vat_id, save_profile }. plan: single (diese Umwandlung, 3,99 € zzgl. USt) oder pro (Automatisieren, interval year oder month). Antwort { url }, die Seite der Zahlung bei Stripe. Im Gastmodus dazu email; gehört sie schon zu einem Konto, kommt 409 mit login_required: true, und du kaufst angemeldet in deinem Konto?session_id=…: { paid, plan }{ filename, mime, content, note }. Bezahlt liegt sie sieben Tage bereit; nach dem ersten Abholen noch eine Stunde, falls der Download nicht ankamFehler
missing nennt sie, etwa seller.vat_id oder seller.tax_number. Kommt ein Feld in falscher Form, etwa prepaid_amount als Text, steht es auch dortoverage_required: true per accept_overage bestätigen; ohne dieses Feld ist Mehrnutzung für das Konto nicht eingerichtet oder, wie im Testzugang, ausgeschlossen, und details sagt, wie es weitergeht. Ohne Tarif: payment_required: true, die Datei ist fertig und wartet auf den Kauf/pdf auch, sobald die hochgeladene Datei weg istdraft, oder schon umgewandelt. Mit in_progress: true läuft gerade eine Bestätigung für ihn; Verwerfen und Ersetzen warten, bis sie fertig ist. Mit paid: true ist die Umwandlung bezahlt, hol die Datei mit /file abexpired: true ist der Entwurf abgelaufen, aber noch nicht gelöscht. Sonst ist die Datei weg, oder die Zahlung passt nicht mehr in die Frist. Dann lädst du die Rechnung neu hoch. Bei /file heißt 410: Die bezahlte Datei ist nicht mehr da. Schreib uns, wir helfen dir weiter.problems erklärt es auf DeutschIst eine Frist abgelaufen, löschen wir Auftrag und Datei, spätestens zehn Minuten danach. Bis dahin antwortet /confirm mit 410 und expired: true, ab dann jeder Aufruf mit 404, wie bei einem unbekannten Auftrag.
DELETE /v1/convert/{id} verwirft einen Auftrag und löscht die Datei sofort.Stapel-Prüfung auf dem Server. Für viele Rechnungen auf einmal, ohne dass dein Programm oder Browser die ganze Zeit verbunden bleibt: Dateien hochladen, starten, später die Ergebnisse abholen. Ab Automatisieren. Die Rechnungen liegen verschlüsselt auf unserem Server in Deutschland, bis sie geprüft sind, und werden direkt danach gelöscht. Die Ergebnisse bleiben sieben Tage, danach löschen wir sie. Wenn alles fertig ist, kommt eine E-Mail an die Adresse des Kontos. In einem Firmenkonto kann der Inhaber das für die anderen Zugänge abschalten (PATCH /v1/org/settings mit { "stapel_ablage": false }).
Aufrufe
{ sprache?: "de" | "en" | "fr" } (Sprache der Mail). Antwort 201 mit { id, max_dateien, max_bytes }. Höchstens 3 offene Aufträge je Schlüssel.{ name, file_type: "pdf" | "xml", file_content } (Base64, höchstens 15 MB). Höchstens 500 Dateien je Auftrag.status (hochladen, wartend, fertig, angehalten), anzahl, fertig, ok, mit_fehlern, neu, grund, ablauf. In ergebnisse stehen die Prüfergebnisse wie bei validate_invoice, mit nr und reference (Dateiname). Mit seit=0 kommen alle und die Liste namen; danach seit = der zuletzt gelieferte stand, dann kommen nur neue (das letzte kann doppelt kommen).Jede Datei zählt aufs Wochenkontingent. Ist es aufgebraucht, hält der Auftrag an (status: "angehalten", grund: "kontingent"); die übrigen Dateien bleiben ungeprüft und werden gelöscht. Der Server prüft solche Aufträge nur auf Plätzen, die gerade frei sind; wer direkt prüft, geht vor.
Listet die Rechnungen, die wir dir gestellt haben, mit Nummer, Datum und Beträgen. GET /v1/invoices/{nummer}/pdf liefert das Dokument als PDF. Die Rechnungen sind selbst gültige E-Rechnungen im ZUGFeRD-Format nach EN 16931, deine Buchhaltung kann sie also einlesen. Dieselbe Liste steht im Konto unter „Rechnungen". Der Aufruf kostet kein Kontingent.
Anmeldung
?api_key=… an die Adresse.Beispiel
curl -H "X-Api-Key: dein_key" https://api.zugferd-validator.de/v1/invoices
curl -H "X-Api-Key: dein_key" \
-o ZF-2026-007.pdf \
https://api.zugferd-validator.de/v1/invoices/ZF-2026-007/pdf
Antwort
{
"invoices": [
{ "number": "ZF-2026-007", "date": "2026-08-17T09:12:03.000Z",
"net": 2000, "vat": 380, "gross": 2380, "currency": "eur" }
]
}
Beträge in Cent. Es werden nur eigene Rechnungen ausgeliefert; die Nummer eines anderen Kontos beantworten wir mit 404.
Liefert das Prüfergebnis als Validierungsbericht im Format PDF/A-3b, zum Ablegen und Weitergeben. Der Bericht nennt das Ergebnis, alle Meldungen mit Regel-ID und Feld, den Prüfzeitpunkt, das erkannte Format samt Profil, die SHA-256-Prüfsumme der geprüften Datei und den Regelstand, also die Versionen der eingesetzten Prüfwerkzeuge. Jeder Aufruf prüft die Datei neu und zählt wie eine Validierung gegen das Wochenkontingent. Als MCP-Werkzeug validation_report und über REST als POST /v1/report.
Input
pdf oder xmlAFRelationship /Source), damit sie maschinell lesbar bleibt. Standard false.de, en, fr — Standard derechnung.pdf bzw. rechnung.xml.Output
Content-Type: application/pdf Content-Disposition: attachment; filename="validierungsbericht-rechnung.pdf" X-Validation-Result: valid | invalid
Beispiel
curl -X POST https://api.zugferd-validator.de/v1/report \
-H "X-Api-Key: $ZV_KEY" \
-H "Content-Type: application/json" \
-d "{\"file_content\": \"$(base64 -w0 rechnung.pdf)\", \"file_type\": \"pdf\", \"attach_source\": true}" \
-o bericht.pdf
403; einen Beispielbericht mit Wasserzeichen gibt es ohne Schlüssel unter GET /v1/report/sample?lang=de|en|fr.6. Resource: validation_rules
Gibt das aktuelle Regelwerk des Servers zurück: unterstützte Formate, Profile und die verwendete Validierungsengine.
URI: validation://rules
{
"supported_formats": [
"ZUGFeRD 1.0", "ZUGFeRD 2.0", "ZUGFeRD 2.1", "ZUGFeRD 2.2",
"ZUGFeRD 2.3", "ZUGFeRD 2.x / Factur-X 1.0x",
"XRechnung 1.2", "XRechnung 2.0", "XRechnung 2.3", "XRechnung 3.0"
],
"supported_profiles": [
"minimum", "basic_wl", "basic", "en16931", "extended", "xrechnung"
],
"validation_engines": [
"Mustang Project v2.26.0",
"KoSIT Validierungstool v1.6.3 (XRechnung 3.0.2 + EN 16931 CII)"
],
"last_updated": "2026-04-08"
}
7. Fehlerbehandlung
Alle Tools geben bei Fehlern ein JSON-Objekt mit einem error-Feld zurück. Über MCP gibt es eine Ausnahme: Passt die Eingabe nicht zum Schema des Tools (falscher Typ, fehlendes Pflichtfeld, Wert nicht in der Liste), meldet das schon das Protokoll als Werkzeugfehler (isError: true) mit dem Text der Schemaprüfung, nicht als JSON-Objekt.
{
"error": "Kurze Fehlerkategorie",
"details": "Ausführliche Beschreibung mit konkretem Hinweis zur Behebung."
}
| error | Auslöser |
|---|---|
"Fehlender Parameter" | Pflichtfeld nicht übergeben |
"Ungültiger Parameter" | Falscher Wert für file_type |
"Ungültiger Base64-Input" | Kein gültiger Base64-String übergeben |
"Validierungsfehler" | Mustang CLI konnte nicht starten (z.B. Java fehlt) oder Timeout nach 30s |
"XML-Extraktion fehlgeschlagen" | Keine XML-Datei im PDF-Anhang gefunden (bei extract / consistency). Bei validate kommt stattdessen valid: false mit not_an_einvoice: true und dem einzigen Fehler NO_EMBEDDED_XML (Beispiel 5) |
"PDF-Lesefehler" | PDF kann nicht gelesen werden |
"XML-Parsing-Fehler" | Extrahiertes XML ist kein valides XML |
"Interner Fehler" | Unerwarteter Laufzeitfehler |
"error": "Validierungsfehler" zurückgegeben. Ein KoSIT-Timeout wird still ignoriert — Mustang-Ergebnisse bleiben erhalten.8. Gemeinsame Datentypen
ValidationIssue
Wird in den Arrays errors, warnings und notices von validate_invoice verwendet.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
severity | "error" | "warning" | "notice" | Ja | Schweregrad des Befundes |
rule_id | string | Ja | Regel-ID, z.B. "BR-DE-1", "BR-CL-10". Wert "UNKNOWN" bei XSD-Schema-Verletzungen (KoSIT) oder wenn keine Regel-ID ermittelbar ist |
field | string | Nein | Betroffenes BT-Feld, z.B. "BT-10" |
message | string | Ja | Fehlermeldung auf Deutsch |
fix_suggestion | string | Nein | Konkreter Korrekturhinweis mit XML-Beispiel |
xpath | string | Nein | XPath zum betroffenen XML-Element |
InvoiceMetadata
Optionales Feld im Ergebnis von validate_invoice (nur bei file_type: "xml").
| Feld | Typ | Beschreibung |
|---|---|---|
invoice_number | string? | Rechnungsnummer (BT-1) |
issue_date | string? | Rechnungsdatum ISO 8601, z.B. "2026-04-01" |
seller | string? | Name des Verkäufers (BT-27) |
buyer | string? | Name des Käufers (BT-44) |
total_amount | string? | Gesamtbetrag als Dezimalstring, z.B. "1190.00" |
currency | string? | ISO 4217 Währungscode, z.B. "EUR" |
9. Unterstützte Formate & Profile
Formate
| Format | Standard | Anmerkung |
|---|---|---|
| ZUGFeRD 1.0 | ZUGFeRD 1.0 / GEFEG | Ältere Version, eingeschränkte Profilunterstützung |
| ZUGFeRD 2.0 | FeRD 2.0 | Erste CII-basierte Version |
| ZUGFeRD 2.1 | Factur-X 1.0 (FR) | Technisch identisch mit Factur-X 1.0 |
| ZUGFeRD 2.2 | Factur-X 1.0.05 | Kleinere Korrekturen |
| ZUGFeRD 2.3 | Factur-X 1.0.06 | Version vor 2.4 |
| ZUGFeRD 2.x / Factur-X 1.0x | EN 16931 + D16B | Aktuelle Hauptversion (2026) — API gibt "ZUGFeRD 2.x" zurück |
| XRechnung 1.2 | XRechnung 1.2 | Ältere XRechnung-Version |
| XRechnung 2.x | XRechnung 2.0–2.3 | Verschiedene Zwischenversionen |
| XRechnung 3.0 | XRechnung 3.0 | Aktuelle XRechnung-Version |
Profile (ZUGFeRD/Factur-X)
| Profil-ID | Anzeigename | Typischer Einsatz |
|---|---|---|
minimum | MINIMUM | Einfache maschinelle Verarbeitung |
basic_wl | BASIC-WL | Ohne Positionsdetails |
basic | BASIC | Standard-Rechnungen |
en16931 | EN 16931 (COMFORT) | Öffentliche Auftraggeber, PEPPOL |
extended | EXTENDED | Komplexe B2B-Prozesse |
xrechnung | XRECHNUNG | Deutsche öffentliche Verwaltung |
10. Regelwerk & Korrekturvorschläge
Der Server enthält eine Datenbank mit Korrekturvorschlägen für 160 Regelkategorien. Fehler beider Validierungsengines (Mustang + KoSIT) werden konsolidiert — wenn eine bekannte Regel-ID gefunden wird, wird der Korrekturvorschlag automatisch angehängt.
rule_id nennt die Regel in Großbuchstaben und ohne führende Null: BR-6 statt BR-06, BR-DE-25-B statt BR-DE-25-b. Teilt XRechnung eine Regel in zwei, steht die ganze Kennung da. Feldkennungen wie BT-89 sind nie eine Regel-ID.
BR-DE-Regeln 32 Regeln
Deutsche Erweiterungen, Pflicht für XRechnung-konforme Rechnungen. Stand XRechnung 3.0.2; Warnungen und Hinweise machen die Rechnung nicht ungültig.
| Regel-ID | Feld | Kurzbeschreibung |
|---|---|---|
BR-DE-1 | BG-16 | PAYMENT INSTRUCTIONS (BG-16) fehlen |
BR-DE-2 | BG-6 | SELLER CONTACT (BG-6) |
BR-DE-3 | BT-37 | Stadt des Verkäufers (BT-37) |
BR-DE-4 | BT-38 | PLZ des Verkäufers (BT-38) |
BR-DE-5 | BT-41 | Ansprechpartner des Verkäufers (BT-41) |
BR-DE-6 | BT-42 | Telefonnummer des Verkäufers (BT-42) |
BR-DE-7 | BT-43 | E-Mail des Verkäufers (BT-43) |
BR-DE-8 | BT-52 | Stadt des Käufers (BT-52) |
BR-DE-9 | BT-53 | PLZ des Käufers (BT-53) |
BR-DE-10 | BT-77 | Lieferstadt (BT-77) |
BR-DE-11 | BT-78 | Liefer-PLZ (BT-78) |
BR-DE-12 | – | in aktueller XRechnung-Fassung entfernt |
BR-DE-13 | – | in aktueller XRechnung-Fassung entfernt |
BR-DE-14 | BT-119 | USt-Satz (BT-119) |
BR-DE-15 | BT-10 | Käuferreferenz / Leitweg-ID (BT-10) |
BR-DE-16 | BT-31 | USt-ID/Steuernummer des Verkäufers |
BR-DE-17 | BT-3 | Rechnungsart, die XRechnung nicht empfiehlt, etwa 386 (Warnung) |
BR-DE-18 | BT-20 | Skonto-Angaben (BT-20) im falschen Format |
BR-DE-19 | BT-84 | IBAN des Empfängerkontos bei Überweisung (58) ungültig (Warnung) |
BR-DE-20 | BT-91 | IBAN des Zahlers bei Lastschrift (59) ungültig (Warnung) |
BR-DE-21 | BT-24 | Specification identifier (BT-24) nicht XRechnung-konform (Warnung) |
BR-DE-22 | BT-125 | Dateinamen der Anlagen nicht eindeutig |
BR-DE-23-A | BG-17 | Überweisung (30, 58) ohne Kontoangaben |
BR-DE-23-B | BT-81 | Überweisung (30, 58) mit Karte oder Lastschrift |
BR-DE-24-A | BG-18 | Kartenzahlung (48, 54, 55) ohne Kartenangaben |
BR-DE-24-B | BT-81 | Kartenzahlung mit Konto oder Lastschrift |
BR-DE-25-A | BG-19 | Lastschrift (59) ohne Lastschriftangaben |
BR-DE-25-B | BT-81 | Lastschrift (59) mit Empfängerkonto oder Karte |
BR-DE-26 | BT-3 | Korrigierte Rechnung (384) ohne Bezug auf die frühere Rechnung (Warnung) |
BR-DE-27 | BT-42 | Telefon mit weniger als drei Ziffern (Warnung) |
BR-DE-28 | BT-43 | E-Mail-Adresse in falscher Form (Warnung) |
BR-DE-30 | BT-90 | Lastschrift ohne Gläubiger-ID |
BR-DE-31 | BT-91 | Lastschrift ohne IBAN des Zahlers |
BR-DE-TMP-32 | BT-72 | Kein Liefer- oder Leistungsdatum (Hinweis) |
EN-16931-Kernregeln (BR-*) 10 Regeln
| Regel-ID | Feld | Kurzbeschreibung |
|---|---|---|
BR-1 | BT-24 | Specification identifier (BT-24) |
BR-2 | BT-1 | Rechnungsnummer (BT-1) |
BR-3 | BT-2 | Rechnungsdatum (BT-2) |
BR-4 | BT-3 | Rechnungstyp-Code (BT-3) |
BR-5 | BT-5 | Währungscode (BT-5) |
BR-6 | BT-27 | Verkäufername (BT-27) |
BR-7 | BT-44 | Käufername (BT-44) |
BR-8 | BG-5 | Postanschrift des Verkäufers (BG-5) |
BR-9 | BG-5 | Ländercode des Verkäufers (BT-40) |
BR-10 | BG-8 | Postanschrift des Käufers (BG-8) |
Berechnungsregeln (BR-CO-*) & Codelistenregeln (BR-CL-*) 8 Regeln
| Regel-ID | Kurzbeschreibung |
|---|---|
BR-CO-3 | Steuerdatum und Steuerdatum-Code schließen sich aus |
BR-CO-9 | USt-ID des Verkäufers ohne Länderpräfix |
BR-CO-10 | Summe der Netto-Positionsbeträge stimmt nicht |
BR-CO-13 | Gesamtbetrag ohne USt falsch berechnet |
BR-CL-10 | Ungültige schemeID (nicht aus ISO 6523) |
BR-CL-16 | Ungültiger Zahlungsart-Code (nicht aus UNTDID 4461) |
BR-CL-17 | Ungültige USt-Kategorie bei Rabatt oder Zuschlag auf Belegebene (in UBL auch in der Steueraufschlüsselung) |
BR-CL-18 | Ungültige USt-Kategorie auf Positionsebene (in CII auch in der Steueraufschlüsselung) |
Steuerkategorieregeln (BR-S/Z/E/AE-*) 4 Regeln
| Regel-ID | Kurzbeschreibung |
|---|---|
BR-S-1 | Normalsatz (S) ohne Steueraufschlüsselung der Kategorie S |
BR-Z-1 | Nullsatz (Z): genau eine Steueraufschlüsselung der Kategorie Z |
BR-E-1 | Steuerbefreit (E): genau eine Steueraufschlüsselung der Kategorie E, also ein Grund für 0 % je Rechnung |
BR-AE-1 | Reverse Charge (AE): genau eine Steueraufschlüsselung der Kategorie AE |
11. Nutzungsbeispiele
Beispiel 1: XRechnung-XML validieren
{
"tool": "validate_invoice",
"arguments": {
"file_content": "PD94bWwgdmVyc2lvbj0iMS4wIj8+...",
"file_type": "xml",
"profile": "xrechnung"
}
}
{
"valid": true,
"format": "XRechnung 3.0",
"profile": "XRECHNUNG",
"summary": "Keine Probleme gefunden",
"errors": [],
"warnings": [],
"metadata": {
"invoice_number": "INV-2026-0042",
"issue_date": "2026-04-07",
"seller": "Tech GmbH",
"buyer": "Bundesbehörde X",
"total_amount": "5950.00",
"currency": "EUR"
}
}
Beispiel 2: Fehlerhafte Rechnung mit Korrekturvorschlag
{
"tool": "validate_invoice",
"arguments": {
"file_content": "JVBERi0xLjQK...",
"file_type": "pdf"
}
}
{
"valid": false,
"format": "ZUGFeRD 2.x",
"profile": "XRECHNUNG",
"summary": "1 Fehler gefunden",
"errors": [{
"severity": "error",
"rule_id": "BR-DE-15",
"field": "BT-10",
"message": "Käuferreferenz (BT-10) muss für XRechnung angegeben werden.",
"fix_suggestion": "Füge 'ram:BuyerReference' hinzu, z.B. '04011000-1234-34' für Behörden.",
"xpath": "//ram:ApplicableHeaderTradeAgreement/ram:BuyerReference"
}],
"warnings": []
}
Beispiel 3: XML extrahieren und validieren
// Schritt 1 — XML aus PDF extrahieren { "tool": "extract_xml", "arguments": { "pdf_content": "JVBERi0x..." } } // Schritt 2 — Extrahiertes XML validieren (base64-kodiert übergeben) { "tool": "validate_invoice", "arguments": { "file_content": "<base64 des xml_content>", "file_type": "xml" } }
Beispiel 4: Konsistenzprüfung
{
"tool": "check_consistency",
"arguments": { "pdf_content": "JVBERi0xLjQK..." }
}
{
"consistent": false,
"discrepancies": [{
"field": "total_amount",
"pdf_value": "1190.00",
"xml_value": "1180.00",
"message": "Gesamtbetrag im PDF ('1190.00') unterscheidet sich von dem im XML ('1180.00')."
}]
}
Beispiel 5: PDF ohne eingebettetes XML
Eine normale PDF-Rechnung ohne eingebettetes XML ist keine E-Rechnung. Die Antwort sagt das mit valid: false und not_an_einvoice: true; der einzige Fehler NO_EMBEDDED_XML nennt, was fehlt. Format und Profil fehlen dann.
{
"tool": "validate_invoice",
"arguments": {
"file_content": "JVBERi0xLjQK...",
"file_type": "pdf"
}
}
{
"valid": false,
"not_an_einvoice": true,
"summary": "1 Fehler gefunden",
"errors": [{
"severity": "error",
"rule_id": "NO_EMBEDDED_XML",
"message": "Diese PDF enthält kein eingebettetes XML. …",
"fix_suggestion": "Erzeuge die Rechnung mit E-Rechnungs-fähiger Software, die das strukturierte XML in die PDF einbettet (ZUGFeRD/Factur-X), oder validiere direkt die XRechnung-XML."
}],
"warnings": []
}
12. Grenzen & Bekannte Einschränkungen
| Einschränkung | Details |
|---|---|
| Timeout | Mustang CLI wird serverseitig nach 30 Sekunden abgebrochen. Sehr große oder korrupte Dateien können diesen Timeout auslösen. |
| Rate-Limit | Validierung: Prüfen 20/Woche · Automatisieren 500/Woche · Skalieren unbegrenzt. Erstellung (eigenes Kontingent): Prüfen 1 im Monat · Automatisieren und Skalieren unbegrenzt, Fair Use über das Stundenlimit. Sandbox-Erstellung: 100/Tag, max. 3/Minute. Sandbox-Prüfungen zählen auf das normale Wochenkontingent. Bei Überschreitung: HTTP 429. |
| Durchsatz | Automatisieren läuft bis 60, Skalieren bis 300 Aufrufe pro Stunde mit voller Geschwindigkeit. Darüber gibt es keine Sperre: Weitere Aufrufe laufen in einer langsamen Spur und bekommen nur Plätze, die gerade frei sind. Ist der Server voll, antwortet er nach bis zu 20 Sekunden Wartezeit mit HTTP 503, Retry-After: 15 und slow_lane: true. Dein Programm sendet die Rechnung dann einfach erneut. Das Wochenkontingent gilt weiter. |
| PDF-OCR | check_consistency wertet nur maschinenlesbaren PDF-Text aus. Eingescannte PDFs ohne OCR-Schicht werden nicht unterstützt. |
| Metadaten bei PDFs | validate_invoice extrahiert Metadaten auch bei PDFs, sofern ein eingebettetes XML vorhanden und lesbar ist. Bei Plain-PDFs ohne XML fehlt dieses Feld. |
| Konsistenzprüfung | Nur drei Felder werden verglichen (Nummer, Datum, Betrag). Adressen, Steuernummern und Positionsdetails werden nicht abgeglichen. |
| Unbekannte Regel-IDs | Fehlt eine Regel-ID in der Fix-Suggestions-DB, bleibt fix_suggestion leer. Die Meldung wird trotzdem zurückgegeben. |
| Dateigröße | Gehostete API: Eine Anfrage darf als JSON höchstens 50 MB groß sein, sonst kommt 413. Base64 macht Dateien um ein Drittel größer, also passen rund 35 MB an Dateien in eine Anfrage. Je Datei gilt dazu beim Umwandeln (/v1/convert) höchstens 10 MB, bei der Stapel-Prüfung (/v1/stapel) höchstens 15 MB. Der selbst betriebene MCP-Server hat keine feste Grenze, aber Mustang bricht nach 30 Sekunden ab; sehr große PDFs schaffen das womöglich nicht. |
| Anlagen | Beim Erstellen und Umwandeln höchstens 10 Anlagen je Rechnung, jede und alle zusammen höchstens 5 MB, gemessen nach dem Dekodieren. Ab zwei Anlagen warnt die Prüfung mit CII-SR-476; die Rechnung bleibt gültig. |
13. Changelog
Oktober 2026: Testzugang, Umwandlungskontingent und Enterprise
- Neu: Testzugang mit Frist, eigenes Umwandlungskontingent, Enterprise-Angebot im Konto.
- Neu beim Umwandeln:
quotainGET /v1/convertnennttrial_until(letzter Tag des Testzugangs, sonstnull) undindividual(truebei einem vereinbarten Kontingent). Im Testzugang gibt es keine Mehrnutzung: Ist das Kontingent aufgebraucht, antwortet/confirmmit402ohneoverage_required.
Oktober 2026: Steuernummer, Lastschrift und Anlagen
- Neu: Steuernummer statt USt-IdNr., durchlaufende Posten, schon gezahlte Beträge, Bezug auf frühere Rechnungen, SEPA-Lastschrift, Anlagen (Erstellen und Umwandeln); Sammeldownload als ZIP auf der Website. In
POST /v1/createundcreate_invoiceheißen die Felderseller.tax_number,lines[].pass_through,prepaid_amount_cents,prepaid_vat_cents,preceding_invoices,direct_debitundattachments; beim Umwandeln stehen sie in Entwurf und Bestätigung, Beträge in Euro. - Neu: Das Absenderprofil (
/v1/keys/issuer) trägt die Gläubiger-ID (creditor_id).PUT /v1/keys/issuerändert nur die Felder, die im Aufruf stehen; eine leere Zeichenkette odernulllöscht ein Feld. Eine USt-IdNr. ohne Ländercode und eine Steuernummer in falscher Form lehnt es mit400ab. - Geändert: Mit Leistungszeitraum und ohne Leistungsdatum steht als Leistungsdatum (BT-72) jetzt das Ende des Zeitraums, nicht mehr das Rechnungsdatum. Bei einer Vorschussrechnung ohne Leistungsdatum und Zeitraum fehlt BT-72; die ZUGFeRD-Prüfung warnt dann (PEPPOL-EN16931-R008).
- Geändert: Eingaben, die bisher eine ungültige Datei ergaben (weder USt-IdNr. noch Steuernummer, USt-IdNr. ohne Ländercode, Zeitraum mit Ende vor Anfang, Lastschrift in der XRechnung ohne Mandat), beantworten wir jetzt mit 400.
- Geändert: Die PDF einer Rechnungskorrektur (
credit_note) nennt keinen Zahlbetrag mehr, sondern sagt: „Dieser Betrag wird Ihnen gutgeschrieben.“ - Geändert: Über MCP enthält die Antwort einer ZUGFeRD-Rechnung mit Anlagen nur
pdf_base64; das XML steckt in der PDF. - Geändert: Regelkennungen berichtigt: keine Scheinkennungen mehr (BT-89, TMP-32, EU-79), KoSIT-Regeln mit Buchstaben heißen ganz (BR-DE-25-B statt BR-DE-25), doppelte Meldungen entfallen. Der Korrekturvorschlag zu BR-DE-20 (IBAN des Zahlers) sagt nicht mehr, die Regel gebe es nicht; CII-SR-475 und CII-SR-476 bei mehreren Anlagen erklären wir als harmlos.
- Geändert beim Umwandeln:
missingnennt stattseller.vat_idjetztseller.vat_id oder seller.tax_number. Ein Absenderprofil mit USt-IdNr. und gültiger Steuernummer ergibt beide im XML. XRechnung mit Lastschrift braucht keine eigene IBAN.save_profileübernimmt auch Steuernummer und Gläubiger-ID. - Geändert auf der Website, E-Rechnung erstellen: Der Absender hat jetzt Ansprechpartner und Telefon. XRechnung verlangt beide; ohne sie war jede XRechnung dieser Seite ungültig (BR-DE-5, BR-DE-6). Dazu kamen die Felder für Steuernummer, Rechnungsart, Bezüge, durchlaufende Posten, schon gezahlte Beträge, Lastschrift und Anlagen, auf Deutsch, Englisch und Französisch.
Oktober 2026: Formaterkennung
formatundprofilekommen jetzt aus der Kennung der Spezifikation (in CII das Feld der Guideline, in UBLCustomizationID), nicht mehr aus der ersten URN im Dokument. Vorher blieben viele XRechnungen und EN-16931-Rechnungen ohne Format.- Neue Felder
container(pdf: PDF mit eingebetteter E-Rechnung,xml: reine XML-Datei) undsyntax(CII,UBL). - Bezeichnungen:
ZUGFeRD 2.xundZUGFeRD 1.0für PDF, sonstXRechnung 3.0,Peppol BIS Billing 3.0oderEN 16931. Profile zusätzlichXRECHNUNGundPEPPOL;EXTENDEDwird nicht mehr alsEN16931gemeldet.
Oktober 2026: Umwandeln
- Neu:
POST /v1/convertmacht aus PDF, Word oder Excel eine E-Rechnung (ZUGFeRD im bisherigen Layout oder XRechnung), mit Entwurf, Bestätigung und Prüfung vor der Ausgabe. - Erkennt mehrere Steuersätze, Rabatte und Zuschläge, Reverse Charge und Einheiten; unsichere Felder mit Begründung.
- Ab Automatisieren (20 im Monat) und Skalieren (100), Mehrnutzung 3,99 € je Umwandlung mit ausdrücklicher Bestätigung.
Juni 2026 — Rechnungserstellung
- Neues Tool
create_invoice/POST /v1/create: valide E-Rechnungen aus strukturierten Daten erzeugen — als ZUGFeRD-PDF (PDF/A-3) oder reine XRechnung-XML (mit Leitweg-ID für B2G). - Mehrere Positionen, alle USt-Kategorien (S/Z/E/AE), Rabatte/Zuschläge, Zahlungsangaben, Fälligkeit.
- Belegtypen: Rechnung, Rechnungskorrektur (Storno), Korrektur, Gutschriftverfahren, Anzahlungs- und Teilrechnung, mit Bezug auf die Ursprungsrechnung.
- Tier-abhängiges Branding (Footer im Prüfen-Tarif / White-Label ab Automatisieren mit optionalem Logo); eigenes Wochenkontingent, getrennt von der Validierung.
- Sandbox-/Test-Keys (
zv_test_…): freies Integrieren mit „DEMO"-Wasserzeichen, ohne das Live-Kontingent zu verbrauchen.
April 2026 — Erstveröffentlichung
- Validierung gegen EN 16931 (
validate_invoice) für ZUGFeRD/Factur-X-PDF und XRechnung-XML, mit konkreten Korrekturvorschlägen. - XML-Extraktion (
extract_xml) und Konsistenzprüfung PDF↔XML (check_consistency). - MCP-Client für Claude & andere KI-Agenten; Mustang- und KoSIT-Engines.