Skip to Content
🔐 Closed Beta – Jetzt auf die Warteliste eintragen! Limitierte Plätze für Early Adopters →
De AtAPIWebhooks & Events

Webhooks & Events

Einleitung

💬

Hallo, ich bin Sophie! 👋 Mit Webhooks wirst Sie in Echtzeit über wichtige Ereignisse in BuchhaltGenie informiert. Anstatt ständig unsere API abzufragen, senden wir Ihnen automatisch Benachrichtigungen, sobald etwas Relevantes passiert - zum Beispiel wenn eine Rechnung bezahlt wurde oder ein neuer Kunde angelegt wurde.

Das ist nicht nur effizienter, sondern ermöglicht Ihnen auch, sofort auf Änderungen zu reagieren!

🔐

Sicherheitshinweis: Alle Webhooks werden mit HMAC-SHA256 signiert. Validiere IMMER die Signatur, bevor Sie einen Webhook verarbeitest. Das schützt Sie vor gefälschten Anfragen.


Wie funktionieren Webhooks?

Webhooks sind HTTP-POST-Anfragen, die BuchhaltGenie an Ihren Server sendet, wenn bestimmte Events eintreten:


Verfügbare Events

BuchhaltGenie sendet Webhooks für folgende Event-Kategorien:

Rechnungen

EventBeschreibungWann ausgelöst
invoice.createdNeue Rechnung erstelltBei Erstellung einer Rechnung
invoice.sentRechnung versendetWenn E-Mail an Kunden geht
invoice.paidRechnung bezahltBei Zahlungseingang
invoice.overdueRechnung überfälligWenn Fälligkeit überschritten
invoice.cancelledRechnung storniertBei Stornierung

Kunden

EventBeschreibungWann ausgelöst
customer.createdNeuer Kunde angelegtBei Kundenanlage
customer.updatedKundendaten geändertBei Änderung der Stammdaten
customer.deletedKunde gelöschtBei Löschung (Soft-Delete)

Zahlungen

EventBeschreibungWann ausgelöst
payment.receivedZahlung eingegangenBei Zahlungseingang
payment.failedZahlung fehlgeschlagenBei fehlgeschlagener Zahlung
payment.refundedZahlung rückerstattetBei Rückerstattung

Abonnements

EventBeschreibungWann ausgelöst
subscription.createdNeues AbonnementBei Abo-Abschluss
subscription.updatedAbo geändertBei Upgrade/Downgrade
subscription.cancelledAbo gekündigtBei Kündigung
subscription.renewedAbo verlängertBei automatischer Verlängerung

FinanzOnline (Österreich-spezifisch)

EventBeschreibungWann ausgelöst
uva.submittedUVA eingereichtBei UVA-Übermittlung
uva.confirmedUVA bestätigtBei Finanzamt-Bestätigung
uva.rejectedUVA abgelehntBei Ablehnung durch Finanzamt
💡

Sophie’s Tipp: Sie können mehrere Webhooks für unterschiedliche Event-Typen einrichten. So kannst Sie zum Beispiel Zahlungs-Events an Ihr Buchhaltungssystem und Kunden-Events an Ihr CRM senden.


Webhook einrichten

Endpoint erstellen

Erstelle einen HTTP-Endpoint auf Ihrem Server, der POST-Anfragen empfangen kann:

// Beispiel: Next.js API Route export async function POST(request: Request) { const body = await request.text(); const signature = request.headers.get('x-bg-signature'); // Signatur validieren (siehe nächster Abschnitt) if (!verifySignature(body, signature)) { return new Response('Ungültige Signatur', { status: 401 }); } const event = JSON.parse(body); // Event verarbeiten switch (event.type) { case 'invoice.paid': await handleInvoicePaid(event.data); break; // ... weitere Events } return new Response('OK', { status: 200 }); }

Webhook in BuchhaltGenie registrieren

