Webhooks
Erhalten Sie Benachrichtigungen in Echtzeit, sobald Ereignisse eintreten
8 Min. Lesezeit
Leitfaden zu Webhooks
Die Ereigniszustellung ist noch nicht live. Sie können Webhook-Endpunkte heute bereits über das Entwicklerportal oder die unten beschriebene API anlegen und testen, und die Schaltfläche „Webhook testen“ stellt tatsächlich einen Test-Payload zu. Operate versendet echte Kontoereignisse (
invoice.paid,payment.receivedusw.) jedoch noch nicht automatisch, sobald sie eintreten – dieser Teil des Leitfadens beschreibt das vorgesehene Verhalten nach dem Go-live der Ereigniszustellung, nicht den heutigen Stand.
Mit Webhooks erhalten Sie Benachrichtigungen in Echtzeit, sobald in Ihrem Operate-Konto Ereignisse eintreten. Statt die API laufend abzufragen, schieben Webhooks die Daten an Ihren Server, sobald ein Ereignis auftritt.
So funktionieren Webhooks
- Sie registrieren die URL eines Webhook-Endpunkts
- Sie wählen aus, welche Ereignisse Sie abonnieren möchten
- Tritt ein Ereignis ein, sendet Operate einen HTTP-POST an Ihre URL
- Ihr Server verarbeitet das Ereignis und antwortet mit 200 OK
Webhooks einrichten
Über das Dashboard
- Öffnen Sie Entwicklerportal > Webhooks (
/developer/webhooks) - Klicken Sie auf Webhook-Endpunkt erstellen
- Geben Sie die URL Ihres Endpunkts ein (im Produktivbetrieb zwingend HTTPS)
- Wählen Sie die Ereignisse aus, die Sie erhalten möchten
- Klicken Sie auf Erstellen
Über die API
const response = await fetch('https://operate.guru/api/v1/webhooks/endpoints', { method: 'POST', headers: { 'Authorization': 'Bearer op_live_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://your-server.com/webhooks/operate', events: ['INVOICE_CREATED', 'INVOICE_PAID', 'PAYMENT_RECEIVED'], description: 'Production webhook' }) }); const { endpoint, secret } = await response.json(); // Save the secret securely - it's only shown once!
Ereignistypen
Ereignisse zu Ausgangsrechnungen
INVOICE_CREATED– neue Rechnung erstelltINVOICE_SENT– Rechnung an Kundin oder Kunden versendetINVOICE_PAID– Rechnung vollständig bezahltINVOICE_PARTIALLY_PAID– Teilzahlung eingegangenINVOICE_OVERDUE– Rechnung überfälligINVOICE_VOIDED– Rechnung storniert
Ereignisse zu Eingangsrechnungen
BILL_CREATED– neue Eingangsrechnung erhaltenBILL_APPROVED– Eingangsrechnung zur Zahlung freigegebenBILL_PAID– Eingangsrechnung bezahltBILL_OVERDUE– Eingangsrechnung überfällig
Zahlungsereignisse
PAYMENT_RECEIVED– Zahlung eingegangenPAYMENT_FAILED– Zahlung fehlgeschlagen
Ereignisse zu Kundinnen/Kunden und Lieferanten
CLIENT_CREATED– neue Kundin bzw. neuer Kunde angelegtCLIENT_UPDATED– Kundendatensatz aktualisiertVENDOR_CREATED– neuer Lieferant angelegtVENDOR_UPDATED– Lieferantendatensatz aktualisiert
Bankereignisse
BANK_TRANSACTION_IMPORTED– neue Transaktion importiertBANK_TRANSACTION_RECONCILED– Transaktion abgeglichen
Ereignisse zu Bestellungen
PURCHASE_ORDER_CREATED– neue Bestellung angelegtPURCHASE_ORDER_APPROVED– Bestellung freigegebenPURCHASE_ORDER_RECEIVED– Ware erhalten
Steuerereignisse
TAX_RETURN_DUE– Steuererklärung wird demnächst fälligTAX_FILING_SUBMITTED– Steuererklärung übermittelt
Webhook-Payload
Alle Webhooks haben ein einheitliches Format:
{ "id": "evt_abc123", "type": "INVOICE_PAID", "created": "2024-01-15T10:30:00Z", "data": { "id": "inv_xyz789", "number": "INV-2024-001", "customerName": "Acme Corp", "totalAmount": 1500.00, "currency": "EUR", "paidAt": "2024-01-15T10:30:00Z" } }
Signaturen prüfen
Prüfen Sie Webhook-Signaturen immer, um sicherzustellen, dass die Anfragen tatsächlich von Operate stammen.
Signatur-Header
X-Webhook-Signature: sha256=abc123...
X-Webhook-Event: INVOICE_PAID
X-Webhook-Delivery-Id: del_xyz789
Prüfcode (Node.js)
const crypto = require('crypto'); function verifyWebhookSignature(payload, signature, secret) { const expectedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(`sha256=${expectedSignature}`) ); } // Express.js example app.post('/webhooks/operate', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-webhook-signature']; const payload = req.body.toString(); if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(payload); switch (event.type) { case 'INVOICE_PAID': handleInvoicePaid(event.data); break; case 'PAYMENT_RECEIVED': handlePaymentReceived(event.data); break; } res.status(200).send('OK'); });
Prüfcode (Python)
import hmac import hashlib def verify_webhook_signature(payload, signature, secret): expected = hmac.new( secret.encode(), payload.encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(f'sha256={expected}', signature)
Wiederholungsstrategie
Antwortet Ihr Endpunkt nicht innerhalb von 30 Sekunden mit einem 2xx-Status, wiederholen wir die Zustellung:
| Versuch | Verzögerung |
|---|---|
| 1 | sofort |
| 2 | 1 Minute |
| 3 | 5 Minuten |
| 4 | 30 Minuten |
Nach 4 fehlgeschlagenen Versuchen gilt die Zustellung als gescheitert.
Webhooks testen
Über den Test-Endpunkt
// Send a test webhook await fetch('https://operate.guru/api/v1/webhooks/endpoints/wh_abc123/test', { method: 'POST', headers: { 'Authorization': 'Bearer op_live_your_api_key' } });
Mit ngrok in der lokalen Entwicklung
# Expose local server ngrok http 3000 # Use the ngrok URL for your webhook endpoint # https://abc123.ngrok.io/webhooks/operate
Mehrfachzustellungen behandeln
Webhooks können mehr als einmal zugestellt werden (Netzwerkprobleme, Wiederholungen usw.). Ihr Endpunkt muss daher idempotent sein.
Idempotenz-Muster
const processedEvents = new Set(); // Or use a database app.post('/webhooks/operate', async (req, res) => { const event = req.body; const eventId = event.id; // Check if already processed if (processedEvents.has(eventId)) { console.log(`Event ${eventId} already processed, skipping`); return res.status(200).send('OK'); } // Process event await processEvent(event); // Mark as processed processedEvents.add(eventId); // Store in DB for persistence across restarts res.status(200).send('OK'); });
Mit einer Datenbank
// Check if event already processed const existing = await db.webhookEvents.findUnique({ where: { eventId: event.id } }); if (existing) { return res.status(200).send('Already processed'); } // Process event await processEvent(event); // Mark as processed await db.webhookEvents.create({ data: { eventId: event.id, processedAt: new Date(), eventType: event.type } });
Muster für asynchrone Verarbeitung
Blockieren Sie die Webhook-Antwort nicht – verarbeiten Sie asynchron:
Mit einer Queue
const Queue = require('bull'); const webhookQueue = new Queue('webhooks'); app.post('/webhooks/operate', async (req, res) => { const signature = req.headers['x-webhook-signature']; const payload = req.body; // Verify signature (fast) if (!verifySignature(payload, signature, SECRET)) { return res.status(401).send('Invalid signature'); } // Add to queue (fast) await webhookQueue.add(payload); // Respond immediately res.status(200).send('Queued'); }); // Process queue in background webhookQueue.process(async (job) => { const event = job.data; await processEvent(event); });
Mit Workern
const { Worker } = require('worker_threads'); app.post('/webhooks/operate', async (req, res) => { // Verify signature // ... // Spawn worker const worker = new Worker('./webhook-processor.js', { workerData: req.body }); // Respond immediately res.status(200).send('Processing'); // Handle worker completion/error in background worker.on('message', (result) => { console.log('Worker completed:', result); }); });
Beispiele für Ereignisse
Ereignis INVOICE_PAID
{ "id": "evt_abc123", "type": "INVOICE_PAID", "created": "2024-01-15T10:30:00Z", "data": { "id": "inv_xyz789", "number": "INV-2024-001", "customerName": "Acme Corp", "customerId": "client_123", "totalAmount": 1500.00, "currency": "EUR", "paidAt": "2024-01-15T10:30:00Z", "paymentMethod": "BANK_TRANSFER", "transactionId": "txn_456" } }
Ereignis TRANSACTION_IMPORTED
{ "id": "evt_def456", "type": "BANK_TRANSACTION_IMPORTED", "created": "2024-01-15T08:00:00Z", "data": { "id": "txn_789", "accountId": "acc_123", "amount": -250.50, "currency": "EUR", "date": "2024-01-14", "description": "Office supplies", "category": "OFFICE_SUPPLIES", "vendor": "Staples", "matched": false } }
Ereignis PURCHASE_ORDER_RECEIVED
{ "id": "evt_ghi789", "type": "PURCHASE_ORDER_RECEIVED", "created": "2024-01-15T14:20:00Z", "data": { "id": "po_456", "vendorName": "Supplier Co", "totalAmount": 5000.00, "currency": "EUR", "status": "RECEIVED", "receivedAt": "2024-01-15T14:20:00Z", "receivedBy": "John Smith", "items": [ { "description": "Office Supplies", "quantityOrdered": 100, "quantityReceived": 95, "unitPrice": 5.50 } ] } }
Fehlersuche bei Webhooks
Protokollierung aktivieren
app.post('/webhooks/operate', (req, res) => { console.log('Webhook received:', { eventId: req.body.id, eventType: req.body.type, timestamp: new Date().toISOString(), signature: req.headers['x-webhook-signature'] }); // Process... });
Test mit curl
curl -X POST https://your-server.com/webhooks/operate \ -H "Content-Type: application/json" \ -H "X-Webhook-Signature: sha256=test123" \ -H "X-Webhook-Event: INVOICE_PAID" \ -d '{ "id": "evt_test", "type": "INVOICE_PAID", "created": "2024-01-15T10:30:00Z", "data": { "id": "inv_123" } }'
Zustellprotokolle ansehen
Den Zustellstatus Ihrer Webhooks finden Sie im Operate-Dashboard:
- Öffnen Sie Entwicklerportal > Webhooks (
/developer/webhooks) - Klicken Sie auf den Namen des Webhook-Endpunkts
- Öffnen Sie den Reiter Letzte Zustellungen
Angezeigt werden:
- Zeitstempel der Zustellung
- zurückgegebener HTTP-Statuscode
- Antwortzeit
- Wiederholungsversuche
- Fehlermeldungen (bei Fehlschlag)
Sicherheits-Checkliste für Webhooks
✅ Signaturen prüfen – bei jeder Anfrage ✅ HTTPS verwenden – für Ihren Endpunkt (im Produktivbetrieb zwingend) ✅ 200 zurückgeben – innerhalb von 30 Sekunden ✅ Asynchron verarbeiten – die Antwort nicht blockieren ✅ Mehrfachzustellungen behandeln – idempotente Verarbeitung ✅ Payload validieren – die Struktur vor der Verarbeitung prüfen ✅ Alle Ereignisse protokollieren – für die Fehlersuche ✅ Secrets rotieren – alle 90 Tage ✅ Fehlschläge überwachen – und Alarme einrichten ✅ Gründlich testen – vor dem Go-live
Bewährte Vorgehensweisen
- Schnell antworten – sofort 200 OK zurückgeben und asynchron in Queue oder Worker verarbeiten
- Idempotent sein – Mehrfachzustellungen sauber über die Ereignis-ID abfangen
- Signaturen prüfen – die Echtheit eines Webhooks immer per HMAC validieren
- Alles protokollieren – Aufzeichnungen für Fehlersuche und Nachvollziehbarkeit aufbewahren
- Fehler sauber behandeln – die Verarbeitung einreihen, wenn Ihr System nicht erreichbar ist
- HTTPS verwenden – im Produktivbetrieb aus Sicherheitsgründen zwingend
- Überwachung einrichten – bei fehlgeschlagenen Zustellungen alarmieren
- Mit ngrok testen – lokal testen, bevor Sie in den Produktivbetrieb gehen
- Secrets regelmäßig rotieren – mindestens alle 90 Tage
- Ihren Endpunkt dokumentieren – damit spätere Wartung leichtfällt
Zustellverlauf ansehen
Den Zustellstatus Ihrer Webhooks finden Sie im Dashboard oder über die API:
// Get delivery history const deliveries = await fetch( 'https://operate.guru/api/v1/webhooks/deliveries?endpointId=wh_abc123', { headers: { 'Authorization': 'Bearer op_live_your_api_key' } } ).then(r => r.json());
Secrets rotieren
Rotieren Sie Ihr Webhook-Secret aus Sicherheitsgründen regelmäßig:
await fetch('https://operate.guru/api/v1/webhooks/endpoints/wh_abc123/rotate-secret', { method: 'POST', headers: { 'Authorization': 'Bearer op_live_your_api_key' } });