10. Dez. 2025·6 Min. Lesezeit

Replay‑Schutz für Webhooks: Duplikate zuverlässig verhindern

Replay‑Schutz für Webhooks verhindert doppelte Abbuchungen und Aktionen, indem Signaturen geprüft, Zeitfenster durchgesetzt und Idempotenzschlüssel sicher gespeichert werden.

Replay‑Schutz für Webhooks: Duplikate zuverlässig verhindern

Warum doppelte Webhooks vorkommen und warum das wichtig ist

Ein Webhook ist eine Nachricht, die ein Dienst an Ihre App sendet (meist eine HTTP‑Anfrage), um mitzuteilen, dass ein Ereignis stattgefunden hat — zum Beispiel eine Zahlung erfolgreich war oder ein Abo gekündigt wurde.

Der Haken: „gesendet“ heißt nicht „einmal verarbeitet“. Die meisten Provider liefern Webhooks mit einer „mindestens einmal“-Garantie. Wenn Ihr Endpoint time‑outet, 5xx zurückgibt oder die Antwort auf dem Rückweg verloren geht, versucht der Provider es erneut. Diese Retries sind ungewollte Duplikate: dasselbe reale Ereignis wird mehrmals zugestellt.

Replays sind etwas anderes. Bei einem Replay‑Angriff fängt jemand eine gültige Webhook‑Anfrage ab und sendet sie später erneut, um denselben Effekt noch einmal auszulösen. Die Anfrage kann legitim aussehen; ohne Replay‑Schutz akzeptieren Sie eine alte Nachricht wie eine neue.

Wenn Duplikate oder Replays wie neue Ereignisse behandelt werden, sind die Folgen schnell real: doppelte Abbuchungen oder Rückerstattungen, doppelte E‑Mails, Inventar zweimal reduziert, doppelte Abos oder Rechnungen und Analytics, die nicht mehr mit der Realität übereinstimmen.

Das Ziel ist simpel zu sagen und leicht falsch umzusetzen: Jedes gültige Ereignis genau einmal akzeptieren und Wiederholungen sicher ignorieren. „Sicher“ ist wichtig, denn legitime Retries sind normal, während manipulierte Requests und veraltete Replays abgelehnt werden sollten.

Ein guter Handler behandelt jede eingehende Webhook‑Anfrage als nicht vertrauenswürdig, bis das Gegenteil bewiesen ist. Er überprüft, wer sie geschickt hat, prüft, ob sie frisch genug ist, und speichert einen stabilen „bereits verarbeitet“-Marker, sodass eine zweite Zustellung eine No‑Op wird.

Häufige Ursachen für Duplikate und Replays

Doppelte Zustellungen sind erwartetes Verhalten. Selbst wenn alles funktioniert, kann dasselbe Ereignis erneut ankommen.

Die häufigste Ursache sind Retries nach einem Timeout oder einer 5xx‑Antwort. Möglicherweise haben Sie die Verarbeitung bereits abgeschlossen, aber der Provider hat kein klares Erfolgssignal erhalten. Netzwerkprobleme führen zum gleichen Ergebnis: die Anfrage gelingt, die Antwort geht verloren oder ein Proxy setzt die Verbindung zurück.

Duplikate können auch aus Ihrem eigenen System stammen und beim Review wie „Webhook‑Probleme“ aussehen: ein Nutzer klickt zweimal auf einen Button, eine Automation läuft in einer Schleife oder eine Queue liefert nach einem Worker‑Crash neu aus.

Typische Quellen sind Provider‑Retries, manuelle erneute Zustellungen im Dashboard, Antwortverlust nach erfolgreicher Verarbeitung, Queue‑Redelivery und Integrations‑Loops.

Replays sind die besorgniserregendere Variante. Ein Angreifer (oder ein fehlerhafter Client) kann eine alte, vorher gültige Anfrage erneut senden. Ohne Replay‑Schutz können dadurch Aktionen wie Zugriffsgewährung, Kontoänderungen oder Rechnungsstellungen wiederholt werden.

