Skip to main content
Chaque requête que nous envoyons à votre serveur — livraisons de webhooks et invocations de points de terminaison d’outils — contient une signature HMAC-SHA256 dans l’en-tête X-ThunderPhone-Signature. Configurez la vérification correctement une seule fois et réutilisez le même utilitaire dans chaque gestionnaire.

L’algorithme

  1. Lisez le corps de requête brut — les octets exacts que nous vous avons envoyés par POST.
  2. Calculez hmac_sha256(secret, body).hexdigest().
  3. Comparez en temps constant avec X-ThunderPhone-Signature. (Une comparaison naïve de chaînes expose des informations de temporisation.)
Nous signons exactement les octets que nous transmettons. La vérification du corps brut fonctionne donc toujours. Ces octets correspondent également à la sérialisation JSON canonique de la charge utile — clés triées par ordre alphabétique, séparateurs compacts (, et : sans espaces), UTF-8. Cela vous offre une deuxième méthode, entièrement équivalente, lorsque votre framework n’expose que le JSON analysé : resérialisez de manière canonique et calculez le HMAC de ce résultat.
Préférez le corps brut — cela évite une étape et supprime les particularités de conversion aller-retour des nombres JSON dans certains langages.

Quel secret ?

Stockez le secret dans votre gestionnaire de secrets ou une variable d’environnement — ne le validez jamais dans votre dépôt.

Implémentations de référence

Les quatre vérifient le corps de requête brut :

Configuration spécifique au framework

Vérifier les appels d’outils

Lorsque l’agent invoque directement l’un de vos outils de fonction (l’outil possède un endpoint), la requête inclut deux en-têtes ThunderPhone en plus de vos endpoint.headers configurés :
  • X-ThunderPhone-Call-ID — l’identifiant numérique de l’appel en cours.
  • X-ThunderPhone-Signature — HMAC-SHA256, utilisant comme clé votre secret de webhook au niveau de l’organisation, sur les octets exacts du corps de la requête.
Le même assistant verify() fonctionne sans modification, avec deux particularités :
  1. Les outils GET / DELETE n’ont pas de corps. Les arguments sont transmis en tant que paramètres de requête, et la signature est calculée sur la chaîne d’octets vide — donc verify(b"", sig, secret) (Python) ou verify(Buffer.alloc(0), sig, secret) (Node). Ne hachez pas la chaîne de requête.
  2. Les organisations sans webhook hérité configuré n’ont pas de secret d’organisation. Dans ce cas, les appels d’outils incluent uniquement X-ThunderPhone-Call-ID et aucun en-tête de signature. Configurez le webhook hérité (PUT /v1/webhook) pour obtenir un secret de signature, ou authentifiez les appels d’outils avec votre propre en-tête via endpoint.headers.
La distribution des outils en mode webhook (outils sans endpoint, transmis à votre webhook d’organisation sous la forme telephony.tool / web.tool) est un webhook signé classique — la procédure standard ci-dessus s’applique. Consultez Outils de fonction pour les deux formats de requête.

Pièges courants

Analyser le corps puis le réexporter avec les paramètres par défaut de votre bibliothèque JSON (espaces après , / :, clés dans l’ordre d’insertion) produit des octets différents et invalide le HMAC. Vérifiez le corps brut — ou, si vous devez le resérialiser, reproduisez exactement notre forme canonique : clés triées, séparateurs compacts, UTF-8.
Le middleware express.json() d’Express consomme le flux du corps et vous perdez les octets bruts. Utilisez express.raw() spécifiquement sur la route du webhook, ou mettez en mémoire tampon le corps brut dans un pré-middleware. Même principe pour NestJS / Koa — consultez leur documentation sur le « corps brut ».
expected === signature en JS ou expected == signature en Python sont des comparaisons dont la durée varie. Utilisez crypto.timingSafeEqual ou hmac.compare_digest, respectivement. La différence de performances est nulle.
Les appels directs aux points de terminaison d’outils sont signés avec le secret de webhook au niveau de l’organisation (GET /v1/webhook) — et non avec un secret propre à chaque point de terminaison provenant de /v1/developer/webhook-endpoints. Réutilisez la même fonction verify(), mais assurez-vous de lui fournir le secret de l’organisation sur les routes d’outils.
Pour les méthodes d’outils sans corps, la signature couvre la chaîne d’octets vide, ce qui conserve une recette universelle : appliquez le HMAC au corps brut de la requête, quel qu’il soit. Le hachage de l’URL ou de la chaîne de requête ne correspondra jamais.
Renvoyer 200 lorsqu’une vérification échoue fait du gestionnaire une cible de rejeu. Répondez toujours avec un statut autre que 2xx si la vérification échoue.

Étapes suivantes

Vue d’ensemble des webhooks

Sémantique de livraison, tentatives, adresses IP source.

Points de terminaison des webhooks

Gérez plusieurs URL, faites tourner les secrets.

Outils de fonction

Les deux modes d’invocation d’outils et les formats de leurs requêtes.

Intégrations d’outils

Créez une intégration complète basée sur des outils, de bout en bout.