Zum Hauptinhalt springen

E-Rechnungen (ZUGFeRD, Factur-X)

Eine E-Rechnung ist das PDF, das Ihre Vorlage rendert, und dieselbe Rechnung als XML, in einer Datei. Formfeed erzeugt ZUGFeRD- und Factur-X-Rechnungen: Es wandelt das gerenderte PDF in PDF/A-3b um, bettet die Rechnung als XML ein und validiert die Datei, bevor sie ausgeliefert wird. Das XML wird aus einem _invoice-Block in den Render-Daten gebaut.

Formfeed ist ein Werkzeug, das das Format schreibt. Es leistet keine Steuerberatung: Sie stellen die Rechnung aus und stehen für ihren Inhalt und ihre umsatzsteuerliche Behandlung ein, Formfeed für das Format.

Was Sie erhalten​

  • Eine Datei für Menschen und für Software. Das PDF sieht aus, wie Ihre Vorlage es rendert. Es ist ein PDF/A-3b und trägt die Rechnung als Anhang namens factur-x.xml, in der Syntax Cross Industry Invoice (CII), die ZUGFeRD und Factur-X verwenden.
  • ZUGFeRD und Factur-X. Beide sind eine Spezifikation unter zwei Namen, und die Datei ist dieselbe. Formfeed schreibt die Version Factur-X 1.09, das ist ZUGFeRD 2.5, in den Profilen en16931 und basic.
  • Das XML kommt aus Ihren Daten. Es wird aus data._invoice gebaut und nie aus dem PDF herausgelesen. Formfeed berechnet nichts: Eine Summe, die nicht aufgeht, wird abgelehnt, nie gerundet.
  • Vor der Auslieferung validiert. Das XML wird an seinem Schema und an den Regeln des Profils gemessen, zu denen die Geschäftsregeln der EN 16931 gehören, und die Datei an PDF/A-3b. Eine Datei, die nicht besteht, wird nicht ausgeliefert, und an ihrer Stelle auch kein gewöhnliches PDF: Das Rendering schlägt fehl und sagt, warum.
  • Ein Bericht zu jeder Rechnung. Das Feld einvoice des Renderings sagt, was erzeugt wurde, was der Validator gefunden hat und ob das PDF die Werte zeigt, die das XML nennt.

Das funktioniert für die PDF-Ausgabe von HTML-Vorlagen, von Word- und PowerPoint-Vorlagen, von Ad-hoc-Renderings mit html und von Renderings mit url.

Abdeckung der E-Rechnung nennt die Geschäftsbegriffe der EN 16931, die die Datei trägt, und den Validator und die Regeln, die sie besteht. E-Rechnungen nach Ländern sagt, welches Land was verlangt und wo der Teil von Formfeed endet.

Schnellstart​

  1. Einen Schlüssel besorgen. Ein Test-Schlüssel (ff_test_…) erzeugt E-Rechnungen in jedem Plan, jede mit der Testmarkierung, bis zu einer Anzahl pro Tag; ein Live-Schlüssel (ff_live_…) erzeugt sie ab dem Starter-Plan. Siehe Authentifizierung und Pläne und Einheiten.
  2. Eine Rechnungsvorlage anlegen. Am schnellsten geht es mit einer Kopie des Beispiels: Vorlagen → Beispiele → E-Rechnung: ZUGFeRD und Factur-X aus einer Vorlage. Sie legt die E-Rechnung fest und gibt die Werte ihres _invoice-Blocks aus. Bei einer eigenen Vorlage schalten Sie die E-Rechnung in der Seiteneinrichtung ein (Einschalten) und geben dieselben Werte aus. Veröffentlichen Sie die Version.
  3. Die Rechnungsdaten senden. POST /v1/renders mit dem Slug der Vorlage und dem _invoice-Block in data, wie in der Anfrage unten.
  4. Den Bericht lesen. Ein erfolgreiches Rendering hat eine gültige E-Rechnung erzeugt. Sein einvoice.validation.messages nennt die Warnungen des Validators, einvoice.display.missing die Werte des XML, die das PDF nicht zeigt (Was zurückkommt).

Einschalten​

Eine E-Rechnung lässt sich an drei Stellen festlegen. Sie werden Feld für Feld zusammengeführt, die spätere hat Vorrang:

  1. Die Einstellungen der Vorlage (settings.einvoice). Jedes PDF, das aus der Vorlage gerendert wird, ist dann eine E-Rechnung, und eine Anfrage muss nichts dazu sagen.
  2. settings.einvoice der Anfrage.
  3. post.einvoice der Anfrage: ein Objekt mit den Optionen, {} für die Standardwerte, oder false.

Jede Stelle nimmt dasselbe Objekt mit Optionen oder false. false verwirft, was die Stellen davor festgelegt haben; post.einvoice: false schaltet also die Festlegung einer Vorlage für eine Anfrage ab. Ein Wert, der weder ein Objekt mit diesen Optionen noch false ist, beantwortet die API mit 400 invalid_request und nennt das Feld.

In der Vorlage​

Öffnen Sie im Editor die Seiteneinrichtung, gehen Sie zum Abschnitt E-Rechnung und schalten Sie Die Rechnung als XML in jedes PDF einbetten ein. Der Abschnitt bietet dann Format, Profil, Wenn das PDF einen Wert des XML nicht zeigt und Das XML als eigene Datei speichern; das sind die Optionen weiter unten.

Darunter sagt die Karte Rechnungsdaten, was der Datensatz auf dem Bildschirm über seinen _invoice-Block zu sagen hat: Vollständig mit Rechnungsnummer, Positionen und Gesamtbetrag, die Zahl der Befunde mit dem Feld und der Regel, die jeder verletzt, oder Kein _invoice-Block, mit _invoice-Block hinzufügen, das einen Block mit Platzhaltern einfügt. Die Statusleiste nennt die Art der E-Rechnung, die die Vorlage erzeugt. Speichern und veröffentlichen Sie die Version, wie bei jeder anderen Einstellung.

In einem Plan ohne E-Rechnungen lässt sich der Schalter nicht einschalten, es sei denn, die Test-Renderings des Plans erzeugen welche (im Free-Plan ist das so, siehe Pläne und Einheiten). Eine Vorlage, die schon eine festlegt, etwa eine Kopie des Beispiels, zeigt den Schalter eingeschaltet, und Sie können ihn ausschalten, um gewöhnliche PDFs zu rendern.

Bildvorlagen haben keinen solchen Abschnitt, denn eine E-Rechnung ist ein PDF. Word- und PowerPoint-Vorlagen haben auf ihrer Seite ebenfalls keinen: Legen Sie die E-Rechnung in ihren Einstellungen über die Vorlagen-API oder die settings.json des Projekts fest, oder verlangen Sie sie pro Anfrage.

In einem Projekt ist die Festlegung der Schlüssel einvoice der settings.json:

{
"einvoice": { "profile": "en16931", "flavour": "zugferd" }
}

In der Anfrage​

curl https://api-eu.formfeed.dev/v1/renders \
-H "Authorization: Bearer $FORMFEED_API_KEY" \
-H "Idempotency-Key: invoice-RE-2026-0001" \
-H "Content-Type: application/json" \
-d '{
"template": "invoice",
"data": {
"_invoice": {
"number": "RE-2026-0001",
"issue_date": "2026-01-15",
"type_code": "380",
"currency": "EUR",
"seller": {
"name": "Fennlor Studio GmbH",
"vat_id": "DE000000000",
"address": { "street": "Musterstraße 1", "postcode": "12345", "city": "Musterstadt", "country": "DE" },
"contact": { "name": "Erika Mustermann", "email": "rechnung@fennlor.example", "phone": "+49 30 0000000" }
},
"buyer": {
"name": "Olvarest GmbH",
"address": { "street": "Beispielweg 2", "postcode": "54321", "city": "Beispielstadt", "country": "DE" }
},
"delivery": { "date": "2026-01-15" },
"lines": [
{ "id": "1", "name": "Consulting", "quantity": 8, "unit_code": "HUR", "net_price": 120, "net_amount": 960, "tax": { "category": "S", "rate": 19 } }
],
"tax": { "breakdown": [{ "category": "S", "rate": 19, "basis": 960, "amount": 182.4 }] },
"totals": { "line_net": 960, "tax_basis": 960, "tax_total": 182.4, "grand": 1142.4, "due": 1142.4 },
"payment": { "means_code": "58", "iban": "DE36000000000000000000", "reference": "RE-2026-0001", "terms": "Zahlbar innerhalb von 14 Tagen ohne Abzug", "due_date": "2026-01-29" }
}
},
"post": { "einvoice": { "profile": "en16931", "flavour": "zugferd" } }
}'