Ein einfaches Fehlerszenario: Ihr Handler erzeugt bei payment_succeeded eine Rechnung. Wird das Event dreimal wiederholt oder einen Tag später replayed, können mehrere Rechnungen entstehen — sofern Sie nicht Signaturen prüfen, ein Zeitfenster durchsetzen und per Idempotency‑Key dedupen.

Signaturprüfung: Ihre erste Verteidigungslinie

Signaturprüfung blockiert die meisten gefälschten Webhooks, bevor sie Ihr System erreichen. Eine gültige Signatur beweist, dass die Nutzlast unterwegs nicht verändert wurde (Integrität) und dass sie von jemandem stammt, der das gemeinsame Secret kennt (Authentizität).

Das ist ein wichtiger Teil des Replay‑Schutzes, weil so zufällige Dritte keine Events erfinden können. Allein schützt die Signatur jedoch nicht davor, dass ein legitimer Sender dasselbe Ereignis mehrfach zustellt. Sie stellt nur sicher, dass Sie echte Nachrichten verarbeiten.

Worauf Teams hereinfallen, ist das Vertrauen in das Vorhandensein eines Headers anstelle der tatsächlichen Verifikation. Ein Request mit X-Signature: abc123... bedeutet nichts, wenn Sie die Signatur nicht auf Ihrer Seite über den rohen Request‑Body und Ihr Secret nachrechnen.

Ein brauchbarer Verifikationsablauf ist:

  • Sofort ablehnen, wenn der Signatur‑Header fehlt.
  • Die rohen Body‑Bytes lesen (nicht das geparste JSON‑Objekt).
  • Den erwarteten HMAC (oder den vom Provider spezifizierten Algorithmus) über exakt diese Bytes berechnen.
  • Vergleich mittels einer konstantzeitigen Funktion durchführen.
  • Erst danach JSON parsen und Datenbank‑Arbeit ausführen.

Ein Vergleich in konstanter Zeit ist sinnvoll, weil normale String‑Vergleiche über Timing‑Unterschiede Informationen leaken können.

Und: schnell abbrechen. Wenn Sie die Signatur erst nach dem Parsen großer Payloads prüfen, geben Sie Angreifern einen einfachen Weg, Ihre CPU zu verbrennen. Behandeln Sie fehlende oder ungültige Signaturen wie eine verschlossene Tür: früh stoppen, minimale Details loggen und einen Fehler zurückgeben, ohne weitere Arbeit zu leisten.

Zeitfenster: Replays ablaufen lassen

Ein Zeitfenster limitiert, wie lange eine abgefangene Webhook‑Anfrage nützlich bleibt. Am besten funktioniert das, wenn der Sender einen Zeitstempel mitsendet und diesen zusammen mit dem Body signiert.

Der Ablauf ist einfach: Signatur prüfen, dann prüfen, ob der Zeitstempel frisch genug ist. Wird dieselbe Anfrage Stunden später erneut gesendet, scheitert sie an der Frischeprüfung.

Wie man das Fenster wählt

Viele Teams starten mit einer kleinen erlaubten Abweichung, z. B. 5 Minuten. Das reicht meist für normale Netzverzögerungen und Queueing, ohne alte Nachrichten durchzulassen.

Ein praktisches Vorgehen:

  • Extrahieren Sie den Zeitstempel aus dem Header des Providers (oder aus der Payload, falls das deren Format ist).
  • Verifizieren Sie die Signatur, wobei Sie denselben Zeitstempelwert als Teil der signierten Eingabe verwenden.
  • Vergleichen Sie ihn mit Ihrer Serverzeit und akzeptieren Sie nur innerhalb des Skew‑Fensters.
  • Außerhalb des Fensters behandeln Sie die Anfrage als Replay, selbst wenn die Signatur gültig ist.

