Webhooks
Geplant: Echtzeit-Benachrichtigungen über Events in deinem Account. Diese Seite beschreibt den vorgesehenen Vertrag — Events, Payload, Signatur und Retry-Verhalten —, damit eine Integration vorbereitet werden kann.
Echtzeit-Events
Vorgesehen: sofortige Benachrichtigung bei Rechnungs-Erstellung, Validierung und Konvertierung
Signiert
HMAC-SHA256 Signaturen zum Verifizieren der Authentizität
Automatische Retries
Vorgesehen: Bei Fehlern werden Webhooks automatisch erneut gesendet
Verfügbare Events
| Event | Beschreibung | Auslöser |
|---|---|---|
invoice.created | Eine neue Rechnung wurde erfolgreich erstellt | POST /api/v1/invoice/de/xrechnung/generate erfolgreich |
invoice.validated | Eine Rechnung wurde geprüft und ist konform | POST /api/v1/invoice/{countryCode}/validate liefert `valid: true` |
invoice.validation_failed | Validierung einer Rechnung ist fehlgeschlagen | E-Rechnung entspricht nicht dem Schema |
conversion.completed | Format-Konvertierung abgeschlossen | POST /api/v1/invoice/convert erfolgreich |
conversion.failed | Format-Konvertierung fehlgeschlagen | Konvertierungsfehler |
peppol.sent | E-Rechnung über Peppol versendet | Peppol-Übertragung erfolgreich |
peppol.delivered | Empfangsbestätigung von Peppol erhalten | MDN vom Empfänger |
peppol.failed | Peppol-Übertragung fehlgeschlagen | Übertragungsfehler |
Webhook Payload
Vorgesehenes Format: HTTP POST mit JSON-Body. Die Feldnamen entsprechen dem Rechnungsschema (`subtotal`, `total`, `taxSummary`) und der Generate-Antwort (`format`, `filename`, `mimeType`, `hash`):
1{2 "id": "evt_abc123xyz",3 "type": "invoice.created",4 "created": "2026-03-01T10:30:00Z",5 "data": {6 "object": {7 "invoiceNumber": "RE-2026-0042",8 "format": "xrechnung",9 "filename": "RE-2026-0042.xml",10 "mimeType": "application/xml",11 "hash": "9f2c1b7d4e8a03f5c6b9d0e1a2f3c4b5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1",12 "currency": "EUR",13 "subtotal": 1500.00,14 "total": 1785.00,15 "taxSummary": [16 { "taxRate": 19, "taxCategoryCode": "S", "netAmount": 1500.00, "taxAmount": 285.00 }17 ]18 }19 }20}HTTP Headers
X-Xhub-SignatureHMAC-SHA256 Signatur des Payloads
X-Xhub-EventEvent-Typ (z.B. invoice.created)
X-Xhub-DeliveryEindeutige Delivery-ID
X-Xhub-TimestampUnix-Timestamp der Signatur-Erstellung
Signatur-Verifizierung
Vorgesehen: Verifiziere die Signatur, um sicherzustellen, dass der Webhook von Invoice-api.xhub stammt:
Node.js / Express
1import crypto from 'crypto';2 3function verifyWebhookSignature(payload, signature, secret) {4 const expectedSignature = crypto5 .createHmac('sha256', secret)6 .update(payload)7 .digest('hex');8 9 const trusted = Buffer.from(`sha256=${expectedSignature}`, 'ascii');10 const untrusted = Buffer.from(signature, 'ascii');11 12 return crypto.timingSafeEqual(trusted, untrusted);13}14 15// Express.js Handler16app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {17 const signature = req.headers['x-xhub-signature'];18 const payload = req.body;19 20 if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {21 return res.status(401).send('Invalid signature');22 }23 24 const event = JSON.parse(payload);25 26 switch (event.type) {27 case 'invoice.created':28 console.log('Invoice created:', event.data.object.invoiceNumber);29 break;30 case 'invoice.validation_failed':31 console.log('Validation failed:', event.data.object.errors);32 break;33 }34 35 res.status(200).send('OK');36});Python / Flask
1import hmac2import hashlib3from flask import Flask, request, abort4 5app = Flask(__name__)6WEBHOOK_SECRET = 'your_webhook_secret'7 8def verify_signature(payload, signature, secret):9 expected = hmac.new(10 secret.encode(),11 payload,12 hashlib.sha25613 ).hexdigest()14 return hmac.compare_digest(f'sha256={expected}', signature)15 16@app.route('/webhook', methods=['POST'])17def webhook():18 signature = request.headers.get('X-Xhub-Signature')19 payload = request.data20 21 if not verify_signature(payload, signature, WEBHOOK_SECRET):22 abort(401)23 24 event = request.json25 26 if event['type'] == 'invoice.created':27 print(f"Invoice created: {event['data']['object']['invoiceNumber']}")28 elif event['type'] == 'invoice.validation_failed':29 print(f"Validation failed: {event['data']['object']['errors']}")30 31 return 'OK', 200Retry-Policy
Vorgesehen: Wenn dein Endpoint nicht mit 2xxantwortet, soll der Webhook nach diesem Plan erneut gesendet werden:
| Versuch | Wartezeit |
|---|---|
| 1 | Sofort |
| 2 | 1 Minute |
| 3 | 5 Minuten |
| 4 | 30 Minuten |
| 5 | 2 Stunden |
| 6 | 12 Stunden |
Nach 6 fehlgeschlagenen Versuchen soll der Webhook als fehlgeschlagen markiert und eine E-Mail-Benachrichtigung verschickt werden.
Best Practices
Schnell antworten
Antworte innerhalb von 5 Sekunden mit 200 OK. Verarbeite den Webhook asynchron im Hintergrund.
Signatur verifizieren
Verifiziere immer die HMAC-Signatur. Lehne Requests ohne gültige Signatur ab.
Idempotenz sicherstellen
Speichere die Delivery-ID und verarbeite jeden Webhook nur einmal (Duplikate können bei Retries auftreten).
HTTPS verwenden
Dein Webhook-Endpoint muss HTTPS unterstützen. HTTP-Endpoints werden nicht akzeptiert.
Webhook einrichten
Vorgesehen ist die Konfiguration im Dashboard. Dort soll möglich sein:
- • Endpoint-URL festlegen
- • Events auswählen, die gesendet werden sollen
- • Webhook-Secret einsehen und rotieren
- • Delivery-Logs und fehlgeschlagene Webhooks einsehen