Die Antwort ist das Rendering, mit dem Bericht in einvoice. Bei einer Vorlage, die selbst eine E-Rechnung festlegt, lassen Sie post weg: Der _invoice-Block in data ist alles, was die Anfrage braucht.

  • Asynchrone Renderings und Batches nehmen dieselben Felder. Ein Batch reiht nichts ein, solange nicht jeder Eintrag, der eine E-Rechnung erzeugt, auch eine erzeugen kann; das Problem nennt den ersten Eintrag, der es nicht kann, in index.

  • post.einvoice: false schaltet die Festlegung einer Vorlage für eine Anfrage ab, zum Beispiel für ein gewöhnliches PDF mit Passwort:

    { "template": "invoice", "data": { … }, "post": { "einvoice": false, "password": { "user": "open-sesame" } } }
  • Ad-hoc-html nimmt die Rechnung ebenfalls aus data._invoice. Ohne engine wird das HTML unverändert gedruckt, und data enthält nichts außer dem Block:

    { "html": "<h1>Rechnung RE-2026-0001</h1> …", "data": { "_invoice": { … } }, "post": { "einvoice": {} } }
  • Ein Rendering mit url funktioniert genauso: Die Seite unter der Adresse wird unverändert gedruckt, die Rechnung kommt aus data._invoice, und die Sichtprüfung liest den Text dieser Seite:

    { "url": "https://invoices.example/RE-2026-0001", "data": { "_invoice": { … } }, "post": { "einvoice": {} } }

Optionen​

Dieselben vier Optionen sind die Felder von post.einvoice, von settings.einvoice und des Abschnitts E-Rechnung im Editor. Jede hat einen Standardwert, {} verlangt also eine Factur-X-Rechnung im Profil EN 16931.

OptionWerteStandardBedeutung
profileen16931, basicen16931en16931 trägt jedes Feld der europäischen Norm. basic ist das kleinste Profil, das für sich allein eine Rechnung ist; für eine Rechnung zwischen zwei französischen Unternehmen nimmt Frankreich es nicht an.
flavourfactur-x, zugferdfactur-xDer Name, unter dem die Rechnung läuft. ZUGFeRD und Factur-X sind eine Spezifikation unter zwei Namen, und die Datei ist dieselbe: Das eingebettete XML heißt in beiden Fällen factur-x.xml. Die Wahl bestimmt den Namen und die Version, die das Rendering meldet, Factur-X 1.09 oder ZUGFeRD 2.5.
xmlembedded, bothembeddedboth speichert das XML zusätzlich als eigene Datei neben dem PDF.
display_checkwarn, strictwarnWas passiert, wenn das PDF einen Wert des XML nicht zeigt: warn meldet es, strict lässt das Rendering fehlschlagen. Siehe Die Sichtprüfung.
  • Groß- und Kleinschreibung und Leerzeichen am Rand spielen bei profile und flavour keine Rolle. Ein Profil oder ein flavour außerhalb dieser Werte beantwortet die API mit 422 einvoice_profile_unsupported; dazu gehören minimum, basic-wl, extended und xrechnung.
  • Eine Option, die es nicht gibt, oder ein Wert von xml oder display_check außerhalb seiner Liste beantwortet die API mit 400 invalid_request.
  • In basic lässt das XML weg, wofür dieses Profil keinen Platz hat: den contact von Verkäufer und Käufer, seller.legal_info, bei einer Position description, seller_item_id, buyer_item_id, order_line_reference und buyer_accounting_reference sowie payment.bic und payment.account_name. Ein totals.rounding ungleich 0 wird in basic abgelehnt. Im Profil basic ausgelassen nennt sie mit ihren Geschäftsbegriffen.
  • Eine Rechnung zwischen zwei französischen Unternehmen wird in basic mit 422 einvoice_data_invalid abgelehnt, weil Frankreichs Reform nur die Profile EN 16931 und EXTENDED-CTC-FR annimmt. Siehe Französische Inlandsrechnungen.
  • Die Ebenen werden Feld für Feld zusammengeführt. Eine Vorlage, die { "flavour": "zugferd", "display_check": "strict" } festlegt, und eine Anfrage mit "post": { "einvoice": { "xml": "both" } } ergeben eine ZUGFeRD-Rechnung im Profil EN 16931, mit strenger Sichtprüfung und dem XML neben dem PDF.

Der _invoice-Block​

_invoice steht auf der obersten Ebene von data, neben allem, was die Vorlage sonst verwendet. Dies ist der Block der Anfrage oben; denselben fügt _invoice-Block hinzufügen im Editor ein (dort mit dem heutigen Datum als issue_date und dem Fälligkeitsdatum 14 Tage später):

{
"_invoice": {
"number": "RE-2026-0001",
"issue_date": "2026-01-15",
"type_code": "380",
"currency": "EUR",
"seller": {
"name": "Fennlor Studio GmbH",
"vat_id": "DE000000000",
"address": {
"street": "Musterstraße 1",
"postcode": "12345",
"city": "Musterstadt",
"country": "DE"
},
"contact": {
"name": "Erika Mustermann",
"email": "rechnung@fennlor.example",
"phone": "+49 30 0000000"
}
},
"buyer": {
"name": "Olvarest GmbH",
"address": {
"street": "Beispielweg 2",
"postcode": "54321",
"city": "Beispielstadt",
"country": "DE"
}
},
"delivery": { "date": "2026-01-15" },
"lines": [
{
"id": "1",
"name": "Consulting",
"quantity": 8,
"unit_code": "HUR",
"net_price": 120,
"net_amount": 960,
"tax": { "category": "S", "rate": 19 }
}
],
"tax": {
"breakdown": [
{ "category": "S", "rate": 19, "basis": 960, "amount": 182.4 }
]
},
"totals": {
"line_net": 960,
"tax_basis": 960,
"tax_total": 182.4,
"grand": 1142.4,
"due": 1142.4
},
"payment": {
"means_code": "58",
"iban": "DE36000000000000000000",
"reference": "RE-2026-0001",
"terms": "Zahlbar innerhalb von 14 Tagen ohne Abzug",
"due_date": "2026-01-29"
}
}
}

Was für jedes Feld gilt:

  • Zahlen sind JSON-Zahlen oder dasselbe als Text (1142.4 oder "1142.40"). Ein Geldbetrag hat höchstens 2 Nachkommastellen, eine Menge oder ein Einzelpreis höchstens 6, ein Satz oder ein Prozentwert höchstens 4. Mehr Nachkommastellen sind ein Befund; es wird nichts für Sie gerundet. Eine JSON-Zahl wird mit fünfzehn signifikanten Stellen gelesen, 0.30000000000000004 zählt also als 0.3; eine Zahl als Text wird genommen, wie sie geschrieben ist.
  • Textfelder dürfen nicht leer sein und nicht nur aus Leerzeichen bestehen. Lassen Sie das Feld dann weg.
  • Datumsangaben haben die Form YYYY-MM-DD und müssen im Kalender existieren.
  • Codes (currency, address.country, unit_code, payment.means_code, type_code) müssen in ihrer Codeliste stehen, in der Fassung, die der Validator verwendet; Groß- und Kleinschreibung spielen keine Rolle.
  • Kennungen (id, legal_registration, electronic_address, standard_item_id) sind eine Zeichenkette oder ein Objekt { "value": "…", "scheme": "…" }, das das Schema nennt, zu dem der Wert gehört.
  • Unbekannte Felder werden verworfen, nicht abgelehnt. Die Vorlage liest _invoice auch für die Anzeige; Daten, die nur die Seite braucht, dürfen also im Block stehen.