Navigiere zu Einstellungen > API > Webhooks und klicken Sie auf “Webhook hinzufügen”:

  1. Gib Ihre Endpoint-URL ein (muss HTTPS sein)
  2. Wählen Sie die Events aus, die Sie empfangen möchtest
  3. Optional: Gib einen benutzerdefinierten Header hinzu
  4. Klicken Sie auf “Speichern”

Webhook-Secret sichern

Nach dem Speichern erhältst Sie ein Webhook-Secret im Format whsec_xxxx. Speichern Sie dieses sicher als Umgebungsvariable:

# .env BUCHHALTGENIE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxx

Endpoint testen

Klicken Sie auf “Test senden”, um einen Test-Webhook zu versenden und Ihre Integration zu prüfen.


Signatur-Validierung

⚠️

Kritisch: Validiere IMMER die Webhook-Signatur! Ohne Validierung könnte ein Angreifer gefälschte Webhooks an Ihren Server senden und Ihr System manipulieren.

So funktioniert die Signatur

BuchhaltGenie signiert jeden Webhook mit HMAC-SHA256:

  1. Timestamp + Payload werden kombiniert
  2. HMAC-SHA256 wird mit Ihrem Webhook-Secret berechnet
  3. Signatur wird im Header x-bg-signature mitgesendet
  4. Timestamp wird im Header x-bg-timestamp mitgesendet

Validierung implementieren

