Les webhooks bien faits : livraison, relances et signature
Bonnes pratiques webhook pour les intégrations SaaS B2B. Livraison au moins une fois, relances avec backoff, idempotence, charges signées et protection contre le rejeu qui tiennent en production.
Un webhook est une promesse. Le partenaire promet de prévenir votre système dès qu'un changement survient, et votre système promet de recevoir ce message, de prouver qu'il est authentique, et d'agir dessus exactement une fois. La plupart des intégrations webhook tiennent la première moitié de cette promesse dès le premier jour et brisent discrètement la seconde dès que quelque chose tourne mal. L'endpoint était en cours de déploiement, la charge était falsifiée, le même événement est arrivé deux fois, l'écriture en base a expiré. Aucun de ces cas n'est rare. C'est le climat normal dans lequel tourne un récepteur webhook, et la différence entre une intégration webhook qui fonctionne et une qui perd des données tient à ceci : avez-vous conçu pour ce climat ou espéré qu'il resterait au beau fixe.
Ce guide porte sur la partie que les équipes sautent. Mettre en place un endpoint qui renvoie 200 prend un après-midi. Construire un récepteur qui survit à la livraison au moins une fois, vérifie chaque charge, traite chaque événement exactement une fois, relance les bonnes erreurs et ne perd jamais un message en silence, voilà le vrai travail. Nous allons parcourir les garanties de livraison, les relances et le backoff, l'idempotence, la signature et la protection contre le rejeu, dans l'ordre où vous devez les raisonner, et terminer par les erreurs qui reviennent dans presque tous les post-mortems de webhook.
Si vous hésitez encore à utiliser les webhooks, commencez par notre guide webhooks ou polling, qui couvre le compromis et le modèle hybride sur lequel atterrissent la plupart des intégrations en production. Cet article suppose que vous avez décidé de consommer des webhooks et que vous voulez le faire bien.
L'essentiel en 60 secondes
Si vous ne lisez qu'une seule section, lisez celle-ci :
- Considérez la livraison comme au moins une fois, jamais exactement une fois. Le même événement arrivera plus d'une fois, et certains événements arriveront dans le désordre. Concevez pour les deux dès le départ.
- Accusez réception vite, traitez ensuite. Vérifiez, stockez l'événement brut de façon durable, renvoyez 200 en quelques millisecondes, et faites le vrai travail depuis une file. Un traitement lent dans la requête ressemble à un échec de livraison et déclenche des relances.
- Soyez idempotent par identifiant d'événement. Enregistrez les identifiants d'événement déjà traités et faites du retraitement une opération sans effet. C'est la seule propriété qui rend les relances et les doublons sûrs.
- Vérifiez la signature avant de faire confiance à un seul octet. Votre endpoint est public. Vérifiez la signature HMAC sur le corps brut, rejetez les échecs, et utilisez une comparaison à temps constant.
- Protégez-vous contre le rejeu. Une requête valide capturée peut être renvoyée. Liez un horodatage à la signature, rejetez les requêtes périmées, et rejetez les identifiants déjà vus.
- Relancez avec backoff, puis mettez en lettre morte. Relancez les erreurs transitoires sur une cadence croissante, plafonnez les tentatives, et garez le reste là où vous pouvez le rejouer. Alertez quand la file de lettres mortes se remplit.
- Réconciliez derrière le webhook. Un polling périodique qui rattrape tout ce que le push a laissé tomber transforme une perte permanente silencieuse en un retard temporaire et auto-correcteur.
Garanties de livraison : ce que « au moins une fois » signifie vraiment
Avant d'écrire une ligne de code récepteur, soyez au clair sur ce que promet l'émetteur, car presque tous les systèmes de webhook en production promettent une livraison au moins une fois, et presque aucun ne promet exactement une fois. La distinction décide de toute votre architecture.
Au moins une fois signifie que l'émetteur continuera d'essayer jusqu'à recevoir une réponse de succès, donc un événement donné peut être livré plus d'une fois. Si votre endpoint renvoie 200 mais que le réseau perd la réponse sur le chemin du retour, l'émetteur ne voit jamais le succès et réessaie. Vous avez traité l'événement ; l'émetteur ne le sait pas ; vous recevez un doublon. Ce n'est pas un bug de l'émetteur. C'est la seule garantie honnête qu'un système distribué peut offrir sur un réseau peu fiable.
Exactement une fois est ce que tout le monde veut et ce qu'aucun émetteur ne peut vraiment offrir de bout en bout. Le plus proche que vous obteniez est la livraison au moins une fois plus un traitement idempotent de votre côté, ce qui produit des effets exactement une fois. Voilà la vraie cible : vous ne pouvez pas empêcher les doublons d'arriver, mais vous pouvez faire en sorte qu'un doublon ne change rien.
L'ordre n'est pas garanti non plus. Les webhooks sont des requêtes HTTP indépendantes. Sous relances surtout, un événement « subscription.updated » peut atterrir avant l'événement « subscription.created » dont il dépend. Si votre logique suppose que l'ordre d'arrivée égale l'ordre des événements, elle corrompra l'état dès qu'une relance rebattra les cartes.
Les conséquences pratiques découlent directement de ces trois faits :
| La garantie que vous obtenez réellement | La conception qu'elle impose |
|---|---|
| La livraison est au moins une fois | Traiter de façon idempotente ; les doublons doivent être sûrs |
| Les effets doivent être exactement une fois | Dédoublonner par identifiant d'événement avant d'agir |
| L'ordre n'est pas garanti | Se baser sur les identifiants et horodatages, pas l'ordre d'arrivée |
| Certains événements n'arrivent jamais du tout | Réconcilier avec un polling périodique |
Lisez ce tableau comme un contrat. Tout récepteur webhook fiable est une implémentation de ces quatre lignes, et le reste de ce guide explique comment construire chacune.
Accusez réception vite, traitez ensuite
L'erreur architecturale la plus courante est de faire le vrai travail à l'intérieur de la requête. Le récepteur naïf accepte le POST, le vérifie, écrit dans trois tables, appelle un service en aval, puis renvoie 200. Ça marche en démo. En production, ça échoue de deux manières.
D'abord, les émetteurs imposent un délai d'expiration, généralement de quelques secondes. Si votre traitement dépasse cette fenêtre, même occasionnellement sous charge, l'émetteur cesse d'attendre, considère la livraison comme échouée, et relance. Vous traitez alors le même événement une deuxième fois tout en paraissant peu fiable au partenaire, qui voit une expiration dans son journal de livraison.
Ensuite, toute défaillance en plein traitement, un 500 en aval, un délai d'attente de verrou, jette un événement que vous avez déjà accepté, à moins que vous ne l'ayez stocké d'abord.
La solution est une séparation nette entre réception et traitement :
- Vérifiez la signature sur le corps brut de la requête.
- Persistez l'événement brut de façon durable, idéalement sur une file, indexé par l'identifiant d'événement.
- Renvoyez 200 immédiatement, avant toute logique métier.
- Traitez depuis la file, de façon asynchrone, avec ses propres relances.
On appelle parfois cela le modèle accepter-puis-traiter ou « store-and-forward », et il change entièrement le modèle de défaillance. Une fois l'événement brut stocké durablement, une défaillance de traitement est récupérable : vous relancez depuis la copie stockée au lieu de demander au partenaire de relivrer. La requête HTTP devient un accusé de réception fin et rapide dont le seul rôle est de vérifier et de capturer durablement. La référence de la méthode HTTP POST sur MDN est un rappel utile de la sémantique que votre endpoint implémente ici, car un récepteur webhook est fondamentalement un gestionnaire de POST avec des exigences strictes de latence et de confiance.
Une bonne cible est de renvoyer 200 en quelques dizaines de millisecondes. Si votre chemin d'accusé de réception touche à plus que la vérification de signature et une écriture durable, c'est qu'il en fait trop.
Idempotence : la propriété qui rend les relances sûres
Parce que la livraison est au moins une fois, votre récepteur traitera le même événement logique plus d'une fois. L'idempotence est la garantie que le faire ne change rien la deuxième fois. Sans elle, chaque doublon est une occasion de facturer deux fois, de provisionner deux fois, ou de notifier deux fois, et les doublons ne sont pas des cas limites ici. Ils sont la routine.
Le mécanisme est simple. Tout webhook bien construit porte un identifiant d'événement unique. Avant d'appliquer un événement, vérifiez si vous avez déjà enregistré cet identifiant :
- Tenez une table des événements traités indexée par identifiant d'événement, avec une contrainte d'unicité.
- À chaque événement, tentez d'insérer l'identifiant d'abord. Si l'insertion réussit, c'est la première fois ; traitez-le. Si elle viole la contrainte d'unicité, vous avez déjà vu cet événement ; renvoyez un succès et ne faites rien.
- Rendez l'insertion et le traitement atomiques là où ça compte, pour ne jamais marquer un identifiant comme traité alors que le travail derrière a échoué, ni l'inverse. Une seule transaction qui marque l'identifiant et applique le changement est la version la plus propre.
Le modèle mental à intérioriser est le modèle formel : une opération idempotente produit le même résultat qu'elle soit appliquée une fois ou plusieurs. La définition de l'idempotence sur MDN est une référence concise, et c'est exactement la propriété que vous concevez dans votre couche de traitement.
Quelques notes pratiques :
- Utilisez l'identifiant d'événement du partenaire, pas votre propre identifiant de requête. Une relance du même événement réutilise le même identifiant d'événement, ce qui est précisément ce qui vous permet de l'attraper. Un identifiant par requête changerait à chaque relance et anéantirait le dédoublonnage.
- Conservez les identifiants traités assez longtemps pour dépasser la fenêtre de relance de l'émetteur. Si le partenaire relance pendant 24 heures, une table de dédoublonnage qui oublie les identifiants au bout d'une heure laissera passer une relance tardive comme un événement neuf.
- L'idempotence couvre aussi l'ordre, en partie. Si vous basez les changements d'état sur les identifiants et horodatages plutôt que sur l'ordre d'arrivée, un doublon dans le désordre est plus facile à gérer correctement.
| Sans idempotence | Avec idempotence par identifiant d'événement |
|---|---|
| Une relance réapplique l'événement | Une relance est détectée et ignorée |
| Un doublon facture ou provisionne deux fois | Un doublon est une opération sans effet qui renvoie 200 |
| Des relances dans le désordre corrompent l'état | Les identifiants et horodatages décident, pas l'ordre d'arrivée |
| Vous craignez les relances et les désactivez | Les relances sont sûres, donc vous pouvez être agressif dessus |
Relances et backoff : quelles erreurs relancer, et comment
Les relances sont à la fois le travail de l'émetteur et le vôtre. Le partenaire relance les livraisons échouées vers votre endpoint ; votre couche de traitement relance le travail échoué depuis la file. Les deux ont besoin d'une cadence de backoff, et les deux doivent savoir quelles erreurs valent la peine d'être relancées.
Relancez les erreurs transitoires. Ne relancez pas les permanentes. Un 503 d'un service en aval, un délai d'attente de verrou, un bref incident réseau : relancez-les, car la prochaine tentative peut réussir. Une charge malformée, une erreur de validation, un 4xx qui dit que l'entrée est mauvaise : ne les relancez pas, car la prochaine tentative échouera à l'identique. Relancer une erreur permanente ne fait que brûler des tentatives et retarder le moment où vous remarquez le vrai problème.
Espacez sur une cadence croissante. Les relances immédiates martèlent un service déjà en difficulté. Une cadence typique allonge l'écart à chaque fois : quelques secondes, puis des dizaines de secondes, puis des minutes, puis des heures. Le backoff exponentiel avec un plafond est la forme standard.
Ajoutez de la gigue. Si un service en aval a un incident et que mille événements en file relancent tous sur la même cadence fixe, ils relancent au pas et le martèlent par vagues synchronisées. Randomiser chaque délai d'une petite fraction étale la charge et fait la différence entre une reprise et une panne auto-infligée.
Plafonnez les tentatives, puis mettez en lettre morte. Relancer indéfiniment n'est qu'une façon lente de cacher un problème. Après un nombre fixé de tentatives, déplacez l'événement vers une file de lettres mortes plutôt que de le perdre ou de boucler sans fin. Un événement garé que vous pouvez inspecter et rejouer est récupérable. Un événement perdu est un ticket de support que vous n'avez pas encore reçu.
Respectez 429 et Retry-After. Si vous relancez en rappelant l'API du partenaire dans le cadre du traitement, et qu'ils renvoient 429 Too Many Requests, espacez d'au moins l'intervalle que spécifie leur en-tête Retry-After. Le statut 429 et ses compagnons sont définis dans la RFC 6585, et un client bien élevé les traite comme des instructions, pas des suggestions.
| Type d'erreur | Exemple | Relancer ? |
|---|---|---|
| Infrastructure transitoire | 503, délai de verrou, incident réseau | Oui, avec backoff et gigue |
| Limité en débit | 429 avec Retry-After | Oui, après l'intervalle indiqué |
| Erreur client permanente | Charge malformée, échec de validation | Non, envoyer en lettre morte pour inspection |
| Tentatives épuisées | Toujours en échec après le plafond | Arrêter, mettre en lettre morte, alerter |
Signature et vérification : prouver que la charge est réelle
Votre endpoint webhook est une URL publique. Quiconque l'apprend peut y faire un POST, ce qui signifie que quiconque peut tenter d'alimenter votre système avec de faux événements : un faux « paiement réussi », un « compte mis à niveau » usurpé. La vérification de signature est la ligne entre un webhook et une porte ouverte, et elle est non négociable pour tout endpoint qui déclenche un travail conséquent.
Le mécanisme standard est une signature HMAC. Le partenaire partage un secret avec vous hors bande. Pour chaque livraison, il calcule un hash à clé du corps brut de la requête en utilisant ce secret et l'envoie dans un en-tête. Vous recalculez le même hash de votre côté et comparez. S'ils correspondent, la charge vient de quelqu'un qui détient le secret et n'a pas été altérée en transit. HMAC est spécifié dans la RFC 2104, et comprendre la construction aide à éviter les pièges d'implémentation.
Trois choses doivent être justes ou la vérification n'est que du théâtre :
- Hachez les octets bruts, avant tout parsing. Signez et vérifiez exactement le corps que le partenaire a envoyé. Si vous parsez le JSON et le re-sérialisez, des changements d'ordre des clés ou d'espaces feront échouer une signature valide. Capturez le corps brut dans votre framework avant que tout middleware ne le touche, et hachez cela.
- Utilisez une comparaison à temps constant. Comparer les deux signatures avec une égalité de chaîne ordinaire fuit une information temporelle qu'un attaquant peut utiliser pour forger une signature octet par octet. Utilisez la comparaison à temps constant que fournit votre bibliothèque cryptographique, pas
==. - Rejetez en cas d'échec avec un statut clair. Une signature non concordante doit renvoyer 401 et ne jamais atteindre votre couche de traitement. Journalisez-la, car un pic de non-concordances est soit une mauvaise configuration soit une attaque, et les deux valent la peine d'être connues.
L'antisèche de sécurité REST de l'OWASP est une référence indépendante solide pour les préoccupations de validation d'entrée et d'authentification qui entourent un endpoint public comme celui-ci, et elle vaut la peine d'être lue en parallèle de ce que documente le partenaire spécifique.
Protection contre le rejeu : une signature valide ne suffit pas
Voici l'attaque subtile qu'une signature seule n'arrête pas. Supposons que quelqu'un capture une requête webhook authentique, correctement signée, peut-être depuis des journaux, un proxy, ou un intermédiaire compromis. Il ne peut pas l'altérer sans briser la signature, mais il peut la renvoyer telle quelle, autant de fois qu'il le souhaite. Chaque copie se vérifie parfaitement, parce que chaque copie est une vraie requête signée. C'est une attaque par rejeu, et contre un endpoint qui provisionne des accès ou déplace de l'argent, rejouer un seul événement valide « mise à niveau accordée » de façon répétée est un vrai problème.
Deux défenses, utilisées ensemble, la referment :
- Liez un horodatage à la signature et rejetez les requêtes périmées. Les bons schémas de signature de webhook signent l'horodatage avec le corps, et envoient l'horodatage dans le même en-tête. Vous vérifiez la signature, puis contrôlez que l'horodatage est récent, dans une tolérance de quelques minutes qui tient compte du décalage d'horloge. Une requête capturée rejouée une heure plus tard échoue au contrôle de fraîcheur même si sa signature est valide. La tolérance doit être assez serrée pour compter et assez large pour survivre à la dérive d'horloge normale.
- Dédoublonnez par identifiant d'événement, ce que vous faites déjà. Votre couche d'idempotence est aussi une protection contre le rejeu. Un événement rejoué porte le même identifiant d'événement que vous avez déjà enregistré, donc même un rejeu à l'intérieur de la fenêtre d'horodatage est attrapé et ignoré. C'est une raison de plus pour laquelle la table des événements traités gagne son entretien.
La protection contre le rejeu est une catégorie d'attaque que la communauté de sécurité au sens large documente bien ; le projet OWASP API Security catalogue les risques au niveau API qui méritent qu'on conçoive contre eux, le rejeu parmi eux. Le modèle à retenir est que l'authenticité et la fraîcheur sont des propriétés différentes : la signature prouve l'authenticité, l'horodatage et la table de dédoublonnage prouvent la fraîcheur. Vous avez besoin des deux.
| Défense | Arrête |
|---|---|
| Signature HMAC sur le corps brut | Charges falsifiées ou altérées |
| Comparaison à temps constant | Attaques temporelles contre la vérification de signature |
| Horodatage dans la signature + fenêtre de fraîcheur | Rejeu d'une ancienne requête capturée |
| Dédoublonnage par identifiant d'événement | Rejeu dans la fenêtre, et doublons ordinaires |
La file de lettres mortes et le filet de réconciliation
Même avec vérification, idempotence et relances, certains événements ne passeront pas. Un bug dans votre code de traitement, une panne en aval plus longue que votre fenêtre de relance, une charge malformée que vous ne pouvez pas gérer : ceux-là finissent dans la file de lettres mortes, et c'est le système qui fonctionne comme prévu. La file de lettres mortes est l'endroit où vous mettez les événements que vous n'avez pas pu traiter, pour qu'ils soient récupérables plutôt que perdus.
Deux pratiques la rendent précieuse plutôt que décorative :
- Alertez quand des événements y atterrissent. Une file de lettres mortes que personne ne surveille n'est qu'une façon plus lente de perdre des données. Quand elle dépasse un seuil, prévenez quelqu'un. La première personne à remarquer une intégration cassée devrait être vous, pas le client dont les données se sont périmées.
- Construisez un chemin de rejeu. Vous devriez pouvoir retraiter un événement garé, ou un lot d'entre eux, une fois la cause corrigée. Le rejeu passe par le même traitement idempotent que les événements en direct, donc le retraitement est sûr même si une partie du lot a déjà réussi.
Derrière tout cela se trouve le filet de sécurité final : la réconciliation. Supposez, malgré tout, que certains événements ne soient jamais arrivés du tout, perdus pendant un déploiement, perdus quand les relances se sont épuisées. Un polling périodique qui compare votre copie des données avec la source de vérité du partenaire et rattrape les écarts transforme une perte permanente silencieuse en un retard temporaire et auto-correcteur. Nous couvrons le modèle hybride complet, webhooks pour la vitesse plus un polling de réconciliation pour l'exhaustivité, dans webhooks ou polling, et c'est l'ajout à plus haute valeur pour toute intégration webhook.
Les bonnes pratiques webhook à l'échelle d'un portefeuille de partenaires
Rien de tout cela n'est exotique. C'est l'outillage standard pour consommer des webhooks, et plus vous gérez de connecteurs, plus il est rentable de le standardiser une fois plutôt que de le réinventer par partenaire. Une équipe qui construit trois intégrations et écrit trois vérifications de signature différentes, trois schémas de dédoublonnage différents, et trois politiques de relance différentes a triplé à la fois le travail et la surface de bugs. Une équipe qui construit un modèle de récepteur durci et l'applique partout a une convention que le support peut raisonner et que les nouveaux ingénieurs peuvent apprendre une fois.
Cela fait partie du fait de traiter vos intégrations comme un portefeuille avec des conventions partagées plutôt que comme un tas de cas particuliers. La même discipline s'applique dans l'autre sens. Si vous êtes le partenaire qui produit des webhooks pour que d'autres les consomment, la qualité de votre signature, de votre politique de relance et de vos garanties de livraison détermine directement la difficulté à construire sur vous. Une API qui pousse des événements signés, relancés, bien documentés, avec des identifiants stables, est un plaisir à intégrer ; une qui force chaque consommateur à deviner la sémantique de livraison est une taxe sur tous ceux qui se connectent. L'ensemble des décisions qui rendent votre API facile à construire dessus est dans notre guide API partner-ready, et documenter précisément le comportement de votre webhook est un chapitre de ce travail.
Erreurs fréquentes, et comment les corriger
Traiter les webhooks comme du « envoyer et oublier ». La correction : construisez le récepteur complet. Vérifiez les signatures, accusez réception vite, dédoublonnez par identifiant d'événement, relancez avec backoff, mettez en lettre morte, et réconciliez. Un webhook sans cela n'est pas une synchro fiable, c'est l'espoir que rien n'échoue jamais.
Faire le vrai travail à l'intérieur de la requête. La correction : vérifiez, stockez l'événement brut durablement, renvoyez 200, et traitez depuis une file. Un traitement lent dans la requête déclenche l'expiration de l'émetteur et provoque des livraisons en double tout en paraissant peu fiable.
Sauter l'idempotence. La correction : dédoublonnez sur l'identifiant d'événement du partenaire avec une contrainte d'unicité, et faites du retraitement une opération sans effet. Les doublons et les relances sont la norme, et une intégration qui applique deux fois un événement corrompt les données dès sa première semaine en ligne.
Vérifier un corps parsé au lieu des octets bruts. La correction : capturez et hachez exactement le corps que le partenaire a envoyé, avant tout parsing ou re-sérialisation, et comparez à temps constant. Un JSON re-sérialisé brise les signatures valides et une comparaison non à temps constant fuit le secret.
Signer sans protection contre le rejeu. La correction : liez un horodatage à la signature, rejetez les requêtes périmées, et appuyez-vous sur votre dédoublonnage par identifiant d'événement. Une signature valide ne prouve que l'authenticité, pas la fraîcheur, donc une requête capturée peut être rejouée sans elle.
Relancer indéfiniment, ou pas du tout. La correction : relancez les erreurs transitoires avec un backoff exponentiel plafonné et de la gigue, puis mettez le reste en lettre morte et alertez. Les relances infinies cachent les problèmes ; zéro relance perd des événements récupérables au premier incident.
FAQ
Que signifie la livraison au moins une fois pour les webhooks ? Cela signifie que l'émetteur continue de relancer jusqu'à recevoir une réponse de succès, donc le même événement peut être livré plus d'une fois. Vous ne pouvez pas empêcher les doublons ; vous les gérez en traitant de façon idempotente, ce qui produit des effets exactement une fois même si la livraison est au moins une fois.
Comment arrêter de traiter deux fois le même webhook ? Dédoublonnez sur l'identifiant d'événement que le partenaire envoie. Tenez une table des événements traités avec une contrainte d'unicité, tentez d'enregistrer l'identifiant avant d'agir, et s'il est déjà présent, renvoyez 200 et ne faites rien. Utilisez l'identifiant d'événement stable du partenaire, pas un identifiant par requête, pour que les relances réutilisent le même identifiant.
Comment vérifier une signature de webhook ? Hachez le corps brut de la requête, exactement tel qu'envoyé, avec le secret partagé en utilisant l'algorithme HMAC spécifié par le partenaire, puis comparez votre signature calculée à celle de l'en-tête avec une comparaison à temps constant. Rejetez les non-concordances avec 401 avant tout traitement. Ne hachez jamais un corps parsé puis re-sérialisé.
Qu'est-ce qu'une attaque par rejeu de webhook et comment l'empêcher ? C'est le renvoi d'une requête capturée et validement signée pour déclencher le même effet de façon répétée. Empêchez-la en liant un horodatage à la signature et en rejetant les requêtes hors d'une courte fenêtre de fraîcheur, et en dédoublonnant par identifiant d'événement pour qu'un événement rejoué soit reconnu et ignoré.
Combien de fois relancer un webhook échoué, et sur quelle cadence ? Relancez les erreurs transitoires seulement, sur un backoff exponentiel avec gigue, plafonné à un nombre fixe de tentatives, souvent entre cinq et une douzaine sur une fenêtre de plusieurs heures. Après le plafond, déplacez l'événement vers une file de lettres mortes et alertez. Ne relancez pas les erreurs permanentes comme les charges malformées.
Que met-on dans une file de lettres mortes ? Les événements que vous n'avez pas pu traiter après épuisement des relances, plus les événements en échec permanent, comme ceux avec des charges illisibles. Garez-les là où vous pouvez les inspecter et les rejouer, alertez quand la file se remplit, et retraitez par le même chemin idempotent une fois la cause corrigée.
Les webhooks garantissent-ils l'ordre ? Non. Ils arrivent comme des requêtes HTTP indépendantes et peuvent atterrir dans le désordre, surtout sous relances. Basez vos changements d'état sur les identifiants d'événement et les horodatages plutôt que sur l'ordre d'arrivée, et utilisez un polling de réconciliation pour converger vers la vérité du partenaire quel que soit l'ordre d'arrivée des événements.
Pour aller plus loin
- RFC 2104, HMAC : authentification de message par hachage à clé pour la construction derrière la vérification de signature de webhook.
- Antisèche de sécurité REST de l'OWASP pour les préoccupations de validation d'entrée et d'authentification autour d'un endpoint public.
- MDN sur l'idempotence pour la propriété formelle que votre couche de traitement doit implémenter.
- RFC 6585, codes de statut HTTP additionnels qui définit 429 Too Many Requests, la réponse que vos relances doivent respecter.
En bref
Une intégration webhook fiable est un récepteur construit pour les modes de défaillance qui surviendront à coup sûr. La livraison est au moins une fois, donc les doublons et les événements dans le désordre sont la routine, pas des cas limites. Accusez réception vite en vérifiant et en stockant durablement l'événement brut, puis traitez depuis une file. Rendez le traitement idempotent en dédoublonnant sur l'identifiant d'événement du partenaire, pour que les relances et les doublons ne changent rien. Vérifiez la signature HMAC sur le corps brut avec une comparaison à temps constant, et ajoutez une protection contre le rejeu avec un horodatage signé et une fenêtre de fraîcheur. Relancez les erreurs transitoires avec un backoff plafonné et de la gigue, mettez le reste en lettre morte, alertez, et réconciliez avec un polling périodique pour que rien ne reste perdu.
Faites ce travail et les webhooks livrent la vitesse que les clients ressentent sans la perte de données silencieuse que les ingénieurs redoutent. Sautez-le et l'intégration est rapide jusqu'à la première défaillance, et là elle est pire que le polling qu'elle remplaçait.
Si vous voulez de l'aide pour concevoir la pile webhook fiable d'une intégration précise, ou pour rendre votre propre API facile à construire dessus pour les partenaires, c'est exactement à cela que sert un Partner Audit. Nous examinons votre produit, votre API et votre potentiel partenaire, puis définissons quoi construire, qui approcher et comment livrer.