ZUGFeRD E-Rechnung per API erstellen: Anleitung mit RechnungsAPI
Die elektronische Rechnungsstellung nimmt im deutschen B2B-Bereich stark zu. Während XRechnung hauptsächlich für Behörden verwendet wird, etabliert sich ZUGFeRD als der Standard für elektronische Rechnungen zwischen Unternehmen. ZUGFeRD-Rechnungen kombinieren das Beste aus beiden Welten: eine menschenlesbare PDF-Rechnung mit strukturierten XML-Daten für die automatisierte Verarbeitung.
In diesem Tutorial zeigen wir, wie Sie mit der RechnungsAPI einfach und schnell ZUGFeRD-konforme Rechnungen erstellen können - ohne sich in die komplexen technischen Details einarbeiten zu müssen.
Inhaltsverzeichnis
- Was ist ZUGFeRD?
- Das Problem mit nativen CII/XML-Implementierungen
- Die Vorteile von ZUGFeRD im B2B-Bereich
- Setup und Installation: Der erste Schritt
- Client-Initialisierung
- Schritt-für-Schritt: ZUGFeRD-Rechnung erstellen
- Vollständiges ZUGFeRD-Arbeitsbeispiel
- Erweiterte B2B-Features für ZUGFeRD
- Fazit
Was ist ZUGFeRD?
ZUGFeRD (Zentraler User Guide des Forums elektronische Rechnung Deutschland) ist der deutsche Standard für elektronische Rechnungen im Business-to-Business-Bereich. Anders als XRechnung, die als reine XML-Datei daherkommt, ist ZUGFeRD eine hybride Lösung: Eine normale PDF-Rechnung wird um strukturierte XML-Daten erweitert, die als unsichtbare Anlage in der PDF-Datei eingebettet sind.
Das Problem mit nativen CII/XML-Implementierungen
ZUGFeRD basiert auf dem UN/CEFACT CII (Cross Industry Invoice) Format - einem XML-Standard, der noch komplexer als UBL ist. Wer schon einmal versucht hat, ZUGFeRD-Rechnungen direkt als XML zu erstellen, weiß: Es ist ein Alptraum aus verschachtelten Strukturen, kryptischen Codes und strikten Validierungsregeln. Hinzu kommt das aufwendige Einbetten der XML-Datei in die PDF.
Adressdarstellung: Ein Beispiel der Komplexität
Eine einfache Adresse in nativem CII erfordert eine tiefe XML-Verschachtelung:
<ram:PostalTradeAddress>
<ram:LineOne>Musterstraße 55a</ram:LineOne>
<ram:CityName>Hamburg</ram:CityName>
<ram:PostcodeCode>12345</ram:PostcodeCode>
<ram:CountryID>DE</ram:CountryID>
</ram:PostalTradeAddress>
Dieselbe Adresse in der RechnungsAPI benötigt nur wenige Zeilen verständliches JSON:
{
"address": {
"line1": "Musterstraße 55a",
"postalCode": "12345",
"city": "Hamburg",
"country": "DE"
}
}
Komplexe Datenstrukturen: Wo CII versagt
Bei ZUGFeRD müssen Sie mit XML-Namespace-Präfixen wie ram:
, udt:
und qdt:
arbeiten. Eine einzige Rechnungsposition sieht in nativem CII so aus:
<ram:IncludedSupplyChainTradeLineItem>
<ram:AssociatedDocumentLineDocument>
<ram:LineID>1</ram:LineID>
</ram:AssociatedDocumentLineDocument>
<ram:SpecifiedTradeProduct>
<ram:Name>Beratung und Konzeption</ram:Name>
<ram:Description>Analyse und Erarbeitung eines Konzepts</ram:Description>
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount>95.00</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity unitCode="HUR">3</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<ram:ApplicableTradeTax>
<ram:CategoryCode>S</ram:CategoryCode>
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount>285.00</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
Die gleiche Information im RechnungsAPI-Format ist deutlich einfacher:
{
"unitPrice": { "value": "95.00", "currency": "EUR" },
"quantity": { "value": "3", "unit": "HUR" },
"item": {
"name": "Beratung und Konzeption",
"description": "Analyse und Erarbeitung eines Konzepts",
"vat": { "code": "S", "rate": "19.00" }
}
}
Die RechnungsAPI abstrahiert diese Komplexität komplett weg und generiert im Hintergrund das vollständig konforme CII-XML.
Die Vorteile von ZUGFeRD im B2B-Bereich
ZUGFeRD bietet gegenüber traditionellen PDF-Rechnungen erhebliche Vorteile, die sich sowohl für Absender als auch Empfänger auszahlen.
Für den Absender bedeutet ZUGFeRD, dass die gewohnte PDF-Optik erhalten bleibt, während gleichzeitig die Möglichkeit zur automatisierten Verarbeitung beim Empfänger geschaffen wird. Dies führt zu reduzierten Rückfragen zu Rechnungsdetails und beschleunigten Zahlungsprozessen. Die Investition in ZUGFeRD zahlt sich durch die verbesserte Kundenerfahrung und optimierte Cashflow-Zyklen schnell aus.
Der Empfänger profitiert von der Möglichkeit des automatischen Imports in ERP-Systeme, wodurch die manuelle Dateneingabe entfällt. Dies führt nicht nur zu weniger Fehlern bei der Buchung, sondern auch zu deutlich schnelleren Freigabeprozessen. Moderne ERP-Systeme können ZUGFeRD-Rechnungen vollautomatisch verarbeiten, von der Kreditorenerkennung bis zur Kostenstellenzuordnung.
Setup und Installation: Der erste Schritt
Wir verwenden im nachfolgenden Abschnitt beispielhaft das offizielle Node.js SDK von RechnungsAPI. Da RechnungsAPI eine REST-API mit OpenAPI Spezifikation ist, lassen sich die notwendigen HTTP-Aufrufe in jeder gängigen Programmiersprache erledigen. Auch die automatische Erstellung von Client-Code mithilfe von OpenAPI-Generatoren ist möglich.
Beginnen wir mit der praktischen Implementierung. Zuerst installieren wir den offiziellen Client:
npm install @rechnungs-api/client
Das SDK bietet vollständige TypeScript-Unterstützung, was bedeutet, dass Ihr Editor Sie bei der Entwicklung mit Autocomplete und Typprüfung unterstützt. Dies reduziert Fehler erheblich und beschleunigt die Entwicklung.
Client-Initialisierung
Erstellen Sie eine Client-Instanz mit Ihrem API-Key. Den Key erhalten Sie nach der Registrierung auf rechnungs-api.de.
import { Client } from "@rechnungs-api/client";
export const client = new Client({
// Verwenden Sie Umgebungsvariablen für produktive Anwendungen
apiKey: process.env.RECHNUNGS_API_KEY || "YOUR_API_KEY",
});
Wichtig: Verwenden Sie für Tests den Test-API-Key (beginnt mit test_
) und für Produktion den Produktions-Key (beginnt mit prod_
).
Schritt-für-Schritt: ZUGFeRD-Rechnung erstellen
Schritt 1: Absender definieren - Ihr Unternehmen professionell darstellen
Der Absender ist, falls Sie nicht im Namen anderer Rechnungen erstellen wollen, in der Regel Ihr eigenes Unternehmen. Für ZUGFeRD sind vollständige Unternehmensdaten wichtig, damit die automatisierte Verarbeitung beim Empfänger reibungslos funktioniert:
import type { SenderParty } from "@rechnungs-api/client";
const sender: SenderParty = {
name: "Muster GmbH",
address: {
line1: "Musterstraße 55a",
postalCode: "12345",
city: "Hamburg",
country: "DE",
},
contact: {
name: "Max Mustermann",
email: "max.mustermann@example.com",
phone: "+49123456789",
website: "https://www.example.com",
},
vatId: "DE123456789", // USt-IdNr.
taxId: "12/345/67890", // Steuernummer
owner: "Max Mustermann", // Geschäftsführer
registration: {
office: "Amtsgericht Hamburg",
number: "HRB 123456",
},
};
Detaillierte Erläuterung der wichtigsten Felder:
vatId
: Die Umsatzsteuer-Identifikationsnummer ist für umsatzsteuerpflichtige Unternehmen verpflichtend und muss das Format "DE" + 9 Ziffern haben.taxId
: Die Steuernummer des zuständigen Finanzamts. Das Format variiert je nach Bundesland.owner
: Bei Kapitalgesellschaften (GmbH, AG) ist die Angabe der vertretungsberechtigten Person erforderlich.registration
: Handelsregistereintrag ist bei Kapitalgesellschaften verpflichtend. Die Angaben müssen exakt mit dem Handelsregisterauszug übereinstimmen.
Schritt 2: Empfänger definieren - Kunden für B2B optimiert erfassen
Der Empfänger ist Ihr Geschäftskunde. Bei ZUGFeRD ist es besonders wichtig, dass die Empfängerdaten vollständig sind, damit die automatisierte Verarbeitung funktioniert:
import type { RecipientParty } from "@rechnungs-api/client";
const recipient: RecipientParty = {
name: "Beispiel UG (haftungsbeschränkt)",
address: {
line1: "Musterweg 3c",
postalCode: "54321",
city: "Berlin",
country: "DE",
},
electronicAddress: {
scheme: "EM",
value: "buchhaltung@beispiel-ug.de",
},
contact: {
name: "Erika Musterfrau",
email: "erika.musterfrau@beispiel-ug.de",
phone: "+49987654321",
},
vatId: "DE987654321",
};
Das Feld eletronicAddress
wird dabei mit dem Electronic Address Scheme (EAS) definiert. Für B2B-Anwendungen ist die Verwendung des Codes EM
(E-Mail Adresse) üblich.
Schritt 3: Zahlungsinformationen für Unternehmen definieren
B2B-Zahlungsinformationen unterscheiden sich oft von B2C-Rechnungen durch längere Zahlungsziele und spezifische Bankverbindungen:
import type { PaymentInformation } from "@rechnungs-api/client";
const payment: PaymentInformation = {
means: [{
code: "30", // SEPA-Überweisung
bankAccount: {
bankName: "Muster Bank",
iban: "DE12345678901234567890",
bic: "MUSTDE12XXX",
},
}],
terms: "Zahlbar innerhalb von 30 Tagen netto",
};
Verständnis der Payment Codes: Die Codes folgen dem UNTDID 4461. Die wichtigsten Codes für deutsche Unternehmen sind:
30
- SEPA-Überweisung (am häufigsten verwendet)10
- Barzahlung (für Kleinbeträge)20
- Scheckzahlung (selten verwendet)30
- Krebitübertragung (SEPA-Überweisung)31
- Debitübertragung (Lastschriftverfahren)42
- Zahlung direkt an Bank48
- Bankguthaben (Gutschrift)
Schritt 4: Rechnungspositionen mit B2B-Focus
Bei B2B-Rechnungen sind detaillierte Beschreibungen und einheitliche Codes besonders wichtig:
import type { DocumentLineCreateRequest } from "@rechnungs-api/client";
const lines: DocumentLineCreateRequest[] = [
{
unitPrice: { value: "95.00", currency: "EUR" },
item: {
name: "Beratung und Konzeption",
description: "Analyse und Erarbeitung eines Konzepts für die Digitalisierung",
vat: { code: "S", rate: "19.00" }, // S = Standard rate
},
quantity: { value: "3", unit: "HUR" }, // HUR = Hour (Stunde)
},
{
unitPrice: { value: "500.00", currency: "EUR" },
item: {
name: "Logo-Design",
description: "Entwicklung eines Corporate Designs inkl. Logo",
vat: { code: "S", rate: "19.00" },
},
quantity: { value: "1", unit: "H87" }, // H87 = Piece (Stück)
},
];
Hinweise zu Einheit-Codes: Die API verwendet die UN/ECE-Empfehlung No. 20 für Einheitencodes. Diese standardisierten Codes stellen sicher, dass Ihre Rechnungen international verständlich sind:
HUR
= Stunde (Hour) - für DienstleistungenH87
= Stück (Piece) - für einzelne Artikel oder LeistungenMTR
= Meter - für LängenangabenMTK
= Quadratmeter - für FlächenangabenMTQ
= Kubikmeter - für VolumenangabenKGM
= Kilogramm - für GewichtsangabenDAY
= Tag - für tagesweise Abrechnung
Umsatzsteuer-Codes und deren Bedeutung: Die Umsatzsteuer-Codes folgen dem internationalen Standard UNTDID 5305:
S
= Standard rate (Normalsatz, aktuell 19% in Deutschland)A
= Reduced rate (ermäßigter Satz, aktuell 7% in Deutschland)Z
= Zero rate (0% - für bestimmte Leistungen wie Ausfuhrlieferungen)E
= Exempt (steuerbefreit - für bestimmte medizinische, pädagogische Leistungen)AE
= VAT Reverse Charge (Reverse-Charge-Verfahren bei B2B-Leistungen)
Schritt 5: ZUGFeRD-Konfiguration aktivieren
Die ZUGFeRD-Konfiguration unterscheidet sich leicht von XRechnung. ZUGFeRD nutzt das CII-Format und ist primär für B2B-Anwendungen optimiert:
import type { EInvoiceConfiguration } from "@rechnungs-api/client";
const eInvoiceConfig: EInvoiceConfiguration = {
type: "zugferd",
profile: "xrechnung", // Verfügbare Profile: 'minimum' | 'basic-wl' | 'basic' | 'en-16931' | 'extended' | 'xrechnung'
};
Die verfügbaren ZUGFeRD-Profile:
minimum
: Grundlegende Rechnungsdaten, minimaler Funktionsumfang (entspricht nicht § 14 UStG und daher in Deutschland ungültig)basic-wl
: Basic-Profil ohne Leitweg-ID (entspricht nicht § 14 UStG und daher in Deutschland ungültig)basic
: Standard-B2B-Funktionen, ausreichend für die meisten Anwendungsfälleen-16931
: Europäischer Standard, kompatibel mit EU-Richtlinienextended
: Vollständiger Funktionsumfang für komplexe B2B-Szenarienxrechnung
: Kompatibel mit XRechnung-Standard, ideal für öffentliche Auftraggeber
Empfehlung für B2B: Verwenden Sie "xrechnung"
für maximale Kompatibilität oder "en-16931"
für europäische Standards.
Schritt 6: Die vollständige ZUGFeRD-Rechnung zusammenbauen
Jetzt fügen wir alle Komponenten zu einer vollständigen ZUGFeRD-Rechnung zusammen. B2B-Rechnungen benötigen oft zusätzliche Referenzen und Texte:
import type { DocumentCreateRequest } from "@rechnungs-api/client";
const documentRequest: DocumentCreateRequest = {
type: "invoice",
locale: "de-DE",
number: "RE-2024-001",
issueDate: "2024-02-28",
dueDate: "2024-03-29", // 30 Tage später
sender,
recipient,
payment,
lines,
// ZUGFeRD aktivieren
eInvoice: eInvoiceConfig,
// Projekt oder Auftragsnummer für die automatisierte Zuordnung in ERP-Systemen.
// Falls nicht zutreffend wird hier auch "00" verwendet.
buyerReference: "00",
// Professionelles Anschreiben
preTableText: "Sehr geehrte Damen und Herren,\n\nfür die erbrachten Leistungen stellen wir Ihnen folgende Positionen in Rechnung:",
postTableText: "Vielen Dank für Ihren Auftrag! Bitte überweisen Sie den Betrag bis zum Fälligkeitsdatum auf das angegebene Konto.",
// Corporate Design
theme: {
fontFamily: "Open Sans",
// logo: `data:image/png;base64,${logoBase64}`, // Base64-kodiertes Logo
},
};
Schritt 7: ZUGFeRD-Rechnung erstellen und verwenden
Der finale Schritt - die Erstellung der ZUGFeRD-Datei. Das Besondere: Sie erhalten eine PDF-Datei, die die strukturierten Daten unsichtbar enthält:
import * as fs from "node:fs/promises";
try {
// Dokument erstellen
console.log("Erstelle ZUGFeRD-Rechnung...");
const document = await client.createDocument(documentRequest);
console.log(`ZUGFeRD-Rechnung erstellt! ID: ${document.id}`);
// ZUGFeRD PDF herunterladen (enthält eingebettete XML-Daten)
console.log("Lade ZUGFeRD PDF herunter...");
const pdfBuffer = await client.readDocument(document.id, "pdf");
await fs.writeFile("zugferd-rechnung.pdf", Buffer.from(pdfBuffer));
console.log("ZUGFeRD PDF gespeichert als zugferd-rechnung.pdf");
return document;
} catch (error) {
console.error("Fehler beim Erstellen der ZUGFeRD-Rechnung:", error);
throw error;
}
Die resultierende PDF sieht wie folgt aus:
Vollständiges ZUGFeRD-Arbeitsbeispiel
Hier ist das komplette, lauffähige Beispiel für ZUGFeRD:
import * as fs from "node:fs/promises";
import type {
DocumentCreateRequest,
RecipientParty,
SenderParty,
} from "@rechnungs-api/client";
import { Client } from "@rechnungs-api/client";
// Client initialisieren
const client = new Client({
apiKey: process.env.RECHNUNGS_API_KEY || "YOUR_API_KEY",
});
// Absender definieren
const sender: SenderParty = {
name: "Muster GmbH",
address: {
line1: "Musterstraße 55a",
postalCode: "12345",
city: "Hamburg",
country: "DE",
},
electronicAddress: {
scheme: "EM",
value: "info@example.com",
},
contact: {
name: "Max Mustermann",
email: "max.mustermann@example.com",
phone: "+49123456789",
website: "https://www.example.com",
},
vatId: "DE123456789",
taxId: "12/345/67890",
owner: "Max Mustermann",
registration: {
office: "Amtsgericht Hamburg",
number: "HRB 123456",
},
};
// Empfänger definieren
const recipient: RecipientParty = {
name: "Beispiel UG (haftungsbeschränkt)",
address: {
line1: "Musterweg 3c",
postalCode: "54321",
city: "Berlin",
country: "DE",
},
electronicAddress: {
scheme: "EM",
value: "buchhaltung@beispiel-ug.de",
},
contact: {
name: "Erika Musterfrau",
email: "erika.musterfrau@beispiel-ug.de",
phone: "+49987654321",
},
vatId: "DE987654321",
};
// ZUGFeRD-Rechnung erstellen
const documentRequest: DocumentCreateRequest = {
type: "invoice",
locale: "de-DE",
number: "RE-2024-001",
issueDate: "2024-02-28",
dueDate: "2024-03-29",
sender,
recipient,
buyerReference: "PROJEKT-2024-ZF",
preTableText: "Sehr geehrte Damen und Herren,\n\nfür die erbrachten Leistungen stellen wir Ihnen folgende Positionen in Rechnung:",
postTableText: "Vielen Dank für Ihren Auftrag! Bitte überweisen Sie den Betrag bis zum Fälligkeitsdatum auf das angegebene Konto.",
// Rechnungspositionen
lines: [
{
unitPrice: { value: "95.00", currency: "EUR" },
item: {
name: "Beratung und Konzeption",
description: "Analyse und Erarbeitung eines Konzepts für die Digitalisierung",
vat: { code: "S", rate: "19.00" },
},
quantity: { value: "3", unit: "HUR" },
},
{
unitPrice: { value: "500.00", currency: "EUR" },
item: {
name: "Logo-Design",
description: "Entwicklung eines Corporate Designs inkl. Logo",
vat: { code: "S", rate: "19.00" },
},
quantity: { value: "1", unit: "H87" },
},
],
// Zahlungsinformationen
payment: {
means: [{
code: "30",
bankAccount: {
bankName: "Muster Bank",
iban: "DE12345678901234567890",
bic: "MUSTDE12XXX",
},
}],
terms: "Zahlbar innerhalb von 30 Tagen netto",
},
// ZUGFeRD aktivieren - der wichtige Unterschied zu XRechnung
eInvoice: {
type: "zugferd",
profile: "xrechnung", // Für maximale Kompatibilität
},
// Theme anpassen (optional)
theme: {
fontFamily: "Open Sans",
},
};
// Hauptfunktion
async function main() {
try {
console.log("Erstelle ZUGFeRD-Rechnung...");
const document = await client.createDocument(documentRequest);
console.log(`✅ ZUGFeRD-Rechnung erstellt! ID: ${document.id}`);
// ZUGFeRD PDF herunterladen
const pdfBuffer = await client.readDocument(document.id, "pdf");
await fs.writeFile("zugferd-rechnung.pdf", Buffer.from(pdfBuffer));
console.log("✅ ZUGFeRD PDF gespeichert als zugferd-rechnung.pdf");
// Dokumentdetails ausgeben
console.log("\n📋 Rechnungsdetails:");
console.log(`Nummer: ${document.number}`);
console.log(`Nettobetrag: ${document.netAmount.value} ${document.netAmount.currency}`);
console.log(`Bruttobetrag: ${document.grossAmount.value} ${document.grossAmount.currency}`);
console.log(`Erstellt: ${document.createdAt}`);
console.log(`Verfällt: ${document.expiresAt}`);
} catch (error) {
console.error("❌ Fehler:", error);
}
}
main();
Erweiterte B2B-Features für ZUGFeRD
Lieferanten-Integration optimieren
ZUGFeRD-Rechnungen werden oft automatisiert in ERP-Systeme importiert. Zusätzliche Felder helfen dabei:
const documentRequest: DocumentCreateRequest = {
// ... andere Felder
// Lieferadresse für komplexe B2B-Szenarien
delivery: {
address: {
line1: "Lieferstraße 10",
postalCode: "98765",
city: "München",
country: "DE",
},
},
// Leistungszeitraum für Dienstleistungen
deliveryPeriod: {
startDate: "2024-02-01",
endDate: "2024-02-28",
vatDate: "35",
},
};
Branding für B2B-Professionalität
import * as fs from "node:fs/promises";
// Corporate Logo einbetten
const logoBuffer = await fs.readFile("./company-logo.png");
const logoBase64 = logoBuffer.toString("base64");
const documentRequest: DocumentCreateRequest = {
// ... andere Felder
theme: {
logo: `data:image/png;base64,${logoBase64}`,
fontFamily: "Open Sans",
},
};
Fazit
Die RechnungsAPI macht die Erstellung von ZUGFeRD Dokumenten möglich, ohne sich mit den technischen Details auseinanderzusetzen. Statt sich mit komplexen CII-Strukturen und PDF Standards, arbeiten Sie mit einem intuitiven JSON-API.
Die wichtigsten Vorteile im Überblick:
- Einfach: JSON statt XML
- Sicher: Automatische Validierung
- Komplett: Sie müssen keine eigene PDF liefern
- Flexibel: Unterstützung für viele ZUGFeRD-Features
- Developer-friendly: TypeScript-Support, gute Dokumentation
Mit diesem Tutorial können Sie sofort anfangen, ZUGFeRD Rechnungen zu erstellen. Die RechnungsAPI übernimmt die komplexe PDF-Generierung und Sie können sich auf Ihre Geschäftslogik konzentrieren.
Für weitere Informationen und erweiterte Features besuchen Sie die offizielle Dokumentation. Dort lässt sich die API auch direkt mit Beispielen ausprobieren.