import crypto from 'crypto'; interface VerificationResult { valid: boolean; error?: string; } function verifyWebhookSignature( payload: string, signature: string | null, timestamp: string | null, secret: string ): VerificationResult { // Signatur und Timestamp prüfen if (!signature || !timestamp) { return { valid: false, error: 'Fehlende Signatur oder Timestamp' }; } // Timestamp-Freshness prüfen (max 5 Minuten) const timestampMs = parseInt(timestamp, 10) * 1000; const now = Date.now(); const fiveMinutes = 5 * 60 * 1000; if (Math.abs(now - timestampMs) > fiveMinutes) { return { valid: false, error: 'Timestamp zu alt (Replay-Angriff?)' }; } // Erwartete Signatur berechnen const signedPayload = `${timestamp}.${payload}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); // Timing-sicherer Vergleich const isValid = crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) ); return { valid: isValid }; } // Verwendung in Ihrem Webhook-Handler export async function POST(request: Request) { const payload = await request.text(); const signature = request.headers.get('x-bg-signature'); const timestamp = request.headers.get('x-bg-timestamp'); const verification = verifyWebhookSignature( payload, signature, timestamp, process.env.BUCHHALTGENIE_WEBHOOK_SECRET! ); if (!verification.valid) { console.error('Webhook-Validierung fehlgeschlagen:', verification.error); return new Response('Ungültige Signatur', { status: 401 }); } // Webhook verarbeiten... const event = JSON.parse(payload); // ... }

Sicherheits-Checkliste

PrüfungWarum wichtig
Signatur validierenVerhindert gefälschte Webhooks
Timestamp prüfenSchützt vor Replay-Angriffen
HTTPS verwendenVerschlüsselt Daten während Übertragung
Timing-sicherer VergleichVerhindert Timing-Angriffe
Secret sicher speichernNiemals im Code oder Repository

Webhook-Payload-Format

Jeder Webhook enthält eine standardisierte Payload-Struktur:

{ "id": "evt_1234567890abcdef", "type": "invoice.paid", "created": "2026-01-15T14:30:00Z", "api_version": "2026-01", "data": { "object": { "id": "inv_abc123", "customer_id": "cus_xyz789", "amount": 11900, "currency": "EUR", "status": "paid", "paid_at": "2026-01-15T14:30:00Z" }, "previous_attributes": { "status": "sent" } }, "business_id": "bus_123456", "correlation_id": "corr_xxxxxxxx" }

Payload-Felder erklärt

FeldTypBeschreibung
idstringEindeutige Event-ID (für Idempotenz)
typestringEvent-Typ (z.B. invoice.paid)
createdISO 8601Zeitpunkt des Events
api_versionstringAPI-Version
data.objectobjectDas betroffene Objekt
data.previous_attributesobjectVorherige Werte (bei Updates)
business_idstringDeine Business-ID
correlation_idstringID zur Nachverfolgung
💡

Sophie’s Tipp: Speichern Sie die id jedes verarbeiteten Webhooks in Ihrer Datenbank. So kannst Sie Duplikate erkennen und Webhooks idempotent verarbeiten - falls der gleiche Webhook mehrfach zugestellt wird.


Retry-Logik

BuchhaltGenie versucht, fehlgeschlagene Webhooks automatisch erneut zuzustellen:

Retry-Verhalten

VersuchWartezeitZeitpunkt nach erstem Versuch
1Sofort0 Minuten
21 Minute1 Minute
35 Minuten6 Minuten
430 Minuten36 Minuten
52 Stunden2,6 Stunden
68 Stunden10,6 Stunden
724 Stunden34,6 Stunden

Nach 7 fehlgeschlagenen Versuchen wird der Webhook als endgültig fehlgeschlagen markiert.

Was gilt als “erfolgreich”?

Ein Webhook gilt als erfolgreich zugestellt, wenn Ihr Endpoint mit einem HTTP-Statuscode 2xx (200-299) antwortet. Alle anderen Statuscodes lösen einen Retry aus.

// ✅ Erfolgreiche Antworten return new Response('OK', { status: 200 }); return new Response(JSON.stringify({ received: true }), { status: 200 }); // ❌ Lösen Retry aus return new Response('Error', { status: 500 }); return new Response('Not Found', { status: 404 }); // Timeout (keine Antwort innerhalb 30 Sekunden)

Best Practices für Ihre Webhook-Handler

⚠️

Performance-Tipp: Antworte IMMER schnell (unter 30 Sekunden)! Führe zeitaufwändige Verarbeitung asynchron durch.

// ✅ RICHTIG: Schnelle Antwort, asynchrone Verarbeitung export async function POST(request: Request) { const event = await parseAndValidate(request); // Event in Queue einreihen (schnell) await queue.add('process-webhook', event); // Sofort antworten return new Response('OK', { status: 200 }); } // ❌ FALSCH: Lange Verarbeitung vor Antwort export async function POST(request: Request) { const event = await parseAndValidate(request); // Zeitaufwändige Verarbeitung (kann Timeout verursachen!) await sendEmailNotification(event); await updateDatabase(event); await syncWithExternalSystem(event); return new Response('OK', { status: 200 }); }

Idempotenz

Webhooks können mehrfach zugestellt werden (bei Retries oder Netzwerkproblemen). Ihre Verarbeitung sollte daher idempotent sein:

async function handleInvoicePaid(event: WebhookEvent) { const eventId = event.id; const invoiceId = event.data.object.id; // Prüfen ob Event bereits verarbeitet wurde const existingEvent = await db.webhookEvents.findUnique({ where: { event_id: eventId } }); if (existingEvent) { console.log(`Event ${eventId} bereits verarbeitet, überspringe.`); return { success: true, skipped: true }; } // Event als "in Verarbeitung" markieren await db.webhookEvents.create({ data: { event_id: eventId, event_type: event.type, status: 'processing', received_at: new Date() } }); try { // Eigentliche Verarbeitung await markInvoiceAsPaid(invoiceId); // Erfolgreich abgeschlossen await db.webhookEvents.update({ where: { event_id: eventId }, data: { status: 'processed', processed_at: new Date() } }); return { success: true }; } catch (error) { // Fehler protokollieren await db.webhookEvents.update({ where: { event_id: eventId }, data: { status: 'failed', error: error.message } }); throw error; } }

Webhook-Logs einsehen

In BuchhaltGenie kannst Sie alle Webhook-Zustellungen einsehen:

  1. Navigiere zu Einstellungen > API > Webhooks
  2. Klicken Sie auf den gewünschten Webhook
  3. Wählen Sie den Tab “Zustellungsprotokoll”

Für jeden Zustellversuch siehst du:

  • Zeitpunkt der Zustellung
  • HTTP-Statuscode der Antwort
  • Antwortzeit in Millisekunden
  • Request-Payload (zum Debuggen)
  • Response-Body (falls vorhanden)

Häufige Probleme und Lösungen

🔧

Troubleshooting-Guide

Webhook kommt nicht an

  1. URL prüfen: Ist die URL korrekt und von außen erreichbar?
  2. HTTPS: BuchhaltGenie sendet nur an HTTPS-Endpoints
  3. Firewall: Erlaubt Ihre Firewall eingehende Verbindungen?
  4. Logs prüfen: Schau in das Zustellungsprotokoll

Signatur-Validierung schlägt fehl

  1. Raw Body: Verwende den unveränderten Request-Body
  2. Encoding: Body muss UTF-8-kodiert sein
  3. Secret: Prüfe, ob das richtige Secret verwendet wird
  4. Timestamp: Ist die Serverzeit korrekt synchronisiert?

Webhooks kommen doppelt an

  1. Idempotenz: Implementiere Duplikat-Erkennung
  2. Event-ID: Speichern Sie verarbeitete Event-IDs
  3. Timeout: Antworte schneller als 30 Sekunden

Webhook-Handler ist zu langsam

  1. Async Processing: Verarbeite asynchron
  2. Queue: Verwende eine Message Queue
  3. Acknowledge First: Antworte sofort mit 200

Compliance und Datenschutz

🔐

DSGVO & BAO Compliance

Datenschutz (DSGVO Art. 32)

  • Webhooks übertragen personenbezogene Daten (Kundennamen, Adressen)
  • Verwende HTTPS für verschlüsselte Übertragung
  • Speichern Sie Webhook-Daten gemäß Ihrer Datenschutzerklärung
  • Lösche nicht mehr benötigte Daten

Aufbewahrung (BAO 132)

  • Steuerrelevante Webhook-Daten (Rechnungen, Zahlungen) müssen 7 Jahre aufbewahrt werden
  • BuchhaltGenie protokolliert alle Webhooks intern
  • Führe eigene Protokolle für Ihre Verarbeitung

Audit-Trail

Alle Webhook-Zustellungen werden mit folgenden Daten protokolliert:

  • Zeitpunkt der Zustellung
  • Event-Typ und -ID
  • HTTP-Statuscode der Antwort
  • IP-Adresse des Empfängers
  • Correlation-ID für Nachverfolgung

API-Referenz: Webhook-Management

Webhooks auflisten

GET /api/v1/webhooks
{ "data": [ { "id": "wh_abc123", "url": "https://example.com/webhook", "events": ["invoice.paid", "invoice.created"], "status": "active", "created_at": "2026-01-15T10:00:00Z" } ] }

Webhook erstellen

POST /api/v1/webhooks Content-Type: application/json { "url": "https://example.com/webhook", "events": ["invoice.paid", "customer.created"] }

Webhook aktualisieren

PATCH /api/v1/webhooks/{id} Content-Type: application/json { "events": ["invoice.paid", "invoice.created", "customer.created"] }

Webhook löschen

DELETE /api/v1/webhooks/{id}

Secret rotieren

POST /api/v1/webhooks/{id}/rotate-secret

Weiterführende Ressourcen


Support

Bei Fragen zu Webhooks hilft Ihnen unser Entwickler-Support:

⚖️

Hinweis: Diese Dokumentation dient als technische Referenz. Bei komplexen Integrationsanforderungen empfehlen wir, einen erfahrenen Entwickler hinzuzuziehen. Für steuerrechtliche Fragen wende Sie bitte an Ihren Steuerberater.