GH GambleHub

Webhooks et idempotence des événements

TL; DR

Un bon webhook est signé (HMAC/mTLS), un événement résumé et idempotent livré sur le modèle at-least-once avec un backoff exponentiel et une déduplication chez le destinataire. Négociez une enveloppe ('event _ id', 'type', 'ts', 'version', 'attempt', 'signature'), une fenêtre temporelle (≤5 min), des codes de réponse, des rétroactions, DLQ et un statut d'endpoint.


1) Rôles et modèle de livraison

Expéditeur (vous/fournisseur) : génère un événement, signe, essaie de livrer jusqu'à 2xx, rétrograde à 3xx/4xx/5xx (à l'exception des « n'acceptez pas » explicites), conduit DLQ, donne une API de replay.
Destinataire (partenaire/votre service) : vérifie la signature/fenêtre temporelle, fait le dedup et le traitement idempotent, répond avec le code correct, fournit/status et/ack replay par 'event _ id'.

Garanties : at-least-once. Le destinataire doit être capable de traiter les doublons et les changements d'ordre.


2) Enveloppe de l'événement (envelope)

json
{
"event_id": "01HF7H9J9Q3E7DYT5Y6K3ZFD6M",
"type": "payout.processed",
"version": "2025-01-01",
"ts": "2025-11-03T12:34:56.789Z",
"attempt": 1,
"producer": "payments",
"tenant": "acme",
"data": {
"payout_id": "p_123",
"status": "processed",
"amount_minor": 10000,
"currency": "EUR"
}
}

Champs obligatoires : 'event _ id', 'type', 'version', 't',' attempt '.
Règles d'évolution : nous ajoutons des champs ; suppression/changement de type - uniquement avec la nouvelle version.


3) Sécurité : Signatures et ancrage

3. 1 signature HMAC (recommandée par défaut)

Titres :

X-Signature: v1=base64(hmac_sha256(<secret>, <canonical>))
X-Timestamp: 2025-11-03T12:34:56Z
X-Event-Id: 01HF7...
Chaîne canonique :

<timestamp>\n<method>\n<path>\n<sha256(body)>
Vérification auprès du destinataire :
  • abs(now − `X-Timestamp`) ≤ 300s
  • 'X-Event-Id'n'a pas été traité précédemment (dedup)
  • 'X-Signature 'correspond à une comparaison temporelle sécurisée

3. 2 Dop. mesures prises

mTLS pour les webhooks très sensibles.
IP/ASN allow-list.
DPoP (facultatif) pour sender-constrained si le webhook déclenche des callbacks.


4) Idempotence et déduplication

4. 1 Idempotence de l'événement

L'événement avec le même 'event _ id' ne doit pas changer à nouveau d'état. Destinataire :
  • Stocke 'event _ id' dans un kesh idempotent (KV/Redis/OBD) sur TTL ≥ 24-72 h ;
  • conserve le résultat du traitement (succès/erreur, artefacts) pour le retour répété.

4. 2 Idempotence des commandes (appels en arrière)

Si le webhook force le client à renverser l'API (par exemple, « confirmer payout »), utilisez 'Idempotency-Key' sur le volume REST, stockez le résultat sur le côté du service (exactly-once outcome).

Modèle KV (minimum) :

key: idempotency:event:01HF7...
val: { status: "ok", processed_at: "...", handler_version: "..." }
TTL: 3d

5) Retrai et backoff

Graphique recommandé (exponentiel avec gitter) :
  • « 5s, 15s, 30s, 1m, 2m, 5m, 10m, 30m, 1h, 3h, 6h, 12h, 24h » (plus loin que les jours N)
Solutions par code :
  • 2xx - succès, arrêter les retraits.
4xx:
  • « 400/ 401/403/404/422 » n'est pas rétroactif si la signature/le format ok (erreur client).
  • '429' est une Retry-After ou backoff.
  • 5xx/réseau - rétroactif.

Titres de l'expéditeur : 'User-Agent', 'X-Webhook-Producer', 'X-Attempt'.


6) Traitement côté destinataire

Pseudo-ligne :
pseudo verify_signature()
if abs(now - X-Timestamp) > 300s: return 401

if seen(event_id):
return 200 // идемпотентный ответ

begin transaction if seen(event_id): commit; return 200 handle(data)       // доменная логика mark_seen(event_id)    // запись в KV/DB commit return 200

Transactionnalité : l'étiquette « seen » doit être placée atomiquement avec l'effet de l'opération (ou après fixation du résultat) pour éviter un double traitement en cas d'échec.


7) Garanties d'ordre et de snapshots

L'ordre n'est pas garanti. Utilisez 't'et les domaines' seq '/' version 'dans' data 'pour vérifier la pertinence.
Pour les longues tranches/pertes - ajoutez/replay à l'expéditeur et/resync au destinataire (obtenez le snapshot et le delta par la fenêtre temporelle/ID).


8) Statut, replay et DLQ

8. 1 Endpoints de l'expéditeur

'POST/webhooks/replay '- par la liste' event _ id 'ou par la fenêtre temporelle.
'GET/webhooks/events/: id '- afficher le paquet source et l'historique des tentatives.
DLQ : Événements « morts » (limite des retraits épuisée) → stockage séparé, alertes.

8. 2 Endpoints du destinataire