Die Tabellen nennen den Geschäftsbegriff (BT) oder die Gruppe (BG) der EN 16931, die ein Feld trägt. Abdeckung der E-Rechnung führt alle Begriffe in der umgekehrten Richtung auf, und die, die der Block nicht trägt.

Wie der Block geprüft wird​

Bevor etwas gerendert oder gezählt wird, wird der Block an den Regeln der Tabellen unten gemessen, in drei Stufen:

  1. Die Form: Jedes Pflichtfeld ist da, mit dem richtigen Typ.
  2. Die Werte: Nachkommastellen, Datumsangaben, Codes, die Prüfziffern einer IBAN, das Länderkürzel am Anfang einer USt-IdNr.
  3. Die Regeln der EN 16931: Die Summen gehen auf, die Umsatzsteueraufschlüsselung passt zu den Positionen, jede Umsatzsteuerkategorie hat, was sie verlangt, die Zahlungsangaben sind vollständig, und bei einer Rechnung zwischen zwei französischen Unternehmen ist da, was Frankreich verlangt.

Eine Stufe wird erst geprüft, wenn die vorige bestanden hat; einem Block, dem ein Feld fehlt, wird also noch nicht gesagt, dass seine Summen nicht aufgehen. Einen Block, der nicht besteht, beantwortet die API mit 422 einvoice_data_invalid. errors nennt jeden Befund der Stufe, jeden mit dem Feld (path, ab data._invoice, Listeneinträge ab 0 gezählt), seiner message und, wo eine gilt, der rule; detail wiederholt den ersten:

{
"type": "https://docs.formfeed.dev/errors/einvoice-data-invalid",
"title": "E-invoice data invalid",
"status": 422,
"code": "einvoice_data_invalid",
"detail": "_invoice.totals.due is 1000.00, but grand less prepaid plus rounding is 1142.40 (BR-CO-16)",
"errors": [
{
"path": "data._invoice.totals.due",
"message": "_invoice.totals.due is 1000.00, but grand less prepaid plus rounding is 1142.40 (BR-CO-16)",
"rule": "BR-CO-16"
}
]
}

Die Karte Rechnungsdaten im Editor, formfeed validate und formfeed einvoice führen dieselbe Prüfung offline aus. Nach dem Rendern misst der Validator die fertige Datei am vollständigen Regelwerk des Profils, das mehr finden kann; siehe Was zurückkommt.

Dokument​

FeldBegriffPflichtBedeutung
numberBT-1jaDie Rechnungsnummer.
issue_dateBT-2jaDas Rechnungsdatum.
type_codeBT-3neinDie Art des Dokuments, ein Code aus UNTDID 1001, als Text oder als Zahl: 380 Rechnung (der Standard), 381 Gutschrift (credit note), 384 korrigierte Rechnung, 389 selbst ausgestellte Rechnung (self-billed invoice).
currencyBT-5jaDie Währung der Rechnung, ISO 4217 (EUR).
accounting_currencyBT-6neinDie Währung, in der die Umsatzsteuer gebucht wird, wenn die Rechnung auf eine andere lautet. Gehört zu totals.tax_total_accounting: Geben Sie beide an oder keines (BR-53).
buyer_referenceBT-10neinDie Leitweg-Angabe des Käufers. Die Leitweg-ID einer deutschen Behörde steht hier.
order_referenceBT-13neinDie Nummer der Bestellung des Käufers.
contract_referenceBT-12neinDie Nummer des Vertrags.
noteBT-22neinEine Bemerkung zur Rechnung, als freier Text. Sie wird die erste Bemerkung, ohne Betreffcode.
notes[]BT-21, BT-22je nachdemWeitere Bemerkungen, jede mit text und optional subject_code (UNTDID 4451). Drei davon sind Pflicht bei französischen Inlandsrechnungen.
periodBG-14 (BT-73, BT-74)neinDer Abrechnungszeitraum: start, end oder beides. Er darf nicht vor seinem Beginn enden (BR-29).
preceding_invoices[]BG-3neinDie Rechnungen, auf die sich eine Gutschrift oder eine Korrektur bezieht: number (BT-25, in jedem Eintrag Pflicht) und issue_date (BT-26).
operation, operation_codeBT-23je nachdemPflicht bei französischen Inlandsrechnungen.

Verkäufer und Käufer​

seller und buyer nehmen dieselben Felder; wo zwei Begriffe genannt sind, ist der erste der des Verkäufers.

FeldBegriffPflichtBedeutung
nameBT-27, BT-44jaDer Name des Unternehmens.
trading_nameBT-28, BT-45neinDer Name, unter dem das Unternehmen auftritt, wenn er abweicht.
idBT-29, BT-46neinEine Kennung der Partei.
legal_registrationBT-30, BT-47neinDer Registereintrag: eine Handelsregisternummer, eine SIREN.
vat_idBT-31, BT-48je nachdemDie Umsatzsteuer-Identifikationsnummer. Sie beginnt mit ihrem Ländercode, wie in DE000000000 (BR-CO-09; EL für Griechenland); Leerzeichen werden entfernt. Ob sie Pflicht ist, hängt von den Umsatzsteuerkategorien ab.
address.countryBT-40, BT-55jaDas Land, ISO 3166-1 mit zwei Buchstaben (DE).
address.street, .street2, .street3BT-35, BT-36, BT-162; BT-50, BT-51, BT-163neinDie Zeilen der Straßenanschrift.
address.postcode, address.cityBT-38, BT-37; BT-53, BT-52neinDie Postleitzahl und der Ort.
address.subdivisionBT-39, BT-54neinDie Region oder Provinz.
contact.name, .phone, .emailBG-6, BG-9neinWen man zur Rechnung fragt: ein Name, der einer Person oder einer Abteilung. In basic ausgelassen.
electronic_addressBT-34, BT-49je nachdemWo die Partei elektronische Rechnungen empfängt. Eine E-Mail-Adresse als Zeichenkette (sie erhält das Schema EM), oder ein Objekt, dessen scheme ein Code der EAS-Liste ist, wie in { "value": "000000000", "scheme": "0225" }. Jede andere Zeichenkette wird abgelehnt, weil ihr Schema fehlt. Pflicht für beide Parteien einer französischen Inlandsrechnung.

Nur der Verkäufer hat:

FeldBegriffPflichtBedeutung
seller.tax_numberBT-32je nachdemDie Steuernummer des Verkäufers, wenn es keine USt-IdNr. gibt. Ob sie Pflicht ist, hängt von den Umsatzsteuerkategorien ab.
seller.legal_infoBT-33neinWeitere rechtliche Angaben, die die Rechnung nennen muss: Registergericht, Kapital. In basic ausgelassen.
seller.vat_on_debitsBT-8je nachdemPflicht bei französischen Inlandsrechnungen.

Nur der Käufer hat buyer.siren (BT-47), siehe französische Inlandsrechnungen.

Der Verkäufer braucht mindestens eines von vat_id, legal_registration und id (BR-CO-26). Welche Steuerkennungen die Prüfung darüber hinaus verlangt, hängt von den Umsatzsteuerkategorien ab, die die Rechnung verwendet.

Lieferung​

FeldBegriffPflichtBedeutung
delivery.dateBT-72neinDas Datum der Lieferung.
delivery.nameBT-70neinDer Name der Partei, an die geliefert wurde.
delivery.addressBG-15neinDie Lieferanschrift, mit den Feldern der Anschrift einer Partei (BT-75 bis BT-80, BT-165). country (BT-80) ist Pflicht, sobald es eine Anschrift gibt.

Eine Rechnung ohne delivery ist gültig, und ihr Bericht trägt eine Warnung, PEPPOL-EN16931-R008 (ein leeres Element): Die Syntax verlangt das Lieferelement, und es ist leer, wenn der Block keine Lieferung nennt.

Positionen​

lines[] (BG-25) hat mindestens einen Eintrag.