Zeitdrift ist die stille Fehlerquelle. Ist Ihre Serverzeit falsch, lehnen Sie gute Events ab. Halten Sie Hosts zeit‑synchronisiert und vergleichen Sie gegen die Serverzeit, nicht gegen Client‑Zeit.

Bei verspäteten Events entscheiden Sie vorher, ob Sie sie strikt ablehnen oder zur manuellen Überprüfung weiterleiten. Wenn Ihr Provider gelegentlich verzögerte Webhooks liefert, ist Loggen und Review oft sicherer als automatische Verarbeitung außerhalb des Fensters.

Idempotency‑Keys: wie Dedupe praktisch funktioniert

Überprüfen Sie Ihren Webhook‑Flow
Klare nächste Schritte für Raw‑Body‑Verifikation, Dedupe‑Keys und race‑sichere Verarbeitung.

Ein Idempotency‑Key ist ein „mach das einmal“-Label für ein Webhook‑Ereignis. Kommt dasselbe Ereignis erneut an, schauen Sie den Key nach und geben dasselbe Ergebnis zurück, anstatt die Geschäftslogik ein zweites Mal auszuführen.

Der Key muss zwischen Retries stabil sein. Gibt der Provider eine event_id oder message_id, verwenden Sie diese. Wenn nicht, bauen Sie einen Key aus Feldern, die sich zwischen Zustellungen nicht ändern, z. B. einem Hash aus Provider‑Name + Event‑Typ + Resource‑ID + Provider‑Timestamp. Nutzen Sie nicht Ihre Empfangszeit oder zufällige UUIDs — dann stimmen Duplikate nie überein.

Der Scope ist ebenfalls wichtig. Wenn Sie mehrere Kunden bedienen, nehmen Sie die Tenant‑ID in den gespeicherten Key auf, damit ein Kunde nicht versehentlich einen anderen blockiert.

Ein einfaches Modell ist, pro Idempotency‑Key eine Zeile zu speichern mit Status und (optional) einem kompakten Ergebnis:

  • in‑progress (angenommen, Arbeit noch nicht abgeschlossen)
  • processed (abgeschlossen, Duplikate können sofort Erfolg zurückgeben)
  • failed (mit Fehler beendet, ggf. Retry‑Policy)

Bewahren Sie Keys so lange auf, wie das Risiko es verlangt. Bewegt sich Geld, behalten Sie sie länger (Tage oder Wochen). Ist der Impact niedrig, reicht kürzere Aufbewahrung.

Eine praktische Absicherung: erzwingen Sie Eindeutigkeit auf Datenbankebene. Ein Unique‑Constraint macht nebenläufige Zugriffe zu „first writer wins“, selbst wenn zwei Kopien gleichzeitig eintreffen.

Idempotente Speicherung: das einfachste verlässliche Muster

Wenn Sie Dedupe wollen, die bei Retries, Timeouts und parallelen Requests hält, speichern Sie Idempotenz in der Datenbank. Memory‑Caches laufen aus. In‑Process‑Locks brechen beim Skalieren. Ein DB‑Unique‑Constraint ist langweilig, schnell und schwer zu umgehen.

Wählen Sie einen stabilen Idempotency‑Key (oft die Event‑ID des Providers oder ein Hash aus Tenant + Event‑ID). Erstellen Sie z. B. eine Tabelle webhook_receipts mit einem UNIQUE‑Constraint auf diesem Key.

Zuerst einfügen, dann verarbeiten

Der sicherste Ablauf ist, eine Receipt zu schreiben, bevor Sie echte Arbeit tun. Zwei Anfragen können nicht beide „gewinnen“. Ein Insert gelingt, das andere schlägt fehl, und das Duplikat wird zur No‑Op.

