Le webhook Kanal vous notifie en temps réel quand un de vos contacts envoie un message WhatsApp à votre numéro. Idéal pour brancher un bot, alimenter un CRM, ou déclencher des automatisations côté serveur.
Depuis l'interface Kanal, ajoutez l'URL HTTPS publique de votre serveur. Kanal enverra une requête POST à cette URL à chaque message entrant, avec un body JSON décrit ci-dessous.
Chaque webhook envoyé suit la même enveloppe standardisée :
{
"id": "evt_01HRXYZ...",
"type": "message.received",
"api_version": "2026-05-13",
"created_at": "2026-05-13T10:00:00+00:00",
"phone_number_id": 123,
"data": {
"contact": { ... },
"message": { ... }
}
}
Champs racine :
Champ | Description |
|---|---|
| Identifiant unique de l'event. Utilisez-le pour dédupliquer côté serveur. |
| Type d'event. Pour l'instant : |
| Version du contrat webhook. Permet de gérer les évolutions sans casse. |
| Date d'émission de l'event au format ISO 8601. |
| ID du numéro WhatsApp Kanal qui a reçu le message. |
| Objet contenant le contact et le message reçu. |
L'objet data contient toujours deux sous-objets : contact et message.
{
"id": 6789,
"phone_number": "33612345678",
"name": "Jean Dupont",
"country_code": "FR"
}
{
"id": 98765,
"wamid": "wamid.HBgL...",
"type": "text",
"content": "Bonjour, j'ai une question",
"media": null
}
Le champ content contient toujours le texte exploitable du message (corps texte, caption d'un média, label d'un bouton cliqué). Le champ media est rempli uniquement pour les médias. Pour les clics sur bouton et les sélections dans une liste, un objet dédié (button / list_option) fournit en plus l'identifiant technique de l'option choisie.
{
"id": "evt_01HRXYZ...",
"type": "message.received",
"api_version": "2026-05-13",
"created_at": "2026-05-13T10:00:00+00:00",
"phone_number_id": 123,
"data": {
"contact": {
"id": 6789,
"phone_number": "33612345678",
"name": "Jean Dupont",
"country_code": "FR"
},
"message": {
"id": 98765,
"wamid": "wamid.HBgL...",
"type": "text",
"content": "Bonjour, j'ai une question",
"media": null
}
}
}
{
"id": 98766,
"wamid": "wamid.HBgL...",
"type": "image",
"content": "Voici la photo de mon produit",
"media": {
"type": "image",
"url": "https://api.getkanal.com/api/media/messages/98766?signature=...",
"caption": "Voici la photo de mon produit"
}
}
L'URL du champ media.url est un lien signé permanent servi par Kanal : vous pouvez le stocker et re-télécharger le média à tout moment.
{
"id": 98767,
"wamid": "wamid.HBgL...",
"type": "video",
"content": null,
"media": {
"type": "video",
"url": "https://api.getkanal.com/api/media/messages/98767?signature=...",
"caption": null
}
}
{
"id": 98768,
"wamid": "wamid.HBgL...",
"type": "audio",
"content": null,
"media": {
"type": "audio",
"url": "https://api.getkanal.com/api/media/messages/98768?signature=...",
"caption": null
}
}
{
"id": 98770,
"wamid": "wamid.HBgL...",
"type": "button_reply",
"content": "Oui, je confirme",
"media": null,
"button": {
"id": "4233be9add_button_1",
"title": "Oui, je confirme"
}
}
content contient le libellé du bouton cliqué. L'objet button fournit en plus son identifiant technique (button.id) — utile pour router la réponse côté serveur sans dépendre du texte affiché. Ce format couvre aussi bien les boutons d'un message interactif que les boutons de réponse rapide d'un template.
{
"id": 98771,
"wamid": "wamid.HBgL...",
"type": "list_reply",
"content": "Suivi de commande",
"media": null,
"list_option": {
"id": "cd593e96a1_row_2",
"title": "Suivi de commande"
}
}
Même principe : content contient le titre de la ligne choisie, et list_option.id son identifiant technique.
Pour l'instant, le seul event émis est message.received (message entrant d'un contact). Les clics sur les boutons de réponse rapide d'un template arrivent également en message.received avec le type button_reply. D'autres events sont prévus prochainement (statut de livraison, accusé de lecture).
type. Les nouveaux types seront ajoutés sans préavis, mais votre intégration ne sera pas impactée si vous ignorez ceux que vous ne traitez pas.Le champ id (format evt_...) est unique pour chaque event. Stockez-le côté serveur pour ignorer les éventuels doublons en cas de retry.
Le champ wamid (identifiant WhatsApp du message) est également unique et stable — utile si vous voulez croiser plusieurs sources de données.
Le champ api_version indique la version du contrat webhook. La version actuelle est 2026-05-13.
Les ajouts non-cassants (nouveaux champs, nouveaux types d'events) sont déployés sans changer la version.
Une nouvelle version sera publiée uniquement en cas de breaking change, avec une période de transition.
Pour rester compatible, votre intégration doit ignorer les champs qu'elle ne connaît pas.
Répondez 200 OK le plus vite possible (sous 5 secondes). Mettez en file le traitement lourd côté serveur.
Filtrez les events par type pour ne traiter que ce qui vous intéresse.
Stockez l'id de chaque event reçu pour éviter les doublons.
Pour répondre au message reçu, utilisez l'endpoint POST /api/v1/messages/send avec le phone_number du contact.
Pour des raisons de compatibilité avec les anciens clients (notamment les notifications mobiles), les champs title, body et text sont également présents à la racine du payload. Ils contiennent un message générique du type « <nom> vient de vous envoyer un nouveau message ». Ignorez-les pour une intégration moderne — toutes les informations utiles sont dans data.