FeldBegriffPflichtBedeutung
idBT-126jaDie Kennung der Position, als Text oder als Zahl.
nameBT-153jaDer Name des Artikels.
descriptionBT-154neinEine längere Beschreibung des Artikels. In basic ausgelassen.
quantityBT-129jaDie berechnete Menge, höchstens 6 Nachkommastellen. Eine Gutschrift ist eine negative Menge.
unit_codeBT-130, BT-150neinDie Einheit, ein Code der UN/ECE-Empfehlung 20 oder 21: C62 ein Stück (der Standard), HUR eine Stunde, DAY ein Tag, KGM ein Kilogramm. Ein Wort wie hours wird abgelehnt (BR-CL-23); bei den gängigen nennt der Befund den gemeinten Code.
net_priceBT-146jaDer Nettopreis einer Einheit, höchstens 6 Nachkommastellen. Er darf nicht negativ sein (BR-27).
price_base_quantityBT-149neinDie Menge, für die der Preis gilt, wenn es nicht eine Einheit ist.
net_amountBT-131jaDer Nettobetrag der Position: Menge mal Preis (geteilt durch price_base_quantity, wo es eine gibt), abzüglich der Nachlässe der Position, zuzüglich ihrer Zuschläge. Die Prüfung vor dem Rendern rechnet ihn nicht nach; die Summen werden aus ihm gebildet.
tax.categoryBT-151jaDie Umsatzsteuerkategorie: S, Z, E, AE, K, G oder O.
tax.rateBT-152je nachdemDer Umsatzsteuersatz in Prozent, 19 für 19 %. Pflicht für jede Kategorie außer O.
periodBT-134, BT-135neinDer Zeitraum, den die Position abdeckt: start, end oder beides (BR-30).
allowances[], charges[]BG-27, BG-28neinNachlässe und Zuschläge der Position: amount (in jedem Eintrag Pflicht), reason, reason_code, base_amount, percent, wie beim Dokument.
buyer_accounting_referenceBT-133neinDie Buchungsreferenz des Käufers für die Position. In basic ausgelassen.
noteBT-127neinEine Bemerkung zur Position.
seller_item_idBT-155neinDie Artikelnummer des Verkäufers. In basic ausgelassen.
buyer_item_idBT-156neinDie Artikelnummer des Käufers. In basic ausgelassen.
standard_item_idBT-157neinEine standardisierte Kennung des Artikels, als Objekt mit ihrem scheme (BR-64): { "value": "…", "scheme": "0160" } für eine GTIN.
order_line_referenceBT-132neinDie Position der Bestellung des Käufers, auf die diese Position antwortet. In basic ausgelassen.

Nachlässe und Zuschläge des Dokuments​

allowances[] und charges[] auf der obersten Ebene des Blocks (BG-20, BG-21) gelten für die ganze Rechnung. Die Nachlässe und Zuschläge einer Position nehmen dieselben Felder ohne tax.

FeldBegriffPflichtBedeutung
amountBT-92, BT-99jaDer Betrag des Nachlasses oder Zuschlags, ohne Umsatzsteuer.
tax.categoryBT-95, BT-102jaDie Umsatzsteuerkategorie, unter die der Nachlass oder Zuschlag fällt, wie bei einer Position. Nicht bei den Nachlässen und Zuschlägen einer Position, die unter die der Position fallen.
tax.rateBT-96, BT-103je nachdemDer Umsatzsteuersatz, wie bei einer Position: Pflicht für jede Kategorie außer O.
reasonBT-97, BT-104je nachdemDer Grund, als Text. Die EN 16931 verlangt bei jedem Nachlass und Zuschlag reason oder reason_code; die Prüfung vor dem Rendern verlangt es nicht, der Validator schon.
reason_codeBT-98, BT-105je nachdemDer Grund als Code: UNTDID 5189 für einen Nachlass (95 ein Rabatt), UNTDID 7161 für einen Zuschlag (FC Fracht).
base_amount, percentBT-93, BT-94; BT-100, BT-101neinDer Betrag, von dem der Nachlass oder Zuschlag ein Prozentsatz ist, und dieser Prozentsatz.

Wie die Beträge zusammenpassen, mit einem Nachlass einer Position, einem Nachlass und einem Zuschlag des Dokuments, alle zu 19 %:

{
"lines": [
{
"id": "1",
"name": "Etiketten 100 × 150 mm",
"quantity": 10,
"unit_code": "XRO",
"net_price": 18,
"net_amount": 162,
"tax": { "category": "S", "rate": 19 },
"allowances": [
{
"amount": 18,
"base_amount": 180,
"percent": 10,
"reason": "Mengenrabatt",
"reason_code": "95"
}
]
},
{
"id": "2",
"name": "Thermotransferband",
"quantity": 4,
"net_price": 12.5,
"net_amount": 50,
"tax": { "category": "S", "rate": 19 }
}
],
"allowances": [
{
"amount": 10.6,
"base_amount": 212,
"percent": 5,
"reason": "Treuerabatt",
"reason_code": "95",
"tax": { "category": "S", "rate": 19 }
}
],
"charges": [
{
"amount": 9.9,
"reason": "Versand",
"reason_code": "FC",
"tax": { "category": "S", "rate": 19 }
}
],
"tax": {
"breakdown": [
{ "category": "S", "rate": 19, "basis": 211.3, "amount": 40.15 }
]
},
"totals": {
"line_net": 212,
"allowances": 10.6,
"charges": 9.9,
"tax_basis": 211.3,
"tax_total": 40.15,
"grand": 251.45,
"prepaid": 50,
"due": 201.45
}
}

Der Nachlass der Position steckt im net_amount der ersten Position (10 × 18 − 18 = 162). Nachlass und Zuschlag des Dokuments nicht: Sie gehen in die basis der Aufschlüsselung und in die Summen ein (212 − 10,60 + 9,90 = 211,30).

Umsatzsteueraufschlüsselung​

tax.breakdown[] (BG-23) hat einen Eintrag für jede Kombination aus Kategorie und Satz, die die Positionen, Nachlässe und Zuschläge verwenden, und keinen Eintrag doppelt.

FeldBegriffPflichtBedeutung
categoryBT-118jaDie Umsatzsteuerkategorie.
rateBT-119je nachdemDer Umsatzsteuersatz in Prozent, wie bei einer Position.
basisBT-116jaDer Betrag, auf den die Umsatzsteuer berechnet wird: die net_amount der Positionen dieser Kategorie und dieses Satzes, zuzüglich der Zuschläge und abzüglich der Nachlässe des Dokuments in dieser Kategorie und zu diesem Satz.
amountBT-117jaDer Umsatzsteuerbetrag. Weicht er von Satz mal Basis um mehr ab, als sich durch Runden je Position erklären lässt (ein halber Cent je Position, Nachlass und Zuschlag zu diesem Satz), wird der Block abgelehnt (BR-CO-17).
exemption_reasonBT-120je nachdemWarum keine Umsatzsteuer berechnet wird, als Text. Eines der beiden Felder für den Grund ist Pflicht für jede Kategorie außer S und Z, die keines nehmen.
exemption_reason_codeBT-121je nachdemDasselbe als VATEX-Code, etwa VATEX-EU-AE.

Umsatzsteuerkategorien​

Die Kategorien sind die Codes aus UNCL 5305, wie die EN 16931 sie verwendet. Welche Kategorie und welcher Satz für einen Umsatz gelten, ist eine steuerliche Frage. Formfeed beantwortet sie nicht und nimmt die Werte, die Sie senden. Es prüft nur, ob der Block zu der Kategorie passt, die Sie angeben:

KategorierateIn der AufschlüsselungVerkäufer und Käufer
Süber 0kein BefreiungsgrundVerkäufer: vat_id oder tax_number
Z0Betrag 0, kein BefreiungsgrundVerkäufer: vat_id oder tax_number
E0Betrag 0, exemption_reason oder exemption_reason_codeVerkäufer: vat_id oder tax_number
AE0Betrag 0, exemption_reason oder exemption_reason_codeVerkäufer: vat_id oder tax_number; Käufer: vat_id oder legal_registration
K0Betrag 0, exemption_reason oder exemption_reason_codeVerkäufer: vat_id; Käufer: vat_id. Die Rechnung nennt außerdem delivery.date oder period sowie delivery.address.
G0Betrag 0, exemption_reason oder exemption_reason_codeVerkäufer: vat_id
OentfälltBetrag 0, exemption_reason oder exemption_reason_code; keine andere Kategorie in der Rechnungweder Verkäufer noch Käufer nennen eine vat_id

