Quand un webhook n'arrive jamais

Procédez dans l'ordre : le journal de livraison, le nom de l'événement, le pare-feu, la signature. L'onglet Deliveries indique si Didit l'a envoyé, ce qui divise immédiatement le problème en deux.

Short answer

Commencez par l'onglet Deliveries de la destination. Si Didit n'a jamais tenté la livraison, c'est un problème d'abonnement ou de destination. S'il a tenté et échoué, le code de réponse vous indique lequel : 404 signifie que votre route n'était pas joignable à cette URL, une incohérence de signature signifie que vous avez haché les mauvais octets.

#Étape 1 : Didit a-t-il essayé de l'envoyer ?

Ouvrez la destination dans API & Webhooks et regardez l'onglet Deliveries. Chaque tentative est consignée individuellement, avec la réponse.

La page des webhooks dans la console Didit affichant le statut de livraison par destination
  1. Last sent indique si Didit a essayé, tout court.
  2. View stats affiche les tentatives et les échecs pour cette destination.
  3. Une livraison de test sépare votre endpoint de l'événement lui-même.
  4. Une destination qui continue d'échouer peut être désactivée pendant que vous la corrigez.
Tout ce qu'il faut pour distinguer un événement manquant d'un endpoint en échec se trouve sur cette page.

Cette seule vérification divise le problème en deux :

  • Aucune tentative consignée → l'événement n'a jamais été généré pour cette destination. Passez à l'étape 2.
  • Tentative consignée, échouée → Didit l'a envoyé et votre côté l'a rejeté ou ne l'a pas reçu. Passez à l'étape 3.
  • Tentative consignée, 2xx → il a été livré avec succès. Le problème est dans votre gestionnaire, pas dans la livraison.

#Étape 2 : aucune tentative n'a été consignée

Par ordre de probabilité :

  1. L'événement n'est pas souscrit. Il n'y a pas de caractère générique : chaque famille d'événements doit être listée explicitement. Et un nom qui n'existe pas (session.status.updated, kyc.completed) ne reçoit silencieusement rien. Vérifiez dans la liste des événements.
  2. Mauvaise application. Les destinations appartiennent à une application. Si vos sessions s'exécutent sous une application différente de la destination, aucun événement ne l'atteindra jamais. C'est la cause la plus fréquente quand tout semble correctement configuré.
  3. Rien n'a réellement changé. Les webhooks se déclenchent sur un changement. Une session qui n'a pas bougé, ou un re-criblage de monitoring AML qui n'a rien trouvé au-dessus du seuil, ne produit correctement aucun événement.
  4. Le statut que vous attendez ne s'est pas encore produit. Une session en cours n'est pas terminée. Voir quand une session ne se termine jamais.

#Étape 3 : la livraison a été tentée et a échoué

Un 404 signifie que la requête a atteint quelque chose qui n'avait pas votre route. Vérifiez :

  • Le chemin exact, y compris une barre oblique finale. Un framework qui redirige /hook vers /hook/ peut transformer un endpoint fonctionnel en 404 ou en corps perdu.
  • Si l'URL est publique. Un hôte local ou de staging qui n'est pas joignable depuis internet échoue de cette façon.
  • Si un proxy, un répartiteur de charge, ou un routeur basé sur le chemin en amont de votre application envoie ce chemin ailleurs.

Un 5xx signifie que votre gestionnaire a levé une exception. Consignez le corps brut avant de l'analyser pour voir ce qu'il a réellement reçu.

Un timeout signifie que vous n'avez pas répondu assez vite. Renvoyez d'abord un 2xx, traitez ensuite.

Rien du tout / connexion refusée signifie que votre périphérie l'a bloqué. Didit livre depuis l'IP statique 18.203.201.92 avec un user agent DiditWebhook/2.0. Si vous êtes derrière Cloudflare ou un WAF avec une posture de refus par défaut, autorisez cette IP pour le nom d'hôte destinataire.

#Le classique : la livraison automatique renvoie 404 mais Resend fonctionne

Celui-ci revient assez souvent pour mériter un nom. La livraison automatisée échoue avec un 404, puis cliquer sur Resend sur le même événement réussit.

Cette combinaison signifie que la charge utile et votre endpoint fonctionnent tous les deux correctement, donc la différence est une question de timing ou de chemin, pas de contenu. Vérifiez :

  • Un déploiement ou un redémarrage au moment de la livraison initiale. Resend réussit plus tard parce que l'application est de nouveau active.
  • Un démarrage à froid qui a dépassé le délai de votre plateforme, courant sur du serverless avec une première invocation lente.
  • Un routage basé sur le chemin qui a changé entre les deux tentatives, ou une règle qui ne correspond qu'à certaines requêtes.
  • Une limitation de débit ou une protection anti-bot en périphérie qui a laissé passer le renvoi manuel parce qu'il est arrivé seul plutôt qu'en rafale.

L'onglet Deliveries contient les deux tentatives avec leurs horodatages : comparez-les à vos propres journaux de déploiement et d'erreur pour cette minute.

#Échec de la vérification de signature

Presque toujours l'une de ces trois choses :

  1. Vous avez haché du JSON re-sérialisé. Hachez avec HMAC le corps de requête brut exactement tel qu'il a été reçu. Analyser puis re-sérialiser change les espaces et l'ordre des clés, et la signature ne correspondra pas. La plupart des frameworks nécessitent une configuration explicite pour vous donner le corps brut.
  2. Mauvais secret. Le secret de signature est par destination, et ce n'est pas votre clé API. Deux destinations ont deux secrets différents.
  3. Mauvaise hypothèse d'encodage. Si vous n'êtes pas sûr que le secret est utilisé comme chaîne littérale ou décodé au préalable, ne devinez pas : suivez la référence de vérification de signature exactement, et consignez le corps brut pendant le débogage pour pouvoir comparer.
Important

Ne "corrigez" jamais une incohérence de signature en sautant la vérification. Un endpoint de webhook non vérifié acceptera une approbation forgée par n'importe qui trouve l'URL, ce qui transforme un raccourci de débogage en une voie de prise de contrôle de compte.

#Deux nouvelles tentatives, ce n'est pas une file d'attente

Sur un 5xx, un 404, un timeout, ou un échec de connexion, Didit réessaie deux fois : environ 1 minute puis 4 minutes plus tard, puis abandonne la livraison. Si votre endpoint était indisponible plus longtemps que ça, ces événements sont perdus pour de bon.

Construisez un chemin de réconciliation : au démarrage, interrogez l'endpoint de décision pour toute session pour laquelle vous n'avez pas de statut final. Traitez les webhooks comme le chemin rapide et l'interrogation périodique comme le filet de sécurité.

#Tester sans exécuter de vérifications

Try Webhook sur la page de destination envoie un événement entièrement formé du type que vous choisissez : approuvé, refusé, en revue, KYB, entité, transaction. Utilisez-le pour prouver que votre endpoint, votre vérification de signature et votre gestionnaire fonctionnent avant qu'une session réelle n'en dépende.

Le sandbox est l'autre moitié de cela : une session sandbox émet de vrais webhooks avec "environment": "sandbox", donc vous pouvez exercer tout le chemin de bout en bout gratuitement. Voir tester en sandbox.