`GET /webhooks/status/:event_id` — `seen=true/false`, `processed_at`, `handler_version`.
'POST/webhooks/ack '- (en option) confirmation du traitement manuel à partir du DLQ.


9) Contrats d'erreur (réponse du destinataire)

http
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
Retry-After: 120
X-Trace-Id: 4e3f...

{
"error": "invalid_state",
"error_description": "payout not found",
"trace_id": "4e3f..."
}

Recommandations : retournez toujours un code clair et, si possible, « Retry-After ». Ne retournez pas les détails de sécurité.


10) Surveillance et SLO

Métriques (expéditeur) :
  • livraison p50/p95, taux de réussite, retrai/événement, drop-rate DLQ, share 2xx/4xx/5xx, fenêtre de retard jusqu'à 2xx.
Métriques (destinataire) :
  • verify fail rate (signature/heure), dup-rate, latency handler p95, 5xx.
SLO repères :
  • Livraison : ≥ 99. 9 % des événements reçoivent 2xx <3 c p95 (après la première tentative réussie).
  • Cryptoprotection : validation de la signature ≤ 2-5 ms p95.
  • Dedup : 0 effets répétés (exactly-once outcome au niveau du domaine).

11) Sécurité des données et vie privée

Ne pas transmettre le PAN/PII dans le corps du webhook ; utilisez les identifiants et les pulls suivants pour les détails de l'API autorisée.
Masquer les champs sensibles dans les logs ; ne stocker les corps d'événements qu'au minimum, avec TTL.
Crypter le stockage DLQ et le relais.


12) Versioning et compatibilité

Version dans 'version' (enveloppe) et en transit : '/webhooks/v1/payments '.
Nouveaux champs - optionnels ; suppression - seulement après la période 'Sunset'.
Documentez les modifications apportées à la machine-readable changelog (pour les rampes automatiques).


13) Cas de test (chèque UAT)

  • Refaire le même 'event _ id' → un effet et '200' en double.
  • Signature : clé correcte, clé incorrecte, ancienne clé (rotation), 'X-Timestamp' à l'extérieur de la fenêtre.
  • Backoff : le destinataire donne '429' avec 'Retry-After' → une pause correcte.
  • Ordre : les événements '... processed' arrivent avant '... created' → traitement/attente correct.
  • L'OBD du destinataire a échoué entre l'effet et 'mark _ seen' → l'atomicité/répétition.
  • DLQ et replay manuel → une livraison réussie.
  • La « tempête » massive (fournisseur de shlets de paquet) → sans perte, les limites n'étouffent pas critique.

14) Mini-extraits

Signature de l'expéditeur (pseudo) :
pseudo body = json(event)
canonical = ts + "\n" + "POST" + "\n" + path + "\n" + sha256(body)
sig = base64(hmac_sha256(secret, canonical))
headers = {"X-Timestamp": ts, "X-Event-Id": event.event_id, "X-Signature": "v1="+sig}
POST(url, body, headers)
Vérification et déduplication du destinataire (pseudo) :
pseudo assert abs(now - X-Timestamp) <= 300 assert timingSafeEqual(hmac(secret, canonical), sig)

if kv.exists("idemp:"+event_id): return 200

begin tx if kv.exists("idemp:"+event_id): commit; return 200 handle(event.data)        // доменная логика kv.set("idemp:"+event_id, "ok", ttl=259200)
commit return 200

15) Erreurs fréquentes

Pas de dédupit → effets répétés (double refand/peyout).
Signature sans horloge/fenêtre → vulnérabilité à replay.
Gardez un secret HMAC pour tous les partenaires.
Les réponses '200' avant la fixation du résultat → la perte d'événements au crash.
« Laver » les détails de sécurité dans les réponses/logs.
Absence de DLQ/replay - Les incidents ne sont pas résolus.


16) La barre de mise en œuvre

La sécurité : HMAC v1 + ' X-Timestamp ' + ' X-Event-Id ', la fenêtre ≤ 5 mines; mTLS/IP allow-list par extension.
Конверт: `event_id`, `type`, `version`, `ts`, `attempt`, `data`.
Livraison : at-least-once, backoff avec gitter, 'Retry-After', API de replay DLQ +.
Idempotence : KV-cache 24-72 h, fixation atomique de l'effet + « mark _ seen ».
Observabilité : métriques de livraison, signatures, doublons ; trace 'trace _ id'.
Documentation : version, codes de réponse, exemples, chèque UAT.


Résumé

Les webhooks résistants sont construits sur trois baleines : une enveloppe signée, une livraison at-least-once et un traitement idempotent. Formalisez le contrat, activez le HMAC/mTLS et la fenêtre temporelle, implémentez les retraits + DLQ et la réplique, stockez les étiquettes idempotentes et enregistrez les effets atomiquement. Les événements restent alors fiables même en cas de défaillance du réseau, de pics de charge et de rares « doublons du destin ».

Contact

Prendre contact

Contactez-nous pour toute question ou demande d’assistance.Nous sommes toujours prêts à vous aider !

Commencer l’intégration

L’Email est obligatoire. Telegram ou WhatsApp — optionnels.

Votre nom optionnel
Email optionnel
Objet optionnel
Message optionnel
Telegram optionnel
@
Si vous indiquez Telegram — nous vous répondrons aussi là-bas.
WhatsApp optionnel
Format : +code pays et numéro (ex. +33XXXXXXXXX).

En cliquant sur ce bouton, vous acceptez le traitement de vos données.