Zuletzt aktualisiert: Juli 2026 · .NET 8, funktioniert ab .NET 6 · Lesezeit: ca. 8 Minuten

In deutschen Unternehmen läuft die Fakturierung auffallend oft durch .NET-Code — gewachsene Warenwirtschaften, Branchenlösungen, interne Tools. Genau diese Systeme trifft die E-Rechnungs-Pflicht am härtesten: Ab Januar 2027 (Umsatz über 800.000 €) bzw. 2028 (alle) müssen ausgehende B2B-Rechnungen als XRechnung oder ZUGFeRD raus, und ein RechnungDrucken()-Modul aus 2012 hat dazu naturgemäß keine Meinung.

Der Weg mit dem besten Aufwand-Nutzen-Verhältnis: Das Altsystem liefert weiter seine Rechnungsdaten, ein API-Aufruf macht daraus normkonformes, validiertes XML. Was Sie dafür anfassen müssen, ist eine einzige Methode am Ende Ihrer Rechnungsstrecke.

Setup

Kein Paket nötig — HttpClient und System.Text.Json aus der Standardbibliothek reichen völlig, und genau so arbeitet dieser Artikel. (Ein offizielles NuGet-Paket FakturWire erscheint in Kürze; die API bleibt dieselbe.) API-Key kostenlos hier (50 Credits, keine Kreditkarte), abgelegt als Umgebungsvariable oder im Secret Store, nicht in appsettings.json im Repo.

Das Rechnungsobjekt

Ein POCO-Graph, der sich 1:1 nach JSON serialisiert. Beträge sind bewusst Strings — decimal wäre in .NET zwar sicher, aber auf dem Draht garantiert der String, dass nirgendwo ein Binary-Float dazwischenfunkt:

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

Ihnen fehlen die Summenfelder? Richtig so. Endbetrag, Steuerbasis und Umsatzsteuer-Aufstellung werden serverseitig nach den BR-CO-Regeln berechnet und gegengeprüft — die Cent-Differenzen zwischen Altsystem-Summen und normgerechter Rundung sind der häufigste Ablehnungsgrund überhaupt, und so entstehen sie gar nicht erst.

Der Aufruf — HttpClient

using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer",
        Environment.GetEnvironmentVariable("FW_API_KEY"));

var response = await http.PostAsJsonAsync(
    "https://fakturwire.com/v1/convert",
    new { target = "xrechnung-ubl", invoice });

var body = await response.Content.ReadFromJsonAsync<JsonElement>();

if ((int)response.StatusCode == 422)
{
    foreach (var f in body.GetProperty("findings").EnumerateArray())
        Console.Error.WriteLine(
            $"[{f.GetProperty("rule")}] {f.GetProperty("message")}");
}
else if (response.IsSuccessStatusCode)
{
    var xml = body.GetProperty("xml").GetString()!;
    await File.WriteAllTextAsync("RE-2026-0815.xml", xml);
}

Zielformate: xrechnung-ubl (deutsche Empfänger), facturx-en16931 (hybrides ZUGFeRD-Szenario: menschenlesbares PDF, maschinenlesbarer Kern), peppol-bis-3 (EU-Versand über Peppol, in Belgien bereits Pflicht).

Integration ins Altsystem: die zwei bewährten Regeln

Erstens: validieren, bevor der Nutzer weg ist. Rufen Sie /v1/validate bereits beim Erfassen oder Freigeben der Rechnung auf und zeigen Sie die Befunde im UI. Eine fehlende Käuferreferenz korrigiert die Sachbearbeiterin in zehn Sekunden — dieselbe Meldung drei Tage später aus einem Batch-Log ist ein Support-Ticket.

Zweitens: das XML ist das Original. Speichern Sie die zurückgegebene Datei unverändert und GoBD-konform; die hübsche PDF-Ansicht ist nur eine Darstellung. Wer ZUGFeRD/Factur-X nutzt, archiviert die Hybrid-PDF — dort steckt das XML mit drin.

Und ein Betriebshinweis: Jede Antwort enthält den Credit-Reststand. Ein Gauge in Ihrem Monitoring plus Alarm unter Schwellwert erspart den 402 mitten im Monatsabschluss.

Die üblichen Verdächtigen

Beim ersten Lauf mit Bestandsdaten scheitern Rechnungen fast immer an denselben Regeln: BR-DE-15 (Käuferreferenz fehlt), BR-DE-2 (Ansprechpartner unvollständig), BR-CO-15 (Alt-Summen mit Cent-Differenz), BR-E-10 (Reverse Charge ohne Befreiungsgrund). Jede Regel-ID aus der API hat eine eigene Seite mit Ursache und Fix — verlinken Sie sie ruhig direkt aus Ihren Fehlermeldungen.


Zum Ausprobieren ohne eine Zeile Code: der kostenlose Validator — dieselbe Regel-Engine wie die API, direkt im Browser. Wenn's ernst wird: API-Key holen, 50 Credits gratis, Abrechnung pro Rechnung, kein Abo.