Die Regeln, die ein Befund nennt, folgen der Kategorie: BR-S-…, BR-Z-…, BR-E-…, BR-AE-…, BR-IC-… für K, BR-G-… und BR-O-….

Summen​

totals (BG-22). Jede Summe muss auf den Cent dem entsprechen, als was die Norm sie definiert. allowances, charges, prepaid und rounding zählen als 0, wenn sie fehlen, und werden trotzdem geprüft: Eine Rechnung mit Nachlässen des Dokuments muss totals.allowances angeben.

FeldBegriffPflichtBedeutung
line_netBT-106jaDie Summe der net_amount der Positionen (BR-CO-10).
allowancesBT-107neinDie Summe der Nachlässe des Dokuments (BR-CO-11).
chargesBT-108neinDie Summe der Zuschläge des Dokuments (BR-CO-12).
tax_basisBT-109jaDie Nettosumme: line_net abzüglich allowances zuzüglich charges (BR-CO-13).
tax_totalBT-110jaDie Umsatzsteuer: die Summe der Beträge der Aufschlüsselung (BR-CO-14).
tax_total_accountingBT-111neinDie Umsatzsteuer in der accounting_currency (BR-53).
grandBT-112jaDer Gesamtbetrag mit Umsatzsteuer: tax_basis zuzüglich tax_total (BR-CO-15).
prepaidBT-113neinWas bereits gezahlt wurde.
roundingBT-114neinEin Rundungsbetrag. In basic abgelehnt, wenn er nicht 0 ist.
dueBT-115jaDer Zahlbetrag: grand abzüglich prepaid zuzüglich rounding (BR-CO-16).

Zahlung​

payment ist als Ganzes optional, aber eine Rechnung mit einem Zahlbetrag über 0 nennt due_date oder terms (BR-CO-25).

FeldBegriffPflichtBedeutung
means_codeBT-81je nachdemWie die Rechnung bezahlt wird, ein Code aus UNTDID 4461, als Text oder als Zahl: 58 SEPA-Überweisung, 59 SEPA-Lastschrift, 30 Überweisung, 48 Karte. Pflicht, sobald iban, bic, account_name, mandate_id oder debited_iban angegeben ist (BR-49).
ibanBT-84je nachdemDas Konto, auf das zu zahlen ist. Pflicht bei den Codes 30 und 58 (BR-61). Die Prüfziffern werden geprüft.
bicBT-86neinDie BIC dieses Kontos. In basic ausgelassen.
account_nameBT-85neinDer Name des Kontos. In basic ausgelassen.
referenceBT-83neinWas der Zahlende bei der Zahlung angibt.
termsBT-20je nachdemDie Zahlungsbedingungen, als Text. Eines von terms und due_date ist Pflicht, wenn totals.due über 0 liegt.
due_dateBT-9je nachdemDas Datum, an dem die Zahlung fällig ist.
mandate_idBT-89neinLastschrift: das Mandat.
creditor_idBT-90neinLastschrift: die Gläubiger-Identifikation.
debited_ibanBT-91neinLastschrift: das Konto, das belastet wird. Die Prüfziffern werden geprüft.

Das XML ist die Rechnung, das PDF muss also zeigen, was darin steht. Der verlässliche Weg ist, in der Vorlage die Werte aus _invoice auszugeben, statt Werte aus anderen Feldern oder Summen, die die Vorlage selbst addiert:

<h1>Rechnung {{ _invoice.number }}</h1>
<p>{{ _invoice.buyer.name }}</p>

