E-Rechnungen prüfen
POST /v1/einvoices/validate sagt, welche Regeln eine E-Rechnung bestanden hat, mit welchem Validator und welchem Release seiner Regeln, und welche Bytes er geprüft hat. Es nimmt zwei Arten von Anfragen:
- Ein Rendering Ihres Workspace, das eine E-Rechnung erzeugt hat, als JSON mit
render_id. Jede E-Rechnung, die Formfeed ausliefert, wurde vorher validiert, und das Rendering bewahrt diesen Bericht auf. Die Antwort ist dieser Bericht, in der Form unten. Sie kostet nichts und startet keinen Validator. - Eine XML einer E-Rechnung, die Formfeed nicht erstellt hat, als
multipart/form-datamit einem Teilfile: eine, die Sie erhalten haben, oder eine aus einem anderen System. Ab dem Starter-Tarif; jeder Upload zählt eine der Prüfungen des Tages der Organisation.
Der Schlüssel braucht den Scope einvoice:validate. Schlüssel, die in der App angelegt werden, haben ihn standardmäßig, und formfeed login gibt ihn Editoren, Admins und Inhabern; ein Schlüssel ohne ihn erhält 403 forbidden.
Was der Bericht sagt und was nicht
Der Bericht sagt, welche Regeln eine Datei bestanden hat, mit welchem Validator und Release. Er sagt nicht, ob das Dokument umsatzsteuerlich eine ordnungsgemäße Rechnung ist, und er ersetzt nicht die Prüfung, die ein Unternehmen einer empfangenen Rechnung schuldet.
Das Schreiben des Bundesministeriums der Finanzen zur E-Rechnung vom 15. Oktober 2025 (BStBl I S. 1806) trennt dieselben Dinge:
- ein Fehler des Formats macht das Dokument zu einer „sonstigen Rechnung“ (Rn. 6a);
- ein Fehler der Geschäftsregeln ist etwas anderes, etwa eine fehlende Käuferreferenz (BT-10) in einer XRechnung (Rn. 6b);
- ein Unternehmen darf sich auf den Bericht eines Validators stützen, doch der Bericht ersetzt nicht die eigene Prüfung des Empfängers (Rn. 35a).
Deshalb hält der Bericht auseinander, was er geprüft hat: die Syntax der Datei, ihr XML-Schema und jedes Regelwerk mit Namen, jedes mit eigenem Ergebnis. Ein Urteil über das Dokument als Rechnung fällt er nicht. Wo der Validator der KoSIT empfiehlt, ein Dokument anzunehmen oder abzuweisen, wird diese Empfehlung nicht weitergegeben. Diese Seite ist keine Steuerberatung.
Ein Rendering Ihres Workspace
curl https://api-eu.formfeed.dev/v1/einvoices/validate \
-H "Authorization: Bearer $FORMFEED_API_KEY" \
-H "Content-Type: application/json" \
-d '{"render_id": "rnd_0d290c45cbeb4554b946bbad1acee87e"}'
Die Antwort trägt source.stored: true und die Prüfungen des Berichts, den das Rendering aufbewahrt: das XML-Schema seines Profils, die Factur-X-Regeln von Mustang (die die Regeln der EN 16931 enthalten), die Regeln Frankreichs, wo sie galten, und den PDF/A-3b-Container mit der Rechnung, die er trägt. pdf_sha256 und display kommen ebenfalls aus diesem Bericht. Auch ein fehlgeschlagenes Rendering bewahrt seinen Bericht auf; eines, das keine E-Rechnung erzeugt hat, erhält 422 source_invalid.
rules verlangt ein anderes Regelwerk. en16931 misst die XML einer EN-16931-Rechnung an den Regeln von CEN selbst, aus der Konfiguration, die die KoSIT für ihren Validator veröffentlicht, statt an denen von Mustang: Die Datei des Renderings wird gelesen und erneut validiert, was wie ein Upload zählt. Regeln, die für die Spezifikationskennung der Datei nicht gelten, etwa xrechnung für eine Factur-X-Datei, antworten not_checked, ohne zu zählen.
Eine XML, die Sie erhalten haben
curl https://api-eu.formfeed.dev/v1/einvoices/validate \
-H "Authorization: Bearer $FORMFEED_API_KEY" \
-F file=@RE-2026-0001.xml \
-F rules=auto
- Was sie nimmt: eine XML bis 4 MB, CII oder UBL, in UTF-8. Ein PDF wird nicht angenommen (
415 file_type_unsupported): Senden Sie die XML oder, für ein eigenes ZUGFeRD- oder Factur-X-PDF, die ID seines Renderings. Eine größere Anfrage erhält413 file_too_largeanhand ihrerContent-Length, bevor sie gelesen wird. - Was aufbewahrt wird: nichts. Die Datei wird validiert und vergessen; die Antwort nennt ihren SHA-256 (
xml_sha256) und ihre Größe. - Nichts in einer Datei wird verfolgt. Eine Dokumenttyp-Deklaration (
DOCTYPE), XInclude, eine andere Kodierung als UTF-8, eine Verschachtelung tiefer als 64 Elemente, mehr als 32 Attribute an einem Element, ein Attribut länger als 4.096 Zeichen oder mehr als 300.000 Elemente antwortennot_checkedmitreason: not_read: Kein Validator hat die Datei gelesen. Eine Datei, die kein wohlgeformtes XML ist, antwortetfailed, mit fehlgeschlagener Syntaxprüfung.
Wie viele am Tag
| Tarif | Prüfungen von Uploads pro Organisation und UTC-Tag |
|---|---|
| Free | keine |
| Starter | 100 |
| Pro | 500 |
| Business | 2.000 |
| Enterprise | laut Vertrag |
Der gespeicherte Bericht eines Renderings zählt nie. Eine Anfrage, die der Validator nie beantwortet hat (503 conformance_unavailable), gibt ihre Prüfung zurück; eine, deren Zeit abgelaufen ist (500 einvoice_validator_error), zählt, denn dieselbe Datei läuft wieder in die Zeitgrenze. Ist der Tag aufgebraucht, lautet die Antwort 403 forbidden mit feature: einvoice_validation, der Zahl des Tarifs in limit, dem Verbrauch des Tages in used und resets_at, dem Beginn des nächsten UTC-Tages; nie 429. Anfragen zählen außerdem gegen die Anfragen pro Sekunde des Tarifs, wie Renderings. allowance in der Antwort nennt, was der Tag nach der Anfrage verbraucht hat.
Welches Regelwerk eine Datei prüft
Eine Tabelle vor den Validatoren wählt die Regeln, nach dem Wurzelelement und einem exakten Vergleich der Spezifikationskennung (BT-24, GuidelineSpecifiedDocumentContextParameter/ID in CII, cbc:CustomizationID in UBL). Die Datei nennt die Regeln, denen sie folgen will, und wird an diesen gemessen.
| Wurzel | Spezifikationskennung (BT-24) | Regelwerk (rule_set) | Validator |
|---|---|---|---|
| CII | Factur-X und ZUGFeRD 2.x: MINIMUM, BASIC WL, BASIC, EN 16931 (urn:cen.eu:en16931:2017), EXTENDED | factur-x | Mustang, mit den Regeln von Factur-X 1.09 / ZUGFeRD 2.5 für das Profil |
| CII, UBL Invoice, UBL CreditNote | XRechnung 3.0 (urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0), ihre Extension, CVD | xrechnung | Der Validator der KoSIT mit der Konfiguration der KoSIT für XRechnung |
| UBL Invoice, UBL CreditNote | urn:cen.eu:en16931:2017 | en16931 | Der Validator der KoSIT mit den Regeln von CEN aus derselben Konfiguration, ohne die der XRechnung |
| jede | Peppol BIS Billing 3.0 | noch keins | nicht geprüft |
| jede andere Wurzel oder Kennung | keins | nicht geprüft, mit Nennung dessen, was gefunden wurde |
- Für die XRechnung Extension in einer UBL-Gutschrift hat die Konfiguration der KoSIT keine Regeln, eine solche Datei wird also nicht geprüft.
- In CII ist
urn:cen.eu:en16931:2017das Profil EN 16931 von Factur-X und ZUGFeRD und geht an Mustang;rules: en16931misst sie stattdessen an den Regeln von CEN selbst. - Peppol BIS Billing 3.0 wird noch nicht geprüft.
- Ein
rulesaußerautoprüft nur eine Datei, für deren Kennung das Regelwerk gilt; jede andere antwortetnot_checkedmitreason: rules_not_applicable.
Die Releases der Validatoren und Regeln sind festgelegt, und jeder Bericht nennt die, die die Datei geprüft haben (validator, rules, scenario, versions). Die Abdeckungsseite listet die aktuellen Stände.
Die Antwort
{
"id": "6f2c7e9a-1d4b-4c3e-8a5f-2b7d9e0c1a34",
"result": "failed",
"reason": null,
"explanation": null,
"source": {
"type": "upload",
"filename": "RE-2026-0001.xml",
"bytes": 21304
},
"route": {
"syntax": "cii",
"document": "invoice",
"root": "CrossIndustryInvoice",
"customization_id": "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0",
"rule_set": "xrechnung"
},
"validator": "KoSIT validator 1.6.3",
"rules": "XRechnung 3.0.2, configuration of 2026-08-31",
"scenario": "EN16931 XRechnung (CII)",
"profile": null,
"checks": [
{
"kind": "syntax",
"name": "XML well-formedness, UTF-8",
"result": "passed",
"messages": []
},
{
"kind": "schema",
"name": "XML Schema for UN/CEFACT XML (SCRDM - CII uncoupled)",
"result": "passed",
"messages": []
},
{
"kind": "rules",
"name": "Schematron rules for EN16931 (CII)",
"result": "passed",
"messages": []
},
{
"kind": "rules",
"name": "Schematron rules for CIUS XRechnung (CII)",
"result": "failed",
"messages": [
{
"part": "xml",
"severity": "error",
"rule": "BR-DE-15",
"message": "Das Element \"Buyer reference\" (BT-10) muss übermittelt werden.",
"location": "/rsm:CrossIndustryInvoice"
}
]
}
],
"truncated": false,
"versions": {
"kosit": "1.6.3",
"xrechnung_configuration": "2026-08-31",
"xrechnung_schematron": "2.6.0",
"cen": "1.3.16",
"saxon": "12.10"
},
"xml_sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"pdf_sha256": null,
"display": null,
"validated_at": "2026-11-06T10:15:02.118Z",
"allowance": { "limit": 100, "used": 7, "resets_at": "2026-11-07T00:00:00Z" }
}
| Feld | Was es sagt |
|---|---|
result | passed: Ein Validator hat seine Regeln bis zum Ende ausgeführt, und jede Prüfung ist bestanden. failed: Eine Prüfung hat einen Fehler gefunden. not_checked: Kein Regelwerk hier gilt für die Datei, sie wurde nicht gelesen, oder der Validator ist nicht fertig geworden |
reason, explanation | Warum nicht geprüft wurde, als Code und als Satz, der nennt, was gefunden wurde: not_read, unknown_root, no_customization_id, unknown_customization_id, not_offered, no_scenario, rules_not_applicable, validator_stopped, not_validated, no_verdict |
route | Was die Tabelle aus der Datei gelesen hat, bevor ein Validator sie las: Syntax, Dokument, Wurzel, die Kennung, wie die Datei sie schreibt, und das gewählte Regelwerk |
validator, rules, scenario, profile, versions | Welcher Validator, welche Regeln und welches Release die Datei geprüft haben |
checks | Jede Prüfung mit eigenem Ergebnis (passed, failed oder not_run, wo sie nicht bis zum Ende lief oder nie lief) und ihren Befunden: Fehler zuerst, höchstens 100 je Prüfung (truncated sagt, wenn es mehr waren) |
xml_sha256 | SHA-256 der geprüften XML, so wie sie ankam |
allowance | Was die Prüfungen des Tages nach dieser Anfrage verbraucht haben; null, wo nichts gezählt wurde |
Die Antwort ist 200, gleich welches result: Eine Datei, die durchfällt, ist ein Bericht, kein Fehler. result, reason und kind einer Prüfung können neue Werte bekommen; behandeln Sie einen unbekannten als nicht bestanden.
In den SDKs, der CLI und für Agenten
const report = await client.einvoices.validate({
file: { data: xml, name: 'RE-2026-0001.xml' },
});
const stored = await client.einvoices.validate(
'rnd_0d290c45cbeb4554b946bbad1acee87e',
);
report = client.einvoices.validate(file=xml, file_name="RE-2026-0001.xml")
stored = client.einvoices.validate("rnd_0d290c45cbeb4554b946bbad1acee87e")
formfeed einvoice <slug> --validateder CLI schreibt die XML eines Datensatzes offline und sendet diese Datei hierher.- Der MCP-Server hat das Tool
validate_einvoice.