---
title: "Vue d’ensemble des webhooks"
description: "Comment ThunderPhone transmet les événements en temps réel, comment vérifier les signatures et comment les modèles de livraison hérités et basés sur les endpoints se comparent."
---

ThunderPhone envoie des requêtes HTTP `POST` à votre serveur lorsqu'un événement
se produit pendant un appel : un appel entrant démarre, un appel se termine, une exécution
d'évaluation se termine, une alerte se déclenche, etc. Il existe **deux modèles
de livraison** :

<CardGroup cols={2}>
  <Card title="Points de terminaison webhook (recommandé)" icon="bolt" href="/fr/webhooks/endpoints">
    Plusieurs URL, des secrets par point de terminaison, des filtres d'événements par point de terminaison
    et des tentatives automatiques.
    Gérez-les via `GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints`.
  </Card>
  <Card title="Webhook hérité à URL unique" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    Une URL par organisation. Transmet les événements du cycle de vie des appels, y compris les
    échanges de configuration **bloquants**. Géré via `GET/PUT /v1/webhook`.
  </Card>
</CardGroup>

Tous les types d'événements répertoriés dans le [catalogue des événements](/fr/webhooks/events) sont
transmis via des points de terminaison webhook. Les six événements du cycle de vie des appels
(`telephony.incoming`, `telephony.complete`, `telephony.tool`,
`web.incoming`, `web.complete`, `web.tool`) sont **également** envoyés au
webhook hérité à URL unique. Si vous disposez à la fois d'une URL héritée et d'un point de terminaison correspondant, vous recevez l'événement sur **les deux**
chemins. Le comportement bloquant (l'[échange de configuration
`telephony.incoming` / `web.incoming`](/fr/webhooks/call-incoming) et le
[répartiteur d'outils](/fr/tools/overview) en mode webhook) se trouve
exclusivement sur le chemin hérité ; chaque livraison vers un point de terminaison est une
notification envoyée sans attente de réponse.

## Format de la charge utile

Les livraisons vers les points de terminaison sont un objet JSON avec `data`, `event_id` et
`type` :

```json
{
  "data": {
    "call_id": 987654321,
    "from_number": "+14155550199",
    "to_number": "+15551234567"
  },
  "event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
  "type": "telephony.incoming"
}
```

`event_id` est unique pour chaque événement émis. Il est identique lors des tentatives
**et** pour chaque point de terminaison qui reçoit l'événement : dédupliquez sur cette valeur.

Le webhook hérité à URL unique envoie les mêmes `type` et `data`, mais
**sans** `event_id` :

```json
{
  "type": "telephony.incoming",
  "data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}
```

Sur le réseau, chaque corps est sérialisé de manière canonique : clés triées
par ordre alphabétique, sans espaces, en UTF-8. Les exemples mis en forme dans
cette documentation sont fournis uniquement pour faciliter la lecture.

Consultez le [catalogue des événements](/fr/webhooks/events) pour obtenir la liste complète des types
d'événements et des champs de charge utile.

## Vérification de signature

Chaque requête contient deux signatures, toutes deux HMAC-SHA256 utilisant le
`secret` du point de terminaison comme clé (ou le `secret` webhook au niveau de votre organisation pour les
livraisons héritées) :

- `X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>` signe l’
  horodatage, la méthode, le chemin et la requête, ainsi que le corps brut. Vérifiez
  celle-ci et rejetez les requêtes dont `t` diffère de plus de **5 minutes** de
  votre horloge afin qu’une requête interceptée ne puisse pas être rejouée ultérieurement. Les tentatives sont
  signées à nouveau lors de leur envoi.
- `X-ThunderPhone-Signature` signe uniquement le corps brut. Elle est toujours envoyée,
  sans modification, afin que les vérificateurs existants continuent de fonctionner.

### Étapes

1. Lisez l’en-tête, la méthode, le chemin et la requête bruts, ainsi que le
   corps brut **avant** toute analyse.
2. Calculez le HMAC-SHA256 hexadécimal de
   `<t>\n<METHOD>\n<path and query>\n<body>` avec votre secret.
3. Rejetez la requête si `t` diffère de plus de 300 secondes, ou si le
   résultat ne correspond pas à `v1` lors d’une comparaison en temps constant.

Les corps utilisent la sérialisation JSON canonique (clés triées, séparateurs
compacts), et nous signons exactement les octets que nous transmettons. Le
[guide de vérification](/fr/guides/verify-webhook-signatures) contient la chaîne
signée exacte, un exemple détaillé, du code sans le SDK et l’en-tête
historique.

<CodeGroup>
```python Python (Flask)
from flask import Flask, abort, request
from thunderphone import verify_signature

app = Flask(__name__)

@app.post("/thunderphone-webhook")
def handle():
    query = request.query_string.decode()
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=WEBHOOK_SECRET,
        method=request.method,
        path=request.path + (f"?{query}" if query else ""),
        body=request.get_data(),  # raw bytes
    ):
        abort(401)
    event = request.get_json()
    # dispatch on event["type"] …
    return "", 204
```

```javascript Node.js (Express)
import express from "express";
import { verifySignature } from "@thunderphone/sdk";

const app = express();
app.post(
  "/thunderphone-webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ok = verifySignature({
      header: req.header("X-ThunderPhone-Signature-V2"),
      secret: process.env.WEBHOOK_SECRET,
      method: req.method,
      path: req.originalUrl,
      body: req.body,
    });
    if (!ok) return res.sendStatus(401);
    const event = JSON.parse(req.body.toString("utf8"));
    // dispatch on event.type …
    res.sendStatus(204);
  },
);
```
</CodeGroup>

## Sémantique de livraison

Ces sémantiques s’appliquent aux livraisons de **points de terminaison**. Le
webhook hérité à URL unique effectue une seule tentative synchrone sans nouvelle tentative, à l’exception de l’échange de configuration d’appel téléphonique
[`telephony.incoming`](/fr/webhooks/call-incoming),
qui fait l’objet d’une nouvelle tentative.

<AccordionGroup>
  <Accordion title="Nouvelles tentatives">
    Chaque événement fait immédiatement l’objet d’une tentative. Toute réponse `2xx`
    confirme la livraison. Pour tout autre résultat (non-2xx,
    erreur de connexion, délai d’expiration), nous effectuons une nouvelle tentative **1 min, 5 min, 30 min, 2 h, 6 h,
    12 h et 24 h après la première tentative** — soit 8 tentatives sur
    24 heures. Si toutes les tentatives échouent, la livraison s’arrête et le point de terminaison
    est marqué `status="failing"` dans les
    [points de terminaison de webhook](/fr/webhooks/endpoints) ; nous envoyons un e-mail aux
    propriétaires et administrateurs de votre organisation et l’affichons dans le tableau de bord. Renvoyez `2xx` dès que
    la charge utile est acceptée de manière durable ; traitez-la de manière asynchrone.
    Les envois de test depuis l’API de test du point de terminaison bénéficient d’une nouvelle tentative environ une minute après
    la première tentative et ne modifient jamais l’état du point de terminaison.
  </Accordion>

  <Accordion title="Ordre">
    L’ordre de livraison est fourni au mieux. En pratique, nous livrons les événements dans
    l’ordre de leur émission, mais les nouvelles tentatives peuvent les réordonner en cas d’échec.
    Dédupliquez et rapprochez toujours par `call_id` / ID d’objet.
  </Accordion>

  <Accordion title="Doublons">
    La livraison est **au moins une fois** : une nouvelle tentative après une réponse que nous n’avons jamais
    reçue peut dupliquer un événement. Chaque nouvelle tentative contient le même
    `event_id` ; stockez donc les ID traités et ignorez les répétitions. `event_id` est
    également partagé entre les points de terminaison — deux points de terminaison abonnés au
    même événement reçoivent le même `event_id`.
  </Accordion>

  <Accordion title="Délais d’expiration">
    Les livraisons de points de terminaison ont un délai d’expiration de **30 s** par tentative. Sur le
    chemin hérité, les requêtes bloquantes qui pilotent le comportement des appels en direct — l’échange de
    configuration [`telephony.incoming` / `web.incoming`](/fr/webhooks/call-incoming)
    — sont limitées à **10 s** pour la première tentative d’un appel téléphonique
    et à **13 s** pour l’ensemble de l’échange, y compris son unique
    nouvelle tentative, et à **10 s** pour une session de widget. Une réponse lente retarde
    la prise d’appel ; visez donc une réponse en quelques secondes. La [répartition des outils](/fr/tools/overview) en mode webhook autorise 20 s
    par défaut, et les déclarations d’outils peuvent définir un `timeout` de niveau supérieur.
  </Accordion>

  <Accordion title="IP source">
    Les webhooks sortants proviennent de la plage d’IP cloud de ThunderPhone.
    Si votre pare-feu exige une liste d’autorisation, contactez le support et nous
    vous communiquerons les plages actuelles.
  </Accordion>
</AccordionGroup>

## Choisir entre les webhooks historiques et ceux basés sur des points de terminaison

| Fonctionnalité | Hérité (`/v1/webhook`) | Points de terminaison (`/v1/developer/webhook-endpoints`) |
|---------|------------------------|----------------------------------------------|
| Nombre d’URL | 1 par organisation | Plusieurs par organisation |
| Couverture des événements | `telephony.*` / `web.*` uniquement | Les 10 types d’événements |
| Filtre d’événements | — | Par point de terminaison |
| Nouvelles tentatives | Aucune, sauf une pour l’échange de configuration d’appel téléphonique | 8 tentatives sur 24 h |
| Enveloppe | `type` + `data` | `type` + `data` + `event_id` |
| Rotation du secret | Remplace le secret unique | Secret par point de terminaison |
| Désactiver sans supprimer | `PUT /v1/webhook` avec `{"url": ""}` | `status=disabled` |
| Visibilité du statut | — | `active` / `disabled` / `failing` |
| Échange de configuration bloquant | Oui ([`telephony.incoming` / `web.incoming`](/fr/webhooks/call-incoming)) | Jamais — notifications uniquement |
| Idéal pour | Configuration dynamique des appels | Consommation d’événements en production |

Les nouvelles intégrations doivent consommer les événements via des
webhooks basés sur des points de terminaison. Conservez (ou ajoutez) une URL historique uniquement si vous configurez les appels
dynamiquement au moment de la prise d’appel ou utilisez la répartition d’outils en mode webhook — ces
échanges requête/réponse ne fonctionnent que sur le chemin historique.

---

## Associé

<CardGroup cols={2}>
  <Card title="Catalogue des événements" icon="list" href="/fr/webhooks/events">
    Tous les types d’événements et leurs payloads.
  </Card>
  <Card title="Points de terminaison des webhooks" icon="bolt" href="/fr/webhooks/endpoints">
    Gérez plusieurs points de terminaison, filtres d’événements et secrets.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/fr/webhooks/call-incoming">
    La requête bloquante à laquelle votre serveur doit répondre pour configurer les appels.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/fr/webhooks/call-complete">
    Payload post-appel avec transcription, enregistrement et métriques.
  </Card>
</CardGroup>