<table>
<thead>
<tr>
<th>Leistung</th>
<th>Menge</th>
<th>Preis</th>
<th>Netto</th>
</tr>
</thead>
<tbody>
{% for line in _invoice.lines %}
<tr>
<td>{{ line.name }}</td>
<td>{{ line.quantity }}</td>
<td>{{ line.net_price | money }}</td>
<td>{{ line.net_amount | money }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<p>Netto {{ _invoice.totals.tax_basis | money }}</p>
<p>Umsatzsteuer {{ _invoice.totals.tax_total | money }}</p>
<p>Gesamt {{ _invoice.totals.grand | money }}</p>
<p>Zahlbetrag {{ _invoice.totals.due | money }}</p>

Die Helper formatieren die Werte für den Leser; die Sichtprüfung liest Beträge in beiden Schreibweisen. Das XML hängt weder von der locale noch von Übersetzungen ab: Ein deutsches und ein englisches PDF aus denselben Daten betten dasselbe XML ein.

Das Beispiel E-Rechnung: ZUGFeRD und Factur-X aus einer Vorlage ist eine vollständige Rechnungsvorlage, die so gebaut ist. Vorlagen → Beispiele in der App legt eine Kopie davon in Ihrem Workspace an.

Die Sichtprüfung​

In einer E-Rechnung ist das XML die Rechnung. Nichts zwingt eine Vorlage, die Werte aus _invoice auszugeben: Eine, die ihre eigenen Summen addiert oder die Zahl eines anderen Felds zeigt, rendert ohne Beanstandung, und ein PDF, das andere Rechnungsangaben zeigt, kann als zweite Rechnung gelten. Deshalb liest Formfeed den Text des fertigen PDFs, einschließlich Kopf- und Fußzeilen, und sucht nach dem, was das XML nennt:

BegriffWertGesucht
BT-1numberals Text; Leerzeichen, Zeilenumbrüche, Groß- und Kleinschreibung und die Art des Strichs spielen keine Rolle
BT-109totals.tax_basisals Zahl
BT-110totals.tax_totalals Zahl
BT-112totals.grandals Zahl
BT-115totals.dueals Zahl, wenn er von totals.grand abweicht
BT-117jedes tax.breakdown[].amountals Zahl, wenn die Aufschlüsselung mehr als einen Eintrag hat
  • Eine Zahl gilt in beiden Schreibweisen als gezeigt, 1.234,56 oder 1,234.56. Tausender dürfen auch mit einem Leerzeichen oder einem Apostroph gruppiert sein, und das Vorzeichen wird ignoriert, weil eine Gutschrift negativ ausgeben kann, was ihr XML positiv nennt.
  • Nach Nullbeträgen wird nicht gesucht: Eine Vorlage muss 0,00 nicht ausgeben. Datumsangaben werden nicht verglichen.
  • Das Ergebnis ist einvoice.display: checked nennt die Begriffe, nach denen gesucht wurde, missing die, die der Text nicht zeigt.

Was ein fehlender Wert bewirkt, bestimmt die Option display_check:

  • warn, der Standard: Das Rendering gelingt, und display.missing nennt die Begriffe.
  • strict: Das Rendering schlägt mit 422 einvoice_display_mismatch fehl, und es wird keine Datei ausgeliefert. Das Problem trägt den Bericht in einvoice.

Die Prüfung findet einen Wert, der fehlt, nicht einen falschen, der neben dem richtigen steht. Sie ist ein Netz, kein Beweis: Eine Zahl gilt als gezeigt, wo immer sie im Text steht, und ein Wert, der Teil eines Bilds ist, wird nicht gefunden, weil die Prüfung Text liest.

Der Editor führt dieselbe Prüfung aus, bevor etwas gerendert wird. Bei einer Vorlage, die eine E-Rechnung festlegt, zählen die Vorschauen Fließend und Seiten die Rechnungswerte, die das Dokument zeigt, und die Liste Probleme nennt jeden, der fehlt. formfeed render gibt das Ergebnis der Prüfung des Renderings selbst aus.

Französische Inlandsrechnungen​

Ist address.country des Verkäufers und des Käufers jeweils FR, verlangt die Prüfung, was Frankreichs Regeln über die EN 16931 hinaus zur Pflicht machen:

FeldRegelBedeutung
seller.legal_registrationBR-FR-10Die SIREN des Verkäufers (BT-30), neun Ziffern.
buyer.sirenBR-FR-11Die SIREN des Käufers, neun Ziffern. Sie wird als Registereintrag des Käufers (BT-47) mit dem Schema 0002 geschrieben. Eine SIREN in buyer.legal_registration zählt ebenfalls; sind beide angegeben, müssen sie übereinstimmen.
operationBR-FR-08Was verkauft wurde: goods, services oder mixed. Daraus wird der Abrechnungsrahmen B1, S1 oder M1 im Geschäftsprozess (BT-23). Für einen anderen Rahmen senden Sie seinen Code als operation_code, der Vorrang vor operation hat: B1, S1, M1, B2, S2, M2, S3, B4, S4, M4, S5, S6, B7, S7, B8, S8 oder M8.
seller.vat_on_debitstrue, wenn der Verkäufer die Umsatzsteuer mit der Rechnungsstellung schuldet, false, wenn sie mit der Zahlung geschuldet wird. true schreibt den Code für „Datum der Rechnung“ (BT-8) in jede Umsatzsteueraufschlüsselung; false schreibt nichts.
notes[]BR-FR-05Die gesetzlichen Hinweise, jeder als eigene Bemerkung mit seinem subject_code (BT-21): PMT für die Pauschale von 40 € für Beitreibungskosten, PMD für die Verzugsstrafen und AAB für das Skonto bei vorzeitiger Zahlung oder dass keines gewährt wird.
seller.electronic_address, buyer.electronic_addressBR-FR-13, BR-FR-12Die elektronischen Adressen von Verkäufer (BT-34) und Käufer (BT-49), jede mit ihrem Schema.

Das sind die Felder, die Sie im Block oben ergänzen oder ersetzen. Mit ihnen und mit französischen Anschriften beider Parteien besteht der Block die Prüfung in en16931:

{
"operation": "services",
"notes": [
{
"subject_code": "PMT",
"text": "En cas de retard de paiement, une indemnité forfaitaire pour frais de recouvrement de 40 € sera exigée."
},
{
"subject_code": "PMD",
"text": "En cas de retard de paiement, des pénalités seront appliquées au taux de trois fois le taux d'intérêt légal."
},
{
"subject_code": "AAB",
"text": "Aucun escompte n'est accordé pour paiement anticipé."
}
],
"seller": {
"name": "Fennlor Studio SAS",
"legal_registration": { "value": "000000000", "scheme": "0002" },
"vat_id": "FR00000000000",
"vat_on_debits": true,
"address": {
"street": "1 rue du Modèle",
"postcode": "99000",
"city": "Villemodèle",
"country": "FR"
},
"electronic_address": { "value": "000000000", "scheme": "0225" }
},
"buyer": {
"name": "Olvarest SARL",
"siren": "000000018",
"address": {
"street": "2 avenue de l'Exemple",
"postcode": "99100",
"city": "Exempleville",
"country": "FR"
},
"electronic_address": { "value": "000000018", "scheme": "0225" }
}
}
  • Schreiben Sie eine solche Rechnung im Profil en16931. Frankreichs Reform nimmt nur die Profile EN 16931 und EXTENDED-CTC-FR an, deshalb wird basic für sie mit 422 einvoice_data_invalid abgelehnt.
  • Der Validator prüft die Datei danach gegen Frankreichs Geschäftsregeln als Ganzes, die BR-FR-Regeln der Norm AFNOR XP Z12-012, in der Fassung, die Mustang 2.26.0 mitbringt (1.3.0 vom 16. Februar 2026). Was gegen sie verstößt, meldet er als Warnung in einvoice.validation.messages und liefert die Datei trotzdem aus; deshalb verlangt die Prüfung die Pflichtangaben oben schon vor dem Rendering. Sehen Sie dort nach weiteren BR-FR-Befunden, bevor die Rechnung an Ihre Plattform geht.
  • Die Lieferanschrift steht, wenn sie von der des Käufers abweicht, in delivery.address, mit delivery.name und delivery.date. Die Prüfung verlangt sie nicht.
  • Nichts davon wird verlangt, wenn nur einer der beiden in Frankreich sitzt.

Formfeed erzeugt die Datei. Sie über eine plateforme agréée zu versenden, ist Ihre Aufgabe oder die Ihrer Plattform, siehe Was Formfeed nicht tut.

Was zurückkommt​

Ein Rendering, das eine E-Rechnung erzeugt hat, trägt den Bericht in einvoice. Bei jedem anderen Rendering ist das Feld null. Das Beispiel zeigt die Felder, um die es hier geht; das Rendering-Objekt hat die übrigen.

{
"id": "rnd_7da09ab6cd9946b798c187c2a9350852",
"status": "succeeded",
"output": "pdf",
"page_count": 1,
"units": 2,
"einvoice": {
"profile": "en16931",
"flavour": "factur-x",
"spec_version": "1.09",
"xml_url": null,
"validation": {
"valid": true,
"schematron": "Factur-X 1.09.2 (Mustang 2.26.0)",
"pdfa": "PDF/A-3b",
"messages": [],
"id": "6f2c7e9a-1d4b-4c3e-8a5f-2b7d9e0c1a34",
"versions": {
"mustang": "2.26.0",
"verapdf": "1.30.2",
"pdfbox": "3.0.8"
},
"xml_sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
"pdf_sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
},
"display": {
"checked": ["BT-1", "BT-109", "BT-110", "BT-112"],
"missing": []
}
}
}
FeldBedeutung
profile, flavourWas erzeugt wurde, mit allen Standardwerten.
spec_versionDie Version der Spezifikation, für die die Datei geschrieben und validiert wurde, unter dem Namen aus flavour: 1.09 für Factur-X, 2.5 für ZUGFeRD.
xml_urlEin Link zum XML, wenn das Rendering xml: both verlangt hat und die Datei noch gespeichert ist; sonst null. Er entsteht wie download_url: signiert, oder mit access: "public" der öffentliche Link. Das XML steckt in jedem Fall im PDF.
validationWas der Validator gesagt hat. null nur, wenn das Rendering fehlschlug, bevor der Validator lief.
validation.validtrue, wenn kein Befund ein Fehler ist. Ein Rendering gelingt nur mit einer gültigen Datei.
validation.schematronDas Regelwerk, an dem das XML gemessen wurde, wie der Validator es nennt.
validation.pdfaPDF/A-3b, sobald die Datei daran geprüft wurde; null, wenn die Validierung beim XML geendet hat.
validation.messages[]Die Befunde, höchstens 50, Fehler zuerst. Jeder hat part (xml oder pdf), severity (error oder warning), rule (eine Regel der EN 16931 wie BR-CO-25, eine Regel der Syntax wie CII-SR-465, ein Code des XML-Schemas wie cvc-… oder eine Klausel von PDF/A wie 6.2.11.4.1-1; null, wo der Validator keine nennt), message und location (ein XPath in das XML, Zeile und Spalte bei einem Befund des XML-Schemas oder das Objekt des PDFs).
validation.truncatedVorhanden und true, wenn es mehr Befunde gab, als messages enthält.
validation.idDie eigene Kennung des Validators für diesen Bericht. Nennen Sie sie, wenn Sie zu einem Rendering fragen.
validation.versionsDie Versionen der Teile des Validators, die die Datei geprüft haben: Mustang, veraPDF und PDFBox. Validator und Regeln nennt die Versionen im Einsatz.
validation.xml_sha256, validation.pdf_sha256SHA-256 des geprüften XML und des geprüften PDF. Bei einem erfolgreichen Rendering ist das PDF die ausgelieferte Datei, derselbe Wert wie output_sha256 des Renderings, und das XML ist das XML darin. So nennt der Bericht genau die Datei, um die es geht, und lässt sich neben der Rechnung als Nachweis der Prüfung aufbewahren. pdf_sha256 ist null, wo der Validator das XML ablehnte, bevor es eine umgewandelte Datei gab.
displayDie Sichtprüfung: checked nennt die Geschäftsbegriffe, nach denen im Text des PDFs gesucht wurde, missing die, die er nicht zeigt. null, wenn das Rendering fehlschlug, bevor die Prüfung lief.
  • GET /v1/renders/{id}, die Liste der Renderings und die Webhook-Ereignisse render.completed und render.failed tragen dasselbe Objekt.
  • Berichte von Renderings vor dem 9. Oktober 2026 haben weder id noch versions noch Prüfsummen.
  • Mit ?output=binary ist die Antwort das PDF selbst. Lesen Sie den Bericht aus GET /v1/renders/{id}, mit der ID aus dem Header X-Render-Id.
  • Ein fehlgeschlagenes Rendering behält seinen Bericht. Lehnt der Validator die Datei ab, ist das Rendering failed, sein einvoice.validation sagt, warum, und display ist null, weil die Sichtprüfung nach dem Validator läuft. Das Problem der Anfrage trägt dasselbe einvoice.
  • In der App hat das Blatt des Renderings im Render-Protokoll einen Abschnitt E-Rechnung mit dem Urteil, den Befunden und dem, was das PDF zeigt. Bericht (JSON) lädt den Bericht als Datei herunter. Ein Echtes Rendering im Editor zeigt denselben Abschnitt unter seinem Ergebnis: Es ist eine echte E-Rechnung, validiert wie ein API-Rendering, kostenlos wie jede Vorschau und ein Test-Rendering mit der Testmarkierung (siehe Pläne und Einheiten).

Das XML speichern​

Mit "xml": "both" (im Editor Das XML als eigene Datei speichern) wird das XML als zweite Datei neben dem PDF gespeichert. Es ist dasselbe XML, das im PDF eingebettet ist.

  • Die Datei trägt den Namen des PDFs mit .xml: Zu invoice-RE-2026-0001.pdf gehört invoice-RE-2026-0001.xml.
  • einvoice.xml_url ist der Link darauf. download_url bleibt der Link zum PDF.
  • Sie wird mit dem PDF aufbewahrt und gelöscht: dieselbe Aufbewahrung, dasselbe expires_in, dasselbe vorzeitige Löschen.
  • Mit eigenem Speicher wird das XML wie das PDF in Ihren Bucket kopiert. Nennt das Rendering mit storage.key sein eigenes Objekt, erhält das XML diesen Schlüssel mit der Endung .xml.

Mit embedded, dem Standard, ist xml_url null, und das XML gibt es nur im PDF. Vorschauen im Editor speichern nichts.

Womit sie sich nicht kombinieren lässt​

  • Ein Passwort. post.password zusammen mit einer E-Rechnung beantwortet die API mit 400 invalid_request und field: "post.password", egal wo die E-Rechnung festgelegt wurde: PDF/A verbietet Verschlüsselung. Für ein verschlüsseltes gewöhnliches PDF aus einer Rechnungsvorlage senden Sie post.einvoice: false.
  • Jede Ausgabe außer PDF. Eine Anfrage, die eine E-Rechnung für eine Bild-, docx- oder pptx-Ausgabe verlangt, beantwortet die API mit 400 invalid_request und field: "post.einvoice". Die eigene Festlegung einer Vorlage wird dort einfach nicht angewendet: Ein Bild aus einer Rechnungsvorlage bleibt ein Bild.
  • Deduplizierung. Eine E-Rechnung wird nie aus dem Cache der Deduplizierung beantwortet; jede Anfrage rendert.
  • Die PDF-Tools danach. Die PDF-Tools merge, watermark und protect nehmen das PDF einer E-Rechnung wie jedes andere PDF, und was sie zurückgeben, ist eine neue Datei, die nie validiert wurde: Eine zusammengeführte Datei trägt kein XML, eine geschützte ist verschlüsselt, und eine mit Wasserzeichen wurde neu gespeichert. Die E-Rechnung ist die Ausgabe des Renderings selbst; versenden und archivieren Sie diese.

post.merge_after und ein Wasserzeichen funktionieren, als Text oder als Bild. Ein Text-Wasserzeichen deckt lateinische, griechische und kyrillische Buchstaben ab, weil seine Schrift in die Datei eingebettet wird; nehmen Sie für andere Schriften ein Bild. Die E-Rechnung ist der letzte Schritt, nach dem Zusammenführen, dem Wasserzeichen und der Testmarkierung; umgewandelt und validiert wird also das Dokument, wie es ausgeliefert wird. Auch PDFs, die Sie anhängen, müssen PDF/A genügen: Eines, dessen Schriften nicht eingebettet sind, lässt das Rendering mit pdfa_conversion_failed fehlschlagen.

Als PDF/UA-1-Datei​

Eine E-Rechnung kann zugleich ein PDF/UA-1-Dokument sein, das Format, nach dem ein Screenreader ein PDF liest. Setzen Sie pdf.ua neben die E-Rechnung, in den Einstellungen der Vorlage oder in der Anfrage, für eine HTML-Vorlage oder für HTML, das Sie senden. In der settings.json einer Vorlage:

settings.json
{
"pdf": {
"ua": true,
"metadata": { "title": "Rechnung {{ _invoice.number }}" }
},
"einvoice": { "profile": "en16931", "flavour": "zugferd" }
}

Das PDF/A-3b behält die Tags der Seite, und die fertige E-Rechnung wird in derselben Anfrage gegen PDF/UA-1 ebenso geprüft wie gegen PDF/A-3b. Das Rendering trägt dann accessibility neben einvoice. Eine Datei, die PDF/UA-1 nicht besteht, lässt das Rendering mit 422 pdfua_validation_failed fehlschlagen, dessen Problem beide Berichte trägt, oder wird mit { "check": "report" } als die gültige E-Rechnung ausgeliefert, die sie ist, ohne die PDF/UA-Kennung. Die Prüfung kostet keine eigene Einheit.

Zwei Dinge gehen damit nicht zusammen: post.merge_after, weil ein Zusammenführen die Tags des Angehängten verwirft, und Word- und PowerPoint-Vorlagen, deren PDF aus einem anderen Konverter kommt. Eine E-Rechnung aus einer Word-Vorlage ist eine E-Rechnung ohne pdf.ua.

Pläne und Einheiten​

Live-E-Rechnungen setzen den Starter-Plan oder höher voraus. Test-Renderings erzeugen E-Rechnungen in jedem Plan, bis zu einer Anzahl pro Tag, jede eine gültige Datei mit der Testmarkierung auf ihren Seiten:

PlanLive-RenderingsTest-Renderings pro Tag
Freeabgelehnt mit 403 forbidden20
Starterja100
Proja500
Businessja2.000
Enterprisejanicht gezählt

In den bezahlten Plänen ist die Zahl pro Tag ein Dreißigstel der monatlichen Einheiten des Plans.

  • Test-Renderings sind Renderings mit einem Test-Schlüssel, Testanfrage senden im API-Tab des Editors und das Echte Rendering im Editor. Jede Test-E-Rechnung trägt die Testmarkierung, in jedem Plan. Live-Renderings werden weder gezählt noch markiert.
  • Gezählt wird für die Organisation, und die Zählung beginnt um Mitternacht UTC neu. Gezählt wird nach allen anderen Prüfungen; eine Anfrage, die aus einem anderen Grund abgelehnt wird, verbraucht also nichts, ein Rendering, das danach fehlschlägt, hat seine Zählung verbraucht. Ein Batch zählt einen Eintrag für jedes Element, das eine E-Rechnung erzeugt, alle oder keinen. Ein Test-Rendering, sobald der Tag aufgebraucht ist, beantwortet die API mit 403 forbidden und "feature": "einvoice", limit, used und resets_at.
  • In einem Plan ohne E-Rechnungen beantwortet die API ein Live-Rendering, das eine erzeugt, mit 403 forbidden und "feature": "einvoice", auch bei einer Vorlage, die eine E-Rechnung festlegt. Ein Rendering kommt nie stattdessen als gewöhnliches PDF zurück. Eine Vorlage, die eine E-Rechnung festlegt, etwa eine Kopie des Beispiels, lässt sich in der Seiteneinrichtung ausschalten, oder pro Anfrage mit post.einvoice: false, und rendert dann gewöhnliche PDFs.
  • Einheiten. Eine E-Rechnung kostet 1 Einheit zusätzlich zu den Einheiten des Renderings. Eine zweiseitige Rechnung kostet 2 Einheiten: 1 für das PDF, 1 für die E-Rechnung. Test-Renderings, Vorschauen und echte Renderings im Editor kosten nichts, ein fehlgeschlagenes Rendering ebenso wenig. Siehe Einheiten.

Fehler​

Bevor etwas gerendert oder gezählt wird, prüft die API eine Anfrage in dieser Reihenfolge: Profil und flavour, die Ausgabe, den Plan, ein Passwort, den _invoice-Block. Die Zählung der Test-E-Rechnungen des Tages kommt zuletzt.

StatusCodeWann
422einvoice_data_invalidDer _invoice-Block fehlt oder verletzt eine Regel, beantwortet, bevor etwas gerendert wird, mit jedem Befund in errors (siehe Wie der Block geprüft wird); oder der Validator hat die fertige Datei abgelehnt, und das Problem trägt den Bericht in einvoice.
422einvoice_profile_unsupportedEin Profil oder flavour, das Formfeed nicht erzeugt: minimum, basic-wl, extended, xrechnung oder ein unbekannter Wert.
422einvoice_display_mismatchMit display_check: "strict" zeigt das PDF einen Wert des XML nicht.
500pdfa_conversion_failedDas PDF ließ sich nicht in ein gültiges PDF/A-3b umwandeln. Die Befunde stehen in einvoice, oder die Meldung des Konverters in reason. Die bekannten Ursachen: eine Schrift, die nicht eingebettet ist, die ein angehängtes PDF mitbringen kann, und eine Schrift, deren eingebettetes Programm nicht zu den Breiten passt, die das PDF nennt; so schreibt der Office-Konverter chinesischen, japanischen und koreanischen Text einer Word- oder PowerPoint-Vorlage. Eine Wiederholung hilft nicht, und asynchrone Renderings werden dafür nicht wiederholt.
503conformance_unavailableDer Dienst, der umwandelt und validiert, ist ausgelastet oder nicht erreichbar, oder E-Rechnungen sind in der Region nicht verfügbar. Wiederholen Sie nach Retry-After; asynchrone Renderings und Batches wiederholen es von selbst.
400invalid_requestEine E-Rechnung zusammen mit einem Passwort, für eine andere Ausgabe als PDF, oder mit einer Option oder einem Wert, den es nicht gibt.
403forbiddenMit "feature": "einvoice". Der Plan enthält keine E-Rechnungen und das Rendering ist ein Live-Rendering, oder die Test-E-Rechnungen des Tages sind aufgebraucht.

Die Umwandlung kann auch mit zwei allgemeinen Codes enden: 422 output_too_large, wenn das PDF zu groß ist, um eine E-Rechnung zu werden, und 504 render_timeout, wenn die Umwandlung nicht rechtzeitig fertig wird. Eine E-Rechnung, die zugleich eine PDF/UA-1-Datei ist, kann außerdem mit pdfua_validation_failed fehlschlagen.

Kommandozeile​

Die CLI prüft und schreibt E-Rechnungen offline, mit dem Code, den auch die API ausführt.

formfeed validate misst den _invoice-Block jedes Datensatzes an den Regeln, für jede Vorlage, deren settings.json eine E-Rechnung festlegt. Ein Befund nennt die Datei, die Zeile und die Spalte, das Feld und die Regel, und der Befehl endet mit 1:

error invoice/data/storno.json:63:7 _invoice.totals.due is 1000.00, but grand less prepaid plus rounding is 1142.40 (BR-CO-16) [einvoice-sum]
1 error(s)

Ein Datensatz ohne den Block und ein Profil, das nicht angeboten wird, sind ebenfalls Fehler. Bei einer Bildvorlage ist die Festlegung eine Warnung, weil eine solche Vorlage nie eine E-Rechnung erzeugt.

formfeed einvoice <slug> schreibt das XML, das ein Rendering einbetten würde, ohne API-Schlüssel:

formfeed einvoice invoice --out out/rechnung.xml
invoice: ZUGFeRD 2.5, EN 16931, RE-2026-0001, 1 line(s), 1142.40 EUR -> out/rechnung.xml
checked offline against the rules the API applies before a render; the official validator runs with the render

--data nimmt den Namen eines Datensatzes oder eine JSON-Datei, --out die Datei, die geschrieben wird (ohne die Option <slug>.xml), und --profile hat Vorrang vor den Einstellungen der Vorlage. Eine Vorlage, die nichts festlegt, erhält die Standardwerte. Ein Block, der eine Regel verletzt, schreibt keine Datei und listet, was nicht stimmt. Das XML wird an den Regeln geprüft, die die API vor einem Rendering anwendet; der Validator selbst läuft mit dem Rendering, nicht hier.

formfeed render <slug> sendet die lokale Vorlage mit dem, was settings.json festlegt, und dem _invoice-Block des Datensatzes, und gibt den Bericht des Renderings aus:

e-invoice ZUGFeRD, EN 16931, specification 2.5
valid rules of the XML (Factur-X 1.09.2 (Mustang 2.26.0)), PDF/A-3b
shown invoice number, net total, total
warn not in the text of the PDF: VAT total
rnd_7da09ab6cd9946b798c187c2a9350852: 1 page(s), 0 unit(s) -> invoice.pdf

Eine lokale Word- oder PowerPoint-Datei rendert als gewöhnliches PDF, mit einer Warnung: Ihre E-Rechnung entsteht, wenn die veröffentlichte Vorlage rendert, was formfeed render --remote tut.

Was Formfeed nicht tut​

Formfeed erzeugt und validiert die Datei. Es übernimmt nicht:

  • Den Versand. Formfeed ist weder ein Peppol-Access-Point noch eine französische plateforme agréée. Sie, Ihre Plattform oder Ihr Access Point stellen die Rechnung zu.
  • Die Archivierung für die gesetzliche Frist. Siehe unten.
  • Die Buchung. Die Buchhaltung bleibt in Ihrem Buchhaltungssystem.
  • Die Umsatzsteuer. Welche Kategorie, welcher Satz und welcher Befreiungsgrund gelten, entscheiden Sie oder Ihre Steuerberatung. Formfeed leistet keine Steuerberatung.
  • Die Signatur. Die Datei trägt keine elektronische Signatur.
  • XRechnung oder UBL. Beides ist nicht verfügbar. Auch die Profile minimum, basic-wl und extended werden nicht angeboten.

Sie stellen die Rechnung aus und stehen für ihren Inhalt und ihre umsatzsteuerliche Behandlung ein. Formfeed steht für das Format ein.

Archivierung und der Bericht​

Formfeed ist kein Archiv. Ausgaben werden nur für die Aufbewahrungsfrist Ihres Plans und Workspace aufbewahrt (1 Tag bei Free, 30 Tage bei Starter, 365 Tage bei Pro; Business setzt keine Grenze, aber eine Einstellung des Workspace oder eine Löschung beendet sie trotzdem). Nichts in Formfeed bewahrt eine Rechnung die Jahre auf, die das Gesetz von Ihnen verlangt, und nichts schützt sie davor, gelöscht zu werden. Archivieren Sie jede Rechnung selbst:

  • Archivieren Sie die ausgelieferte Datei selbst oder die XML-Ausgabe von xml: both. Auf das XML in der Datei kommt es an. Archivieren Sie nie einen Ausdruck, der kein XML hat, und kein PDF, das ein anderes Programm erneut gespeichert hat: Es ist nicht mehr die Datei, die validiert wurde.
  • Bewahren Sie den Validierungsbericht daneben auf. Er ist das Objekt einvoice des Renderings, aus der Antwort, aus GET /v1/renders/{id} oder aus Bericht (JSON) im Render-Protokoll. Er hält fest, an welchen Regeln die Datei gemessen wurde und dass sie bestanden hat, am Tag, an dem die Rechnung ausgestellt wurde.
  • Wissen Sie, was der Bericht belegt. Die Validierung belegt das Format und die Geschäftsregeln, nicht den Inhalt. Eine Rechnung mit einem falschen Umsatzsteuersatz besteht sie.

Eigener Speicher kopiert jedes PDF und das XML von xml: both beim Rendern in Ihren eigenen Bucket.