Zuletzt aktualisiert: Juli 2026 · Node 18+ (natives fetch), TypeScript-Beispiele · Lesezeit: ca. 7 Minuten

Ihr SaaS stellt Rechnungen? Dann betrifft Sie die deutsche E-Rechnungs-Pflicht doppelt: Ab 2027/2028 erwarten Ihre deutschen Geschäftskunden XRechnung oder ZUGFeRD statt PDF — und wer das früh anbietet, macht aus einer Compliance-Pflicht ein Feature. Die schlechte Nachricht: Die EN 16931 ist mit ihren weit über hundert Geschäftsregeln nichts, was man neben dem Produkt „mal eben" implementiert. Die gute: Man muss es auch nicht.

Setup

Nichts zu installieren — die API ist plain HTTP, natives fetch (Node 18+) reicht, und genau damit arbeiten alle Beispiele hier. (Wer ein SDK bevorzugt: npm install fakturwire — der offizielle, abhängigkeitsfreie TypeScript-Client; das Quickstart steht in dessen README.) Den API-Key gibt's hier kostenlos (50 Credits, keine Kreditkarte); er gehört in eine Umgebungsvariable, nie in den Code.

Das Rechnungsobjekt

Beträge sind Strings. Das ist kein Stilbruch, sondern Absicht: 0.1 + 0.2 !== 0.3, und bei Geld ist „ungefähr richtig" die teuerste Sorte falsch. Die Feldnamen entsprechen den EN-16931-Geschäftsbegriffen:

const invoice = {
  number: 'RE-2026-0815',
  issueDate: '2026-07-20',
  dueDate: '2026-08-19',
  currency: 'EUR',
  buyerReference: 'BESTELLUNG-4711',        // BT-10 — in XRechnung Pflicht
  seller: {
    name: 'Beispiel GmbH',
    vatId: 'DE811128135',
    electronicAddress: { schemeId: '9930', value: 'DE811128135' },
    address: { streetName: 'Hauptstraße 5', city: 'Berlin', postalZone: '10115', countryCode: 'DE' },
    contact: { name: 'Erika Muster', phone: '+49 30 1234567', email: 'rechnung@beispiel.de' }, // BR-DE-2
  },
  buyer: {
    name: 'Kunde AG',
    vatId: 'DE129273398',
    electronicAddress: { schemeId: '9930', value: 'DE129273398' },
    address: { streetName: 'Marktplatz 1', city: 'München', postalZone: '80331', countryCode: 'DE' },
  },
  payment: { meansCode: '58', iban: 'DE02120300000000202051', reference: 'RE-2026-0815' }, // BR-DE-1
  lines: [{
    id: '1',
    name: 'SaaS-Abo Juli 2026, Plan „Team“',
    quantity: '1',
    unitPrice: '499.00',
    vat: { categoryCode: 'S', rate: '19' },
  }],
};

Summen und Umsatzsteuer-Aufstellung fehlen absichtlich: Sie werden serverseitig nach den BR-CO-Regeln berechnet und kreuzgeprüft. Wer schon einmal einen Cent Rundungsdifferenz zwischen Positionssumme und Endbetrag gejagt hat, weiß, warum man das nicht selbst machen will.

Der Aufruf

const res = await fetch('https://fakturwire.com/v1/convert', {
  method: 'POST',
  headers: {
    authorization: `Bearer ${process.env.FW_API_KEY}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({ target: 'xrechnung-ubl', invoice }),
});

const body = await res.json();

if (res.status === 422) {
  // Die Rechnung verletzt EN-16931-/BR-DE-Regeln — Befundliste statt XML:
  for (const f of body.findings) console.error(`[${f.rule}] ${f.message}`);
} else if (!res.ok) {
  throw new Error(`fakturwire: HTTP ${res.status} — ${body.error}`);
} else {
  console.log(body.xml);        // fertige XRechnung
  console.log(body.credits);    // Restguthaben
}

Drei Zielformate stehen zur Wahl: xrechnung-ubl für deutsche Empfänger, facturx-en16931 für das hybride PDF-Szenario, peppol-bis-3 für Rechnungen über das Peppol-Netzwerk (Belgien schreibt das im B2B bereits vor).

Der Workflow, der sich bewährt hat

In Produktionssystemen hat sich ein zweistufiges Muster etabliert: validieren beim Entwurf, konvertieren beim Festschreiben. Beim Anlegen oder Ändern der Rechnung schickt man die Rechnung an POST /v1/validate (1 Credit) und zeigt Befunde direkt im UI — der Nutzer korrigiert die fehlende Käuferreferenz, solange er sie noch im Kopf hat. Erst beim endgültigen Festschreiben läuft convert, und das Ergebnis wird unverändert archiviert (das XML ist das aufbewahrungspflichtige Original, nicht die PDF-Ansicht).

Noch ein Betriebs-Detail: Die Antwort enthält immer den aktuellen Credit-Stand. Loggen Sie ihn und alarmieren Sie unter einem Schwellwert — ein 402 mitten im Monatslauf ist vermeidbar.

Woran es beim ersten Mal scheitert

Erfahrungswerte aus tausenden Validierungen: BR-DE-15 (Käuferreferenz fehlt — das Feld gab es im Datenmodell schlicht nicht), BR-DE-2 (kein vollständiger Ansprechpartner), BR-CO-15 (übernommene Alt-Summen, die einen Cent daneben liegen), BR-E-10 (Reverse Charge ohne Befreiungsgrund — relevant, sobald Sie EU-weit verkaufen). Jede Regel hat bei uns eine eigene Seite mit Ursache und Fix — die Befund-IDs aus der API sind direkt verlinkbar.


Erst ausprobieren, dann integrieren: Der kostenlose Validator prüft jede XRechnung im Browser — mit denselben Regeln wie die API. API-Key holen: 50 Credits gratis, danach Abrechnung pro Rechnung. Kein Abo, Credits verfallen nicht.