Ein verlässliches Muster:

  • Signatur und Zeitstempel validieren, dann den Idempotency‑Key berechnen.
  • Versuchen, eine Receipt‑Zeile mit Status received einzufügen.
  • Schlägt das Insert wegen des Unique‑Constraints fehl, behandeln Sie es als Duplikat und geben ein sicheres 2xx zurück.
  • Gelingt das Insert, führen Sie die Geschäftslogik aus und aktualisieren die Receipt zu processed (oder failed).

Auf Duplikate mit 2xx zu antworten klingt seltsam, ist aber meist korrekt: Der Sender fragt „Haben Sie es bekommen?" und die Antwort ist ja. Neuverarbeitung ist der riskante Teil.

Speichern Sie eine minimale Receipt

Halten Sie die Receipt klein, aber nützlich: idempotency_key, tenant_id, event_type, received_at, processed_at, status und ggf. ein kurzes result‑Feld wie „created invoice 123“. Das ergibt auch eine Audit‑Spur, wenn Sie erklären müssen, warum etwas passiert ist.

Schritt‑für‑Schritt: Einen sicheren Webhook‑Handler bauen

Zuverlässigkeit und Replay‑Schutz sind die gleiche Aufgabe: Ein Ereignis einmalig akzeptieren, selbst wenn es mehrfach zugestellt wird.

Ein Request‑Flow, der bei Retries standhält

Halten Sie den Hot‑Path kurz und teilen Sie ihn in Stufen auf:

  1. Verifizieren, bevor Sie JSON parsen. Lesen Sie den rohen Request‑Body, prüfen Sie die Signatur und das Zeitfenster. Bei Fehlschlag 4xx zurückgeben.
  2. Schema parsen und validieren. JSON decodieren und erforderliche Felder prüfen (Event‑ID, Typ, Tenant/Account).
  3. Idempotency‑Key berechnen. Bevorzugen Sie die Event‑ID des Providers.
  4. Den Key mit einem atomaren Write speichern. Existiert er bereits, 2xx zurückgeben. Ist er neu, erst nach erfolgreichem Write fortfahren.
  5. Geschäftsarbeit ausgelagert ausführen. Enqueuen Sie einen Job mit der Payload (oder einer Referenz). Dedupe am Webhook‑Entrypoint, nicht im Worker.

Nachdem Sie 2xx zurückgegeben haben, können Sie langsamere Aktionen sicher ausführen, wie Payment‑APIs aufrufen, E‑Mails senden oder Datenbanken updaten.

Für Troubleshooting hängen Sie Korrelationselemente an Logs: Request‑ID, Event‑ID (Idempotency‑Key), Tenant‑ID, Event‑Typ und die Entscheidung (akzeptiert vs. Duplikat). So können Sie bei einer Support‑Anfrage eine doppelte Abbuchung schnell über die Retries zurückverfolgen.

Ordering, Concurrency und Multi‑Tenant‑Edge‑Cases

Edge‑Cases und Race‑Conditions auditieren
Wir prüfen Multi‑Tenant‑Keys, Ordering‑Probleme und Concurrency‑Bugs, die zu Chaos führen.

Webhooks sind keine Queue. Sie können Event B vor Event A erhalten oder dasselbe Event zweimal gleichzeitig. Wenn Ihr Code saubere Reihenfolge annimmt, werden Sie früher oder später ältere Zustände überschreiben oder Seiteneffekte doppelt ausführen.

Out‑of‑order Lieferung: akzeptieren Sie sie

Gestalten Sie Handler so, dass sie sicher sind, wenn Events spät ankommen. Bei Update‑Events wenden Sie Änderungen nur an, wenn sie neuer sind als das, was Sie gespeichert haben. „Neuer“ kann eine Versionsnummer, Sequenz oder ein vom Sender geliefertes updated_at‑Feld sein. Haben Sie keines davon, führen Sie pro Objekt einen „last processed“‑Marker und behandeln ältere Updates als No‑Ops.

