XRechnung per API erstellen: Ein Tutorial mit RechnungsAPI
XRechnung ist der deutsche Standard für elektronische Rechnungen an die öffentliche Verwaltung. Lieferanten des Bundes müssen ihre Rechnungen seit dem 27.11.2020 elektronisch einreichen (§ 3 E-Rechnungsverordnung), und seit dem 01.01.2025 ist die E-Rechnung nach § 14 UStG auch zwischen inländischen Unternehmen der Standard. Wer Rechnungsstellung in eigene Software integriert, steht damit vor der Frage: Wie erstellt man konforme XRechnungen, ohne die XML-Spezifikation im Detail zu implementieren?
Dieses Tutorial zeigt Schritt für Schritt, wie Sie mit RechnungsAPI XRechnungen erstellen – ohne UBL-Kenntnisse.
Was ist eine XRechnung?
XRechnung ist eine nationale Ausprägung (CIUS) der europäischen Norm EN 16931 und wird von der KoSIT im Auftrag des IT-Planungsrats betrieben. Eine XRechnung ist ein strukturiertes XML-Dokument in der Syntax UBL oder UN/CEFACT CII. Die technischen Details erklärt unser Artikel XRechnung für Entwickler.
Das Problem mit nativem UBL/XML
Eine einfache Adresse erfordert in UBL eine verschachtelte XML-Struktur mit Namespace-Präfixen:
<cac:PostalAddress>
<cbc:StreetName>Musterstraße 55a</cbc:StreetName>
<cbc:CityName>Hamburg</cbc:CityName>
<cbc:PostalZone>12345</cbc:PostalZone>
<cac:Country>
<cbc:IdentificationCode>DE</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
Dieselbe Adresse in RechnungsAPI ist schlichtes JSON:
{
"address": {
"line1": "Musterstraße 55a",
"postalCode": "12345",
"city": "Hamburg",
"country": "DE"
}
}
Bei Rechnungspositionen wird der Unterschied noch deutlicher. Eine einzelne Position in UBL:
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="HUR">3</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="EUR">285.00</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>Beratung und Konzeption</cbc:Name>
<cbc:Description>Analyse und Erarbeitung eines Konzepts</cbc:Description>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>19</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="EUR">95.00</cbc:PriceAmount>
</cac:Price>
</cac:InvoiceLine>
Die gleiche Information im RechnungsAPI-Format:
{
"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" }
}
}
Positionsnummern, Summenbildung und das konforme UBL-XML erzeugt die API im Hintergrund – inklusive Validierung.
Setup und Installation
Die Beispiele verwenden das offizielle Node.js-SDK. Da RechnungsAPI eine REST-API mit OpenAPI-Spezifikation ist, funktionieren die gleichen Aufrufe aus jeder Programmiersprache, auch mit generierten OpenAPI-Clients.
npm install @rechnungs-api/client
Das SDK ist vollständig in TypeScript typisiert.
Client-Initialisierung
Den API-Key erhalten Sie nach der Registrierung auf rechnungs-api.de. Test-Keys beginnen mit test_, Produktions-Keys mit prod_.
import { Client } from "@rechnungs-api/client";
export const client = new Client({
apiKey: process.env.RECHNUNGS_API_KEY || "YOUR_API_KEY",
});
Schritt für Schritt zur XRechnung
Schritt 1: Absender definieren
Der Absender ist in der Regel Ihr eigenes Unternehmen:
import type { SenderParty } from "@rechnungs-api/client";
const sender: SenderParty = {
name: "Muster GmbH",
address: {
line1: "Musterstraße 55a",
postalCode: "12345",
city: "Hamburg",
country: "DE",
},
// Elektronische Adresse - erforderlich für XRechnung
electronicAddress: {
scheme: "EM", // EM = E-Mail
value: "info@example.com",
},
contact: {
name: "Max Mustermann",
email: "max.mustermann@example.com",
phone: "+49123456789",
},
vatId: "DE123456789", // USt-IdNr.
taxId: "12/345/67890", // Steuernummer
owner: "Max Mustermann", // Inhaber bzw. Geschäftsführung
registration: {
office: "Amtsgericht Hamburg",
number: "HRB 123456",
},
};
Die wichtigsten Felder:
electronicAddress: Die elektronische Adresse ist für E-Rechnungen erforderlich. Der Scheme-Code stammt aus der EAS-Codeliste;EMsteht für eine E-Mail-Adresse.vatId: Die Umsatzsteuer-Identifikationsnummer (in Deutschland „DE“ + 9 Ziffern).taxId: Alternativ oder zusätzlich die Steuernummer des Finanzamts.registration/owner: Handelsregistereintrag und vertretungsberechtigte Person – sie erscheinen auf der PDF-Darstellung der Rechnung.
Schritt 2: Empfänger definieren
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",
};
Rechnungen an Behörden: Öffentliche Auftraggeber werden über ihre Leitweg-ID adressiert. Dafür ist in der EAS-Codeliste der Code 0204 vorgesehen:
electronicAddress: {
scheme: "0204", // EAS-Code für die deutsche Leitweg-ID
value: "991-12345-67890-12", // Die Leitweg-ID der Behörde
}
Die Leitweg-ID teilt Ihnen der Auftraggeber mit, üblicherweise bei der Beauftragung. Sie muss außerdem als Käuferreferenz (buyerReference, siehe Schritt 6) angegeben werden.
Schritt 3: Zahlungsinformationen festlegen
import type { PaymentInformation } from "@rechnungs-api/client";
const payment: PaymentInformation = {
means: [{
code: "58", // SEPA-Überweisung
bankAccount: {
bankName: "Muster Bank",
iban: "DE12345678901234567890",
bic: "MUSTDE12XXX",
},
}],
terms: "Zahlbar innerhalb von 30 Tagen netto",
};
Die Zahlungsart folgt der Codeliste UNTDID 4461. Die wichtigsten Codes:
58– SEPA-Überweisung (SEPA credit transfer)30– Überweisung allgemein (Credit transfer)59– SEPA-Lastschrift (SEPA direct debit)48– Kartenzahlung (Bank card)10– Barzahlung (In cash)
Schritt 4: Rechnungspositionen erstellen
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" },
},
quantity: { value: "3", unit: "HUR" }, // HUR = 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 = Stück
},
];
Einheiten-Codes stammen aus UN/ECE Recommendation N°20 und N°21, zum Beispiel:
H87= Stück,C62= Einheit „Eins“HUR= Stunde,DAY= TagKGM= Kilogramm,MTR= Meter,MTK= Quadratmeter,LTR= Liter
Umsatzsteuer-Kategorien folgen der Codeliste UNTDID 5305:
S= regulär besteuert – gilt für jeden Steuersatz über 0 %, also sowohl 19 % als auch den ermäßigten Satz von 7 % (jeweils mit passendemrate)Z= Steuersatz 0 %E= steuerbefreit; ein Befreiungsgrund ist erforderlich, z. B. bei Kleinunternehmern nach § 19 UStGAE= Reverse Charge (§ 13b UStG)K= innergemeinschaftliche Lieferung,G= Ausfuhr,O= nicht steuerbar
Schritt 5: XRechnung-Konfiguration
Das Feld eInvoice macht aus der Rechnung eine E-Rechnung:
import type { EInvoiceConfiguration } from "@rechnungs-api/client";
const eInvoiceConfig: EInvoiceConfiguration = {
type: "xrechnung", // Alternativ "zugferd"
syntax: "ubl", // Alternativ "cii"
embedPdf: true, // PDF-Darstellung in das XML einbetten
};
syntax: XRechnung erlaubt die Syntaxen UBL und CII; wir empfehlenubl.embedPdf: RechnungsAPI erzeugt aus den Rechnungsdaten auch eine menschenlesbare PDF-Datei und kann sie als Anhang in das XML einbetten.
Schritt 6: Die vollständige Rechnung zusammenbauen
import type { DocumentCreateRequest } from "@rechnungs-api/client";
const documentRequest: DocumentCreateRequest = {
type: "invoice", // Auch andere Dokumenttypen wie "self-billing-invoice" sind möglich
locale: "de-DE",
number: "RE-2026-001",
issueDate: "2026-06-15",
dueDate: "2026-07-15",
sender,
recipient,
payment,
lines,
// XRechnung aktivieren
eInvoice: eInvoiceConfig,
// Käuferreferenz (BT-10) - bei Behörden die Leitweg-ID
buyerReference: "PROJEKT-2026-XR",
// Texte für die PDF-Darstellung
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.",
// Optional: Gestaltung der PDF
theme: {
fontFamily: "Open Sans",
},
};
buyerReference: Eine Referenz des Käufers, etwa eine Auftrags- oder Projektnummer. Bei Rechnungen an deutsche Behörden gehört hier die Leitweg-ID hinein.issueDate/dueDate: Datumsangaben im ISO-FormatYYYY-MM-DD.
Schritt 7: Rechnung erstellen und herunterladen
import * as fs from "node:fs/promises";
const document = await client.createDocument(documentRequest);
console.log(`XRechnung erstellt! ID: ${document.id}`);
// XRechnung-XML herunterladen
const xml = await client.readDocument(document.id, "xml");
await fs.writeFile("xrechnung.xml", xml);
Die in das XML eingebettete PDF-Darstellung sieht so aus:

Vollständiges Arbeitsbeispiel
import * as fs from "node:fs/promises";
import type {
DocumentCreateRequest,
RecipientParty,
SenderParty,
} from "@rechnungs-api/client";
import { Client } from "@rechnungs-api/client";
const client = new Client({
apiKey: process.env.RECHNUNGS_API_KEY || "YOUR_API_KEY",
});
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",
},
vatId: "DE123456789",
taxId: "12/345/67890",
owner: "Max Mustermann",
registration: {
office: "Amtsgericht Hamburg",
number: "HRB 123456",
},
};
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",
};
const documentRequest: DocumentCreateRequest = {
type: "invoice",
locale: "de-DE",
number: "RE-2026-001",
issueDate: "2026-06-15",
dueDate: "2026-07-15",
sender,
recipient,
buyerReference: "PROJEKT-2026-XR",
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.",
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" },
},
],
payment: {
means: [{
code: "58",
bankAccount: {
bankName: "Muster Bank",
iban: "DE12345678901234567890",
bic: "MUSTDE12XXX",
},
}],
terms: "Zahlbar innerhalb von 30 Tagen netto",
},
eInvoice: {
type: "xrechnung",
syntax: "ubl",
embedPdf: true,
},
theme: {
fontFamily: "Open Sans",
},
};
async function main() {
const document = await client.createDocument(documentRequest);
console.log(`XRechnung erstellt! ID: ${document.id}`);
const xml = await client.readDocument(document.id, "xml");
await fs.writeFile("xrechnung.xml", xml);
console.log(`Nummer: ${document.number}`);
console.log(`Nettobetrag: ${document.netAmount.value} ${document.netAmount.currency}`);
console.log(`Bruttobetrag: ${document.grossAmount.value} ${document.grossAmount.currency}`);
}
main();
Erweiterte Features
Logo hinzufügen
import * as fs from "node:fs/promises";
const logoBuffer = await fs.readFile("./logo.png");
const logoBase64 = logoBuffer.toString("base64");
const documentRequest: DocumentCreateRequest = {
// ... andere Felder
theme: {
logo: `data:image/png;base64,${logoBase64}`,
fontFamily: "Open Sans",
},
};
Lieferadresse und Leistungszeitraum
const documentRequest: DocumentCreateRequest = {
// ... andere Felder
delivery: {
address: {
line1: "Lieferstraße 10",
postalCode: "98765",
city: "München",
country: "DE",
},
},
deliveryPeriod: {
startDate: "2026-06-01",
endDate: "2026-06-30",
vatDate: "35",
},
};
Das optionale Feld vatDate gibt an, wann die Umsatzsteuer entsteht. Zulässig ist die von der EN 16931 vorgegebene Teilmenge der Codeliste UNTDID 2005:
3– mit dem Rechnungsdatum35– mit dem tatsächlichen Lieferdatum432– mit der Zahlung
Error Handling
import { ApiError } from "@rechnungs-api/client";
try {
const document = await client.createDocument(documentRequest);
// ...
} catch (error) {
if (error instanceof ApiError) {
console.error(`API Fehler [${error.status}]:`, error.body);
}
throw error;
}
Fazit
Mit RechnungsAPI erstellen Sie XRechnungen über eine JSON-API, ohne UBL-Strukturen, Codelisten-Feinheiten und Validierungsregeln selbst zu implementieren. PDF-Darstellung und konformes XML entstehen in einem einzigen API-Aufruf.
Alle Details und weitere Funktionen finden Sie in der Dokumentation, wo sich die API auch direkt ausprobieren lässt.