Webhooks, die du sendest: Ein zuverlässiges Outbound-Webhook-System für deine API entwerfen
Die meisten Webhook-Tutorials drehen sich um das Empfangen: wie du eine Signatur prüfst, wie du schnell mit 200 antwortest, wie du asynchron verarbeitest. Das ist alles nützlich. Wenn dein SaaS-Produkt aber Events an Kunden-Endpunkte schickt, stehst du auf der anderen Seite dieses Vertrags. Du schreibst den Zustellcode. Und ein zuverlässiges Outbound-Webhook-System zu bauen ist ein wirklich anderes Problem.
Kunden bauen Automatisierung auf deinen Events auf. Sie schreiben Code, der davon ausgeht, dass deine Webhooks in der richtigen Reihenfolge ankommen, dass Retries irgendwann aufhören und dass eine 200-Antwort bedeutet, dass du dasselbe Event nicht erneut sendest. Wenn dein System diese Annahmen bricht, brichst du ihre Systeme. In diesem Beitrag geht es darum, eine Outbound-Webhook-Pipeline mit Zustellgarantien zu entwerfen, auf die sich Kunden tatsächlich verlassen können.
Warum Outbound-Webhook-Zustellung ein Problem verteilter Systeme ist
Einen HTTP-Request an eine Kunden-URL zu senden klingt einfach. Ist es aber nicht, weil du die andere Seite nicht kontrollierst.
Der empfangende Server kann langsam sein, 500er zurückgeben, hinter einer Firewall stehen, die sich gerade geändert hat, oder einfach ausgefallen sein. Dein Zustellversuch läuft vielleicht nach 5 Sekunden in einen Timeout, obwohl der Handler des Kunden tatsächlich gelaufen ist und Erfolg hatte. Vielleicht bekommst du eine 200, die gesendet wurde, bevor der Handler die Verarbeitung abgeschlossen hat. Jedes dieser Szenarien kann dein System in einem unklaren Zustand hinterlassen: Hat der Kunde das Event erhalten oder nicht?
Diese Unklarheit macht Outbound-Webhook-Zustellung zu einem Problem verteilter Systeme. Du musst dafür explizit entwerfen, statt zu hoffen, dass HTTP sich darum kümmert.
Die zwei Eigenschaften, die Kunden wirklich von deinem System brauchen, sind: At-least-once-Zustellung (jedes Event erreicht sie irgendwann, auch wenn es mehrere Versuche braucht) und idempotente Payloads (dasselbe Event zweimal zu senden beschädigt ihre Daten nicht). Beides richtig hinzubekommen erfordert bewussten Entwurf auf deiner Seite.
Die Kernarchitektur: Event-Erzeugung von der Zustellung entkoppeln
Der erste Fehler, den die meisten Teams machen, ist der Versuch, Webhook-Events inline zuzustellen - die Kunden-URL synchron innerhalb des Requests aufzurufen, der das Event ausgelöst hat. Damit entsteht eine harte Abhängigkeit zwischen der Antwortzeit deiner API und der Latenz eines externen HTTP-Requests, den du nicht kontrollierst. Und wenn die Zustellung fehlschlägt, hast du keinen sauberen Weg, es erneut zu versuchen.
Das richtige Muster trennt Event-Erzeugung von Zustellung:
- Wenn etwas passiert (eine Zahlung geht durch, ein Nutzer wird angelegt, ein Abonnement ändert sich), schreibe einen Event-Datensatz in derselben Transaktion in deine Datenbank. Versuche noch keine Zustellung.
- Ein Background-Worker nimmt offene Events auf und versucht die Zustellung.
- Der Worker aktualisiert den Event-Datensatz anhand des Ergebnisses und plant bei Bedarf Retries ein.
Diese Architektur bedeutet, dass deine API-Antworten nie von der Latenz eines Kunden-Endpunkts blockiert werden. Sie gibt dir außerdem einen dauerhaften Datensatz zu jedem Event und jedem Zustellversuch - den du für Debugging und für kundenseitige Zustellprotokolle brauchst.
Der Event-Datensatz sollte mindestens enthalten: eine stabile Event-ID, den Event-Typ, die vollständige Payload als JSON, die Ziel-URL zum Zeitpunkt der Erzeugung, den aktuellen Zustellstatus, die Anzahl der Versuche und den Zeitstempel des nächsten geplanten Versuchs.
Retry-Logik: Exponential Backoff mit Obergrenze
Wenn ein Zustellversuch fehlschlägt, musst du es erneut versuchen. Die Frage ist, wann und wie lange.
Exponential Backoff ist der richtige Ausgangspunkt. Der Abstand zwischen den Versuchen wächst mit jedem Fehlschlag: 30 Sekunden, 5 Minuten, 30 Minuten, 2 Stunden, 12 Stunden, 24 Stunden. So bekommen vorübergehende Fehler - ein kurzer Ausfall, ein Deployment-Neustart, ein erreichtes Rate Limit - Zeit, sich aufzulösen, ohne einen ohnehin angeschlagenen Endpunkt zu überfahren. Der genaue Zeitplan ist weniger wichtig als die Tatsache, dass es überhaupt einen gibt.
Setze eine Obergrenze für die Anzahl der Versuche. Üblich ist irgendwo zwischen 10 und 20. Wenn der letzte Versuch fehlschlägt, überführe das Event in einen Dead-Letter-Zustand und höre auf, es erneut zu versuchen. Unbegrenzt weiterzumachen ist kein Feature - es erzeugt unbegrenzte Systemlast und verwirrt Kunden, die das Problem bereits untersucht und gelöst haben.
Setze auch eine Obergrenze für das Zustellfenster. Viele Teams begrenzen Retries auf 72 Stunden ab dem ursprünglichen Event. Wenn etwas nach drei Tagen nicht zugestellt ist, ist es meist nicht mehr handlungsrelevant - das System des Kunden ist weitergezogen, und ein veraltetes Event zuzustellen kann mehr Probleme verursachen, als es zu überspringen.
Halte deinen HTTP-Timeout knapp. 10 Sekunden reichen normalerweise. Ein Kunden-Endpunkt, der länger braucht, ist entweder überlastet oder defekt, und länger zu warten hilft niemandem. Wenn die Verbindung in einen Timeout läuft, behandle das als Fehlschlag und plane einen Retry ein.
Payload-Signierung: Kunden prüfen lassen, dass du wirklich du bist
Wenn dein Webhook an einem Kunden-Endpunkt ankommt, hat der Kunde keine Möglichkeit zu wissen, dass er von dir stammt, solange du ihn nicht signierst. Jeder, der die Webhook-URL eines Kunden kennt, könnte eine gefälschte Payload posten.
Der Standardansatz ist HMAC-SHA256. Berechne für jeden Zustellversuch eine Signatur über den rohen Request-Body mit einem geheimen Schlüssel, den du und der Kunde teilen. Füge die Signatur in einen Request-Header ein (X-Webhook-Signature oder ähnlich). Füge außerdem einen Zeitstempel hinzu (X-Webhook-Timestamp), damit Kunden Replays alter Requests ablehnen können.
Der Signaturschlüssel sollte pro Webhook-Endpunkt gelten, nicht pro Kunde. So können Kunden Schlüssel rotieren, ohne alle ihre Endpunkte zu beeinflussen, und du kannst begrenzen, was ein kompromittierter Schlüssel anrichten kann. Gib Kunden in deinem Dashboard einen Self-Service-Ablauf für die Schlüsselrotation.
Dokumentiere den genauen Signieralgorithmus mit funktionierenden Codebeispielen in mehreren Sprachen. Kunden kopieren diesen Code direkt. Wenn deine Dokumentation falsch oder unklar ist, bekommst du Support-Tickets von Kunden mit defekten Integrationen, die eigentlich an deiner Dokumentation liegen.
Event-Reihenfolge: Sei ehrlich bei deinen Garantien
Kunden gehen davon aus, dass deine Events in der richtigen Reihenfolge ankommen, solange du nichts anderes sagst. Meist liegen sie damit falsch, und du musst entscheiden, was du tatsächlich garantierst.
Echte Reihenfolgegarantien sind teuer. Sie erfordern Zustell-Queues pro Kunde, serielle Verarbeitung innerhalb jeder Queue und einen sorgfältigen Umgang mit Fehlern, der ein hängendes Event nicht alles dahinter blockieren lässt. Das ist machbar, aber es ist ein echtes System mit echtem Betriebsaufwand.
Ein einfacherer und oft besserer Ansatz: Stelle Events so schnell wie möglich zu (was bedeutet, meist in der richtigen Reihenfolge), nimm eine Sequenznummer oder einen created_at-Zeitstempel in jede Payload auf und dokumentiere, dass Kunden dieses Feld nutzen sollten, um Zustellungen in falscher Reihenfolge zu behandeln. Sage ihnen ausdrücklich, dass Retries dazu führen können, dass frühere Events nach späteren ankommen.
Wenn du Reihenfolgegarantien anbietest, grenze sie sorgfältig ein. Reihenfolge innerhalb einer bestimmten Ressource (alle Events für Order-ID 12345 kommen in der richtigen Reihenfolge an) ist besser erreichbar als globale Reihenfolge über alle Events hinweg. Sei in deiner Dokumentation konkret, was deine Garantie abdeckt.
Idempotenz: Lass die Event-ID echte Arbeit leisten
Jedes Event, das du sendest, sollte eine stabile, eindeutige ID haben, die du in die Payload und in einen eigenen Request-Header aufnimmst (X-Event-ID oder Webhook-Event-ID).
Kunden sollten diese ID nutzen, um Events auf ihrer Seite zu deduplizieren. Sie werden dasselbe Event mehr als einmal erhalten - deine Retry-Logik garantiert das. Ohne eine stabile ID, die sie als Idempotency Key verwenden können, können sie Retries nicht sicher verarbeiten.
Erzeuge keine neue ID für jeden Zustellversuch. Die ID identifiziert das Event, nicht den Versuch. Die Versuchsnummer ist separate Metadaten. Wenn du das Event evt_abc123 dreimal sendest, bevor der Endpunkt des Kunden wieder online ist, sollten alle drei Requests evt_abc123 tragen, und der Kunde sollte den ersten erfolgreichen verarbeiten und den Rest ignorieren.
Verwende für Event-IDs UUIDs oder ähnlich kollisionsresistente Identifier. Fortlaufende Ganzzahlen verraten Informationen über dein Event-Volumen und erzeugen Contention in Systemen mit hohem Durchsatz.
Zustellprotokolle: Kunden Einblick geben
Wenn die Integration eines Kunden kaputtgeht, ist das Erste, was er tut, sich in dein Dashboard einzuloggen und nach Informationen zu suchen, was passiert ist. Wenn du keine Zustellprotokolle hast, öffnet er ein Support-Ticket. Wenn du Zustellprotokolle hast, kann er sich vielleicht selbst helfen.
Protokolliere jeden Zustellversuch: die Event-ID, die Versuchsnummer, den Zeitstempel, den Statuscode der Antwort, den Antwort-Body (bei Bedarf gekürzt) und den Fehlergrund, falls der Request scheiterte, bevor eine Antwort kam. Mache das in deinem Dashboard zugänglich und idealerweise auch über deine API.
Diese Daten sind auch für dein eigenes Team nützlich. Wenn Kunden fehlende Events melden, sind Zustellprotokolle die erste Stelle, an der du nachsiehst. Ohne sie ist das Debugging von Webhook-Zustellproblemen größtenteils Raten.
Die Aufbewahrungsdauer ist wichtig. Zustellprotokolle 30 Tage zu behalten reicht meist. Länger, und die Speicherkosten fangen an ins Gewicht zu fallen; kürzer, und du kannst ältere Meldungen nicht untersuchen.
Dein eigenes Webhook-System testen
Der schwierigste Teil beim Testen von Outbound-Webhook-Zustellung ist, einen schlechten Empfänger zu simulieren. Du musst langsame Antworten, Timeouts, 500er-Fehler und den Fall testen können, dass der Empfänger 200 zurückgibt, aber vor der Verarbeitung abstürzt.
Dienste wie webhook.site und Svix Playground sind für manuelle Inspektion nützlich, aber du willst automatisierte Tests, die Fehlerfälle simulieren können. Ein einfacher Test-Empfänger, den du so konfigurieren kannst, dass er beliebige Statuscodes und Verzögerungen zurückgibt, deckt die meisten Szenarien ab.
Teste deine Retry-Backoff-Logik explizit. Prüfe, dass Events nach einer konfigurierbaren Anzahl von Fehlschlägen in den Dead-Letter-Zustand gelangen, statt endlos weiter versucht zu werden. Teste, dass die Signierung korrekt angewendet wird, indem du die Signatur mit demselben Algorithmus prüfst, den du für Kunden dokumentierst. Teste, dass doppelte Zustellung sicher ist - dass dasselbe Event zweimal zu senden in einem Test-Consumer keinen inkonsistenten Zustand erzeugt.
Betriebliche Themen: Monitoring und Kundenkommunikation
Sobald dein Webhook-System in Produktion läuft, musst du wissen, wann es Probleme hat. Alarmiere, wenn die Tiefe der Dead-Letter-Queue schneller wächst als üblich. Alarmiere, wenn die durchschnittliche Zustelllatenz erfolgreicher Events anfängt zu steigen. Alarmiere, wenn ein bestimmter Kunden-Endpunkt seit mehr als einer Stunde durchgehend fehlschlägt - der Kunde weiß vielleicht nicht, dass seine Integration defekt ist.
Entscheide im Vorfeld, wie du mit Kunden umgehst, deren Endpunkte dauerhaft fehlschlagen. Viele Teams deaktivieren die Webhook-Zustellung automatisch ab einer Schwelle aufeinanderfolgender Fehlschläge (etwa 5 Tage ohne erfolgreiche Zustellung) und senden dem Kunden eine E-Mail. Das verhindert, dass deine Retry-Worker Ressourcen für offensichtlich defekte Endpunkte verbrauchen, und es bringt Kunden dazu, nachzusehen, statt still Events zu verlieren.
Kommuniziere größere Störungen proaktiv. Wenn dein Webhook-Zustellsystem einen Ausfall hatte und Events verzögert oder verloren sind, sage es den Kunden, bevor sie es dir sagen. Ein kurzes Status-Update - was passiert ist, welche Events betroffen waren, was du dagegen tust - ist für das Vertrauen deutlich besser, als wenn Kunden das Problem selbst entdecken.
Wann du Svix, Hookdeck oder einen Managed Service nutzen solltest
Diese Infrastruktur von Grund auf zu bauen ist nicht immer die richtige Entscheidung. Dienste wie Svix und Hookdeck bieten Outbound-Webhook-Infrastruktur als Service: verwaltete Zustellung, Retry-Logik, Signierung, Zustellprotokolle, kundenseitige Dashboards und SDKs. Wenn Webhooks nicht dein Kernprodukt sind und du keine starken Gründe hast, die Zustellmechanik selbst zu bauen, ist ein Managed Service oft der schnellere und zuverlässigere Weg.
Der Kompromiss sind Kosten, Anbieterabhängigkeit und die Grenzen dessen, was der Dienst unterstützt. Für die meisten SaaS-Produkte in frühen Phasen gewinnt der Managed Service. Bei einem Produkt, bei dem Webhook-Zustellung selbst ein Unterscheidungsmerkmal ist, oder bei ungewöhnlichen Anforderungen an Reihenfolge oder Payload-Größe, gibt dir eine eigene Lösung mehr Kontrolle.
Die Grundlagen richtig hinbekommen
Ein zuverlässiges Outbound-Webhook-System läuft auf eine Handvoll Entscheidungen hinaus, die du früh bewusst treffen musst:
Entkopple Event-Erzeugung von Zustellung über eine persistente Queue. Nutze Exponential Backoff mit einer Obergrenze für Versuche und Zeit. Signiere jede Payload und dokumentiere den Signieralgorithmus mit funktionierenden Beispielen. Sei explizit bei deinen Reihenfolgegarantien. Gib jedem Event eine stabile ID, die Kunden zur Deduplizierung nutzen können. Führe Zustellprotokolle und mache sie für Kunden zugänglich.
Nichts davon ist für sich genommen komplex. Die Herausforderung ist, alles konsistent zu tun und es funktionsfähig zu halten, während dein Event-Volumen und dein Kundenstamm wachsen.
Wenn du ein Outbound-Webhook-System baust und vor der Implementierung ein technisches Review des Entwurfs möchtest, melde dich unter hello@wolf-tech.io. Wir arbeiten mit SaaS-Teams an API-Architektur und individueller Softwareentwicklung, wo die Details verteilter Systeme - Zustellgarantien, Retry-Semantik, Fehlerfälle - das Produkt sind. Mehr dazu, wie wir solche Arbeit angehen, findest du auf wolf-tech.io.