Behandeln Sie Creates nicht als Sonderfall. Verarbeiten Sie ein „Update“ vor einem „Create“, sollte Ihr Handler upserten und spätere veraltete Creates ignorieren.

Concurrency: dasselbe Event kann zweimal gleichzeitig eintreffen

Dedupe muss race‑sicher sein. Zwei Requests können die Frage „Habe ich das schon gesehen?“ beide passieren, bevor einer den Status schreibt.

Der Unique‑Constraint in der Datenbank ist die sauberste Lösung. Inserten Sie zuerst den Dedupe‑Eintrag, führen Sie dann die Arbeit aus und markieren Sie ihn als erledigt. Ist die Arbeit lang, speichern Sie einen Status (received, processing, succeeded, failed) und retryen nur sicher, wenn ein vorheriger Versuch eindeutig fehlgeschlagen oder abgelaufen ist.

Multi‑Tenant‑Keys: Cross‑Customer‑Kollisionen vermeiden

Wenn Sie mehrere Tenants bedienen, nehmen Sie die Tenant‑ID in Ihren Dedupe‑Key auf. Sonst könnten zwei Kunden dieselbe event_id teilen und sich gegenseitig blockieren.

Ein praktisches Key‑Format ist tenant_id + provider + event_id (oder tenant_id + provider + object_id + version).

Teilfehler sind ebenfalls wichtig. Chargen Sie eine Karte und stürzen danach ab, bevor Sie den Erfolg markieren? Bei einem Retry können Sie erneut belasten, sofern Sie nicht aufgezeichnet haben, was bereits geschehen ist.

Häufige Fehler, die doppelte Verarbeitung verursachen

Die meisten Probleme sind vorhersehbar, nicht zufällig.

Signaturen zu spät verifizieren ist klassisch. Wenn Sie bereits in die DB geschrieben, E‑Mails gesendet oder ein Charge ausgeführt haben und erst danach die Signatur prüfen, kann eine gefälschte oder replayed Anfrage Schaden anrichten. Validierung muss vor Seiteneffekten stehen.

Ein weiterer häufiger Fehler ist, den Request‑Body falsch zu lesen. Manche Frameworks parsen JSON und serialisieren es neu (Whitespace, Feldreihenfolge oder Encoding ändern sich). Wird die Signatur über die rohen Bytes berechnet, schlägt die Verifikation fehl, wenn Sie gegen ein verändertes Body prüfen. Akzeptieren Sie fehlende Signaturen nicht „vorübergehend“, nur um das System weiterlaufen zu lassen — das macht Signaturprüfungen zur Show.

Weitere typische Muster:

  • Dedupe nur auf Basis von Zeitstempeln. Zwei echte Events können denselben Zeitstempel haben, und ein Angreifer kann einen kopieren.
  • Auf Duplikate mit 500 zu antworten. Der Sender sieht einen Fehler und retryt aggressiver, was einen Retry‑Sturm auslöst.
  • „Bereits verarbeitet“ als Ausnahme behandeln, statt als normalen Ausgang.
  • Secrets loggen oder in Client‑Code einbetten.

Wenn Sie dieselbe Event‑ID zweimal sehen, antworten Sie mit 2xx und tun nichts weiter. Das stoppt Retries in der Regel am zuverlässigsten.

Ein einfaches Praxisbeispiel: doppelte Abbuchungen verhindern

Replay‑Angriffe schnell blocken
Wir härten Signaturprüfungen und Zeitfenster, damit Replays sicher abgewiesen werden.

Ein häufiger Supportalbtraum: ein Kunde wird doppelt belastet. Ihr Payment‑Provider sendet ein payment_succeeded‑Webhook, Ihr Server erstellt eine Bestellung, und dann trifft ein Retry oder Replay erneut ein. Läuft Ihr Handler zweimal durch, haben Sie ein echtes Problem.

