Stripe + E-Rechnung: So erzeugst du ZUGFeRD automatisch nach jeder Zahlung
Stripe sendet nach einer Zahlung automatisch eine Rechnung — aber die ist ein PDF, kein strukturiertes E-Rechnungsformat. Ab 2027 reicht das für B2B-Kunden nicht mehr. Mit einem Stripe-Webhook und rechnungsapi.de ist das in 20 Minuten gelöst.
Stripe ist kein E-Rechnungs-System
Die Rechnungen, die Stripe ausgibt, sind PDF — nicht EN 16931 konform, kein eingebettetes XML. Für B2B-Kunden ab 800.000 € Jahresumsatz gilt das ab 2027 als nicht zulässig. Auch kleinere Unternehmen müssen ab 2028 konforme E-Rechnungen versenden.
Das Problem: Stripe-Rechnungen erfüllen die E-Rechnungspflicht nicht
Stripe erzeugt schöne, gut gestaltete PDF-Rechnungen — das ist unbestritten. Das Problem ist rechtlicher Natur: Nach deutschem Steuerrecht und der EU-Norm EN 16931 müssen B2B-Rechnungen ab 2027 als strukturierte E-Rechnung vorliegen. Das bedeutet maschinenlesbares XML, entweder eingebettet in ein PDF/A-3 (ZUGFeRD) oder als reines XML-Dokument (XRechnung).
Stripe Billing erzeugt ausschließlich PDF-Dokumente ohne eingebettetes XML. Diese gelten rechtlich als sonstige Rechnungen und sind im B2B-Bereich ab den jeweiligen Stichtagen nicht mehr ausreichend. Betroffen sind alle B2B-SaaS-Unternehmen, Subscription-Businesses und Online-Shops, die Stripe in Deutschland einsetzen.
| Eigenschaft | Stripe PDF | ZUGFeRD (via API) | XRechnung |
|---|---|---|---|
| Menschenlesbar | ✓ | ✓ | ✗ |
| Maschinell verarbeitbar | ✗ | ✓ | ✓ |
| EN 16931 konform | ✗ | ✓ | ✓ |
| Ab 2027 B2B-zulässig | ✗ | ✓ | ✓ |
Wer ist betroffen?
Die E-Rechnungspflicht in Deutschland betrifft alle inländischen B2B-Umsätze. Wenn du Stripe verwendest und B2B-Kunden in Deutschland hast, bist du in der Pflicht:
SaaS-Unternehmen
Mit B2B-Abonnements und Stripe Billing als Zahlungsanbieter.
Online-Shops
Die Stripe verwenden und steuerpflichtige B2B-Bestellungen abwickeln.
Freelancer & Agenturen
Die Stripe für Kundenzahlungen nutzen und USt ausweisen.
Kleinunternehmer §19 UStG
Müssen E-Rechnungen empfangen können, aber noch nicht selbst versenden.
Die Lösung: Stripe Webhook → rechnungsapi.de → ZUGFeRD
Das Prinzip ist einfach: Stripe informiert deinen Server per Webhook über jede abgeschlossene Zahlung. Dein Server ruft dann rechnungsapi.de auf und erhält eine fertige, rechtskonforme ZUGFeRD- oder XRechnung zurück. Der gesamte Prozess dauert unter 3 Sekunden. Kein eigenes Entwicklerteam? Wir richten die Integration gemeinsam mit dir ein — wahlweise als schlüsselfertigen n8n-Workflow oder als individuelle Implementierung.
Stripe-Zahlung erfolgreich
payment_intent.succeeded oder invoice.paid Event wird von Stripe ausgelöst.
Webhook feuert an deinen Server
Stripe sendet das Event als HTTP POST an deine Webhook-URL — signiert und verifizierbar.
Server ruft rechnungsapi.de auf
Dein Server mappt die Stripe-Daten auf das rechnungsapi.de JSON-Format und sendet einen POST-Request.
API liefert ZUGFeRD PDF zurück
rechnungsapi.de gibt innerhalb von Sekunden ein fertiges PDF/A-3 mit eingebettetem XML zurück.
PDF versenden & archivieren
PDF per E-Mail an den Kunden senden und GoBD-konform in S3, Google Drive oder DATEV archivieren.
Code-Beispiel: Node.js Stripe Webhook Handler
Das folgende vollständige Beispiel zeigt einen Express-Server, der Stripe-Webhooks empfängt und bei jeder bezahlten Rechnung automatisch eine ZUGFeRD-konforme E-Rechnung über rechnungsapi.de erzeugt. Benötigte Pakete: express, stripe, node-fetch.
// stripe-webhook.js — Stripe Webhook Handler
const express = require('express')
const Stripe = require('stripe')
const fetch = require('node-fetch')
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
const app = express()
app.post('/webhook/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
const sig = req.headers['stripe-signature']
let event
try {
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET)
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`)
}
if (event.type === 'invoice.paid') {
const invoice = event.data.object
const customer = await stripe.customers.retrieve(invoice.customer)
// E-Rechnung via rechnungsapi.de erzeugen
const response = await fetch('https://api.rechnungsapi.de/api/v1/zugferd/createZugferdFromJson', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.RECHNUNGSAPI_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
invoice: {
invoiceNumber: invoice.number,
invoiceIssueDate: new Date(invoice.created * 1000).toISOString().split('T')[0],
invoiceTypeCode: '380',
invoiceCurrencyCode: 'EUR',
seller: {
sellerName: 'Dein Unternehmen GmbH',
sellerVatIdentifier: 'DE123456789',
sellerElectronicAddress: 'rechnungen@deinunternehmen.de',
sellerPostalAddress: {
sellerAddressLine1: 'Musterstrasse 1',
sellerCity: 'Berlin',
sellerPostCode: '10115',
sellerCountryCode: 'DE'
}
},
buyer: {
buyerName: customer.name,
buyerElectronicAddress: customer.email,
buyerPostalAddress: {
buyerAddressLine1: customer.address?.line1 ?? '',
buyerCity: customer.address?.city ?? '',
buyerPostCode: customer.address?.postal_code ?? '',
buyerCountryCode: customer.address?.country ?? 'DE'
}
},
invoiceLine: invoice.lines.data.map((line, i) => ({
invoiceLineIdentifier: String(i + 1),
invoiceLineNetAmount: String((line.amount / 100).toFixed(2)),
itemName: line.description,
invoicedQuantity: String(line.quantity ?? 1),
invoicedQuantityUnitOfMeasureCode: 'C62',
itemNetPrice: String(((line.amount / 100) / (line.quantity ?? 1)).toFixed(2)),
invoiceLineVatInformation: {
invoiceLineVatCategoryCode: 'S',
invoiceLineVatRate: 19
}
})),
documentTotals: {
sumOfInvoiceLineNetAmount: String((invoice.subtotal / 100).toFixed(2)),
invoiceTotalAmountWithoutVat: String((invoice.subtotal / 100).toFixed(2)),
invoiceTotalVatAmount: String((invoice.tax / 100).toFixed(2)),
invoiceTotalAmountWithVat: String((invoice.total / 100).toFixed(2)),
amountDueForPayment: String((invoice.amount_due / 100).toFixed(2))
},
vatBreakdown: [{
vatCategoryTaxableAmount: String((invoice.subtotal / 100).toFixed(2)),
vatCategoryTaxAmount: String((invoice.tax / 100).toFixed(2)),
vatCategoryCode: 'S',
vatCategoryRate: 19
}]
}
})
})
const pdfBuffer = await response.buffer()
// PDF per E-Mail versenden oder in S3/GDrive speichern
console.log('ZUGFeRD-Rechnung erzeugt:', invoice.number)
}
res.json({ received: true })
})
app.listen(3000, () => console.log('Webhook server running on port 3000'))Setze die Umgebungsvariablen STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET und RECHNUNGSAPI_TOKEN in deiner Umgebung. Den API Token erhältst du nach kostenloser Registrierung auf rechnungsapi.de.
Stripe + DATEV: Automatisch zum Steuerberater
Das ZUGFeRD-PDF, das rechnungsapi.de zurückgibt, lässt sich direkt per DATEV Upload Mail an deinen Steuerberater weiterleiten — kein manuelles Exportieren, kein Kopieren von Rechnungsdaten. Stripe-Zahlung rein, DATEV-konforme E-Rechnung raus, automatisch im Buchhaltungssystem verbucht.
Kein manueller Export
ZUGFeRD PDF direkt nach Stripe-Zahlung generiert und weitergeleitet.
DATEV-kompatibel
PDF/A-3 mit eingebettetem ZUGFeRD XML wird von DATEV Unternehmen online erkannt.
GoBD-konform archiviert
Automatische Archivierung in S3 oder Google Drive mit Revisionssicherheit.
Kleinunternehmer §19 UStG — bin ich betroffen?
Als Kleinunternehmer nach §19 UStG bist du von der Sendepflicht ausgenommen, solange du keine Umsatzsteuer ausweist. Du musst jedoch ab 2025 in der Lage sein, E-Rechnungen von deinen Lieferanten und Geschäftspartnern zu empfangen und zu verarbeiten.
Wenn du B2B-Rechnungen mit Umsatzsteuer ausstellst — also nicht unter die Kleinunternehmerregelung fällst — gilt für dich ab 2027 (bei Jahresumsatz über 800.000 €) bzw. ab 2028 (alle anderen) die vollständige E-Rechnungspflicht.
Häufige Fragen: Stripe & E-Rechnungspflicht
Gibt es einen Stripe-nativen Weg für ZUGFeRD?
+
Nein. Stripe bietet kein ZUGFeRD- oder XRechnung-Format an. Stripe Billing erzeugt ausschließlich PDF-Rechnungen, die nicht EN 16931-konform sind. Ein externer Dienst wie rechnungsapi.de ist zwingend erforderlich.
Funktioniert das auch mit Stripe Billing (Abonnements)?
+
Ja. Für Abonnements verwendest du das invoice.paid-Event. Stripe sendet dieses Event automatisch, wenn ein Abonnement erfolgreich verlängert oder ein neues Abonnement gestartet wird. Das Code-Beispiel in diesem Beitrag nutzt genau dieses Event.
Wie lange dauert die Integration?
+
Mit dem vollständigen Code-Beispiel aus diesem Artikel circa 20 Minuten. Du brauchst einen Stripe API Key, einen rechnungsapi.de API Token und einen Server, der Webhooks empfangen kann (z.B. per ngrok lokal oder ein bestehendes Node.js-Backend).
Muss ich eine separate Rechnung erzeugen oder kann ich die Stripe-Rechnung verwenden?
+
Du erzeugst eine separate, konforme E-Rechnung via rechnungsapi.de. Die Stripe-PDF-Rechnung kann zusätzlich existieren — sie ersetzt aber nicht die Pflicht zur E-Rechnung im B2B-Bereich. Beide Dokumente können für unterschiedliche Zwecke verwendet werden.
Was ist mit Stripe Tax?
+
Stripe Tax hilft bei der automatischen Steuerberechnung und ist eine gute Ergänzung. Es erzeugt jedoch kein konformes E-Rechnungsformat nach EN 16931. Du kannst die von Stripe Tax berechneten Steuerbeträge als Eingabe für rechnungsapi.de verwenden.
E-Rechnung-API kostenlos testen
Kein Stripe-Plugin nötig. Einfach API-Token holen, dieses Code-Beispiel einfügen — fertig. Kostenloser Test-Account, keine Kreditkarte.