OdyOdy Aide

Recevoir des webhooks et vérifier les signatures

Mis à jour le Sun Aug 30 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

Ody envoie les événements de l'espace de travail — nouveaux messages, résultats d'appels, changements de contact — vers les points de terminaison HTTPS que vous enregistrez via l'API, chaque livraison étant signée selon la spécification Standard Webhooks afin que vous puissiez prouver qu'elle provient d'Ody.

Avant de commencer

  • Vous avez besoin d'une clé API avec la portée webhooks:manage — voir Obtenir votre clé API Ody.
  • Votre point de terminaison doit être une URL HTTPS qui répond rapidement avec un statut 2xx (les livraisons expirent après 10 secondes).
  • Chaque espace de travail peut enregistrer jusqu'à 50 points de terminaison.

Étape par étape

  1. Listez les types d'événements auxquels vous pouvez vous abonner :
curl https://api.ody.co/v1/api/webhook-events \
  -H "Authorization: Bearer ody_live_…"

Le catalogue aujourd'hui : message.received, message.delivered, message.failed, call.ringing, call.answered, call.completed, call.forwarded, call.missed, call.recording.completed, call.summary.completed, call.transcript.completed, call.voicemail.completed, call.flow.started, call.flow.completed, call.flow.aborted, contact.updated, contact.deleted. S'abonner à "*" couvre tous les types d'événements actuels et futurs.

Les événements call.flow.* se déclenchent lorsqu'un appel est répondu par un flux d'appels : started lorsque l'appelant entre dans le flux, completed lorsqu'il atteint une destination (avec le type de destination — sonnerie, assistant IA, messagerie vocale, transfert ou raccrochage), et aborted si le flux n'a pas pu se terminer.

  1. Enregistrez votre point de terminaison :
curl https://api.ody.co/v1/api/webhooks \
  -H "Authorization: Bearer ody_live_…" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/ody-webhook","events":["message.received"],"label":"prod"}'
  1. Stockez immédiatement le secret de la réponse. Le secret de signature whsec_… n'est renvoyé que lors de la création et de la rotation — il n'est plus jamais affiché.
  2. Envoyez-vous un événement de test signé et confirmez que votre point de terminaison le vérifie et l'accepte :
curl -X POST https://api.ody.co/v1/api/webhooks/WEBHOOK_ID/test \
  -H "Authorization: Bearer ody_live_…"

Le test publie un événement {"type":"ping"} signé exactement comme une livraison réelle.

À quoi ressemble une livraison

Chaque livraison est une requête POST avec un corps JSON et trois en-têtes de signature :

{
  "id": "evt_…",
  "apiVersion": "2026-06-01",
  "createdAt": "2026-08-16T12:00:00.000Z",
  "type": "message.received",
  "data": { "conversationId": "…", "activityId": "…", "numberE164": "+1…" }
}
En-tête Signification
webhook-id L'identifiant de l'événement — dédupliquez-le, car les nouvelles tentatives le réutilisent
webhook-timestamp Secondes Unix au moment de l'envoi
webhook-signature v1,<base64 HMAC-SHA256> sur <id>.<timestamp>.<raw body>

Vérification de la signature

La clé HMAC est la partie décodée en base64 de votre secret après le préfixe whsec_, et le message signé est <webhook-id>.<webhook-timestamp>.<raw body>. Vérifiez toujours par rapport aux octets bruts de la requête — la re-sérialisation du JSON analysé rompt la signature. Rejetez les horodatages de plus de quelques minutes pour bloquer les relectures.

import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
app.post("/ody-webhook", express.raw({ type: "application/json" }), (req, res) => {
  const secret = process.env.ODY_WEBHOOK_SECRET; // whsec_…
  const id = req.headers["webhook-id"];
  const timestamp = req.headers["webhook-timestamp"];
  const signature = req.headers["webhook-signature"];

  // Replay guard: reject deliveries older than 5 minutes.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(401).end();

  const key = Buffer.from(secret.slice("whsec_".length), "base64");
  const expected = "v1," + createHmac("sha256", key)
    .update(`${id}.${timestamp}.${req.body}`)
    .digest("base64");

  const a = Buffer.from(expected);
  const b = Buffer.from(String(signature));
  if (a.length !== b.length || !timingSafeEqual(a, b)) return res.status(401).end();

  const event = JSON.parse(req.body.toString("utf8"));
  console.log("verified event:", event.type);
  res.status(200).end();
});

Les SDKs officiels l'incluent sous forme d'une seule ligne — verifyWebhookSignature (TypeScript) et verify_webhook_signature (Python), tous deux avec une comparaison à temps constant et la protection anti-relecture de 5 minutes intégrée. Voir Démarrage rapide des SDK : TypeScript et Python.

Nouvelles tentatives, historique et gestion

  • Nouvelles tentatives : une livraison échouée (non-2xx, délai d'attente ou erreur de connexion) est réessayée environ 5 secondes puis 30 secondes après la première tentative — trois tentatives au total, avec un délai d'attente de 10 secondes chacune.
  • Historique : GET /v1/api/webhooks/:id/deliveries liste les livraisons récentes, les plus récentes en premier, avec les codes de statut, les erreurs et les durées par tentative — votre premier arrêt lorsque des événements semblent manquants.
  • Gérer les points de terminaison : GET /v1/api/webhooks les liste (jamais le secret), PATCH /v1/api/webhooks/:id met à jour url, events, label ou status (enabled/disabled), et DELETE /v1/api/webhooks/:id en supprime un ainsi que son historique de livraison.
  • Faire pivoter le secret à tout moment avec POST /v1/api/webhooks/:id/rotate — le nouveau whsec_… est renvoyé une seule fois, et les anciennes signatures cessent d'être valides immédiatement.

Dépannage

  • La vérification de la signature échoue toujours — vous vérifiez probablement un corps re-sérialisé. Utilisez les octets bruts de la requête et confirmez que vous avez décodé le secret en base64 après avoir supprimé whsec_.
  • Aucune livraison n'arrive — vérifiez que le status du point de terminaison est enabled, que sa liste events inclut le type que vous attendez (ou "*"), et l'historique des livraisons pour les erreurs par tentative.
  • Événements en double — les nouvelles tentatives réutilisent le même webhook-id. Dédupliquez-les.
  • webhook limit reached — vous avez atteint 50 points de terminaison pour l'espace de travail ; supprimez-en un inutilisé d'abord.

Articles connexes

Questions fréquemment posées

Comment les livraisons de webhook sont-elles signées ?

Selon la spécification Standard Webhooks : un en-tête webhook-signature de la forme v1,<base64 HMAC-SHA256> calculé sur '<webhook-id>.<webhook-timestamp>.<raw body>' avec votre secret whsec_.

Que se passe-t-il si mon point de terminaison est hors service ?

Ody réessaie deux fois — environ 5 secondes puis 30 secondes après le premier échec. Vérifiez GET /v1/api/webhooks/:id/deliveries pour les codes de statut et les erreurs par tentative.

J'ai perdu mon secret de signature — que faire maintenant ?

Faites-le pivoter avec POST /v1/api/webhooks/:id/rotate. Le nouveau secret whsec_ est renvoyé une seule fois ; les anciennes signatures cessent d'être valides immédiatement.

Plus dans API développeur