Replay‑Schutz hilft in Schichten: Signaturprüfung stellt sicher, dass nur Ihr Provider gültige Events senden kann. Ein Zeitfenster begrenzt, wie lange eine abgefangene Anfrage nützlich bleibt. Legitime Retries bleiben normal — und genau da hilft Dedupe per Idempotency‑Key am meisten.

Ein sauberes Muster:

  • Die Event‑ID des Providers extrahieren (oder aus stabilen Feldern bilden).
  • Als Idempotency‑Key verwenden, z. B. provider:event_id:account_id.
  • Den Key mit Unique‑Constraint in Storage einfügen.
  • Gelingt das Insert, die Bestellung verarbeiten.
  • Existiert der Key bereits, 200 zurückgeben und nichts tun.

Was der Kunde sieht: eine Abbuchung, ein Beleg und ein konsistenter Bestellstatus, auch wenn der Provider fünfmal retryt.

Checkliste und nächste Schritte

Wenn Sie Replay‑Schutz für Webhooks in Produktion brauchen, konzentrieren Sie sich auf ein paar unverhandelbare Punkte:

  • Signatur vor jeglicher Geschäftslogik prüfen (und bevor Sie untrusted Felder loggen).
  • Requests mit Zeitstempeln außerhalb Ihres Fensters ablehnen und Serverzeiten synchron halten.
  • Deduplizieren mit einem eindeutigen Idempotency‑Key, atomar gespeichert.
  • Für Duplikate konsistente 2xx zurückgeben, damit der Sender aufhört zu retryen.
  • Sicher loggen: keine Secrets, dafür Korrelationselemente (Event‑ID, Request‑ID, Tenant‑ID) zum Nachverfolgen.

Ein einfacher Test, der die meisten Fehler aufdeckt: Senden Sie dasselbe Webhook‑Payload fünfmal hintereinander und dann nochmal nach Ablauf Ihres Zeitfensters. Sie sollten eine einzige Geschäftsaktion sehen, mehrere schnelle „bereits verarbeitet“ Antworten und eine saubere Ablehnung, wenn das Event zu alt ist.

Wenn Sie einen AI‑generierten Webhook‑Handler geerbt haben, der bei Retries doppelt verarbeitet, sind es oft nur wenige Fixes: Raw‑Body Signaturprüfung, ein Zeitfenster und datenbankgestützte Idempotenz. Wenn Sie eine zweite Meinung wollen, kann FixMyMess (fixmymess.ai) ein kostenloses Code‑Audit durchführen, um zu zeigen, wo Verifikation, Security‑Härtung und Dedupe vor dem Rollout scheitern.

Häufige Fragen

Why am I receiving the same webhook multiple times?

Die meisten Webhook‑Provider garantieren nur mindestens einmal Zustellung. Wenn Ihr Endpoint time‑outet, 5xx zurückgibt oder die Antwort verloren geht, wiederholt der Provider dasselbe Ereignis. Diese Retries sind normal — Ihr Handler sollte Wiederholungen sicher ignorieren.

What’s the difference between webhook duplicates and replay attacks?

Ein Duplicate ist meist eine legitime Wiederholung desselben realen Ereignisses (Timeouts, Fehler oder verlorene Antworten). Ein Replay ist, wenn eine alte, zuvor gültige Anfrage später erneut gesendet wird, um denselben Effekt zu erzielen. Akzeptieren Sie legitime Retries sicher, aber lehnen Sie veraltete Replays durch Frischeprüfung und Dedupe per stabilem Event‑Key ab.

If I verify the signature, do I still need idempotency?

Eine Signatur beweist, dass die Nutzlast unverändert ist und dass der Sender das gemeinsame Secret kennt, wodurch die meisten gefälschten Requests geblockt werden. Sie verhindert jedoch nicht, dass dasselbe gültige Ereignis mehrfach zugestellt wird — Retries tragen weiterhin korrekte Signaturen. Signaturprüfung ist nötig, aber Dedupe verhindert doppelte Verarbeitung.

How do I validate webhook signatures correctly without false failures?

Validieren Sie gegen die rohen Request‑Body‑Bytes, so wie sie empfangen wurden, berechnen Sie den erwarteten HMAC (oder den provider‑spezifischen Algorithmus) und vergleichen Sie in konstanter Zeit. Wenn Sie gegen ein geparstes oder neu serialisiertes JSON prüfen, brechen kleine Formatänderungen die Verifikation und verleiten Teams dazu, ungültige Signaturen „temporär zu akzeptieren“ — das ist gefährlich.

What timestamp window should I use to block replays?

Als Standard ist ein kleines Skew‑Fenster sinnvoll, etwa ~5 Minuten — das reicht für normale Netzverzögerungen und Queueing, lässt aber alte Anfragen schnell verfallen. Der Zeitstempel muss Teil der signierten Daten sein; sonst kann ein Angreifer ihn ändern. Halten Sie Serverzeiten synchronisiert, denn Zeitdrift ist ein häufiger Grund, gute Events abzulehnen.

What should I use as an idempotency key for webhook dedupe?

Verwenden Sie am besten die event_id oder message_id des Providers, weil sie bei Retries gleich bleibt. Wenn nicht vorhanden, bilden Sie einen Key aus stabilen Feldern wie Provider‑Name, Event‑Typ, Resource‑ID, Tenant‑ID und Provider‑Timestamp (z. B. als Hash). Nutzen Sie nicht Ihre eigene Empfangszeit oder eine zufällige UUID — dann stimmen Duplikate nie überein.

Why is database-backed dedupe better than using a cache or in-memory lock?

Ein Datenbank‑Insert mit Unique‑Constraint ist die zuverlässigste Methode, dedupe race‑safe über mehrere Server zu machen. Das typische Muster: „Receipt zuerst einfügen, dann verarbeiten“ — nur ein Request gewinnt, die anderen werden No‑Ops. In‑Memory‑Locks und Caches versagen bei Skalierung oder Neustarts eher.

Should I return 200 or an error when I detect a duplicate webhook?

Bei Duplikaten reagieren Sie konsistent mit einem 2xx, sobald Sie bestätigt haben, dass das Event bereits verarbeitet wurde, damit der Provider aufhört zu retryen. Für ungültige Signaturen oder Zeitstempel außerhalb des Fensters geben Sie 4xx zurück und führen keine Arbeit aus. Die Kernidee: keine Seiteneffekte, solange die Anfrage nicht authentisch und neu ist.

How do I handle out-of-order webhooks and concurrent deliveries?

Gehen Sie davon aus, dass Events aus der Reihenfolge kommen können, und gestalten Sie Handler so, dass sie damit sicher umgehen. Wenden Sie Updates nur an, wenn sie neuer sind als der aktuell gespeicherte Zustand (Provider‑Version, Sequenz oder updated_at), und verwenden Sie Upserts, damit ein „Update vor Create“ nicht bricht. Machen Sie Deduping race‑safe mit einem unique Idempotency‑Key.

How do I stop webhook retries from causing double charges or duplicate invoices?

Doppelte Abbuchungen entstehen oft, weil kein Idempotenz‑Guard am Einstiegspunkt sitzt oder weil nach dem Charging ein Crash eintritt, bevor der Erfolg aufgezeichnet wurde. Prüfen Sie Ihre Logs auf wiederholte Provider‑Event‑IDs und stellen Sie sicher, dass Sie eine Idempotency‑Receipt vor Seiteneffekten einfügen. Wenn Ihr Handler von AI generiert wurde, kann FixMyMess eine kostenlose Code‑Analyse durchführen und typische Fixes (Raw‑Body‑Signaturprüfung, Zeitfenster, DB‑Idempotenz) anwenden.