Votre serveur
Recevoir les événements par webhook
Votre serveur reçoit une requête pour chaque message et chaque Case ouvert ou résolu.
Mis à jour le 28 octobre 2026
Le webhook envoie une requête POST en JSON à votre serveur pour chaque événement de l’App. Par exemple, pour envoyer depuis votre serveur une notification push à un Contact qui a quitté l’app : voir Envoyer des notifications push.
Configurer
- Ouvrez Paramètres de l’App > Développeurs > Webhook.
- Saisissez l’adresse https de votre serveur, puis enregistrez.
- Copiez le secret de signature qui apparaît et gardez-le sur votre serveur.
- Pendant le développement, recevez les événements sur votre ordinateur avec la CLI Zean. Voir Recevoir les webhooks sur votre ordinateur.
Les événements
| Événement | Données | Description |
|---|---|---|
| message.contact | data.message | Le Contact a écrit. |
| message.member | data.message, data.push | Un membre a répondu au Contact. Les notes internes et les réponses automatiques de l’IA n’envoient aucun événement. |
| case.opened | data.caseId | Un Case s’ouvre : au premier message, ou quand la conversation se rouvre. |
| case.resolved | data.caseId | Un Case est résolu, par un membre ou automatiquement. |
La requête
- Méthode
POST, avec l’en-têteContent-Type: application/json. - En-tête
Zean-Event: le type de l’événement. - En-tête
Zean-Signature: la signature, à vérifier avant tout. Voir Vérifier la signature d’un webhook.
Le corps, pour message.contact :
{ "id": "3f1c9a52-6a0e-4c43-9a51-2d1f0e8b7c11", "type": "message.contact", "test": false, "createdAt": 1760515200000, "appId": "…", "data": { "conversationId": "…", "contact": { "id": "…", "externalId": "42", "name": "Awa Diallo", "email": "awa.diallo@example.com" }, "message": { "id": "…", "body": "Bonjour, ma commande est-elle partie ?", "attachments": [ { "name": "recu.jpg", "type": "image/jpeg", "size": 184320 } ], "createdAt": 1760515200000 } }}| Champ | Type | Description |
|---|---|---|
| id | string | L’identifiant de l’événement. Il reste le même d’un essai à l’autre : servez-vous-en pour ignorer un doublon. |
| type | string | Le type, comme dans l’en-tête Zean-Event. |
| test | boolean | true pour un événement de test, envoyé seulement à la CLI Zean, jamais à l’adresse du webhook. false sinon. |
| createdAt | number | Quand l’événement a eu lieu, en millisecondes Unix. |
| appId | string | L’App concernée. |
| data.conversationId | string | La conversation du Contact. |
| data.contact | object | null | id, puis externalId (le sub d’un Contact vérifié), name et email, à null quand ils sont inconnus. null si le Contact n’existe plus. |
| data.message | object | Pour message.contact et message.member : id, body, attachments (le nom, le type et la taille de chaque fichier ; les fichiers restent privés), createdAt, et memberId pour message.member. |
| data.push | object | Pour message.member : la notification push prête à envoyer au Contact. Voir plus bas. |
| data.caseId | string | Pour case.opened et case.resolved, à la place de data.message. |
La réponse d’un membre et sa notification push
Seule la réponse d’un membre envoie message.member. Son corps porte data.push, la notification prête à envoyer à chaque appareil du Contact :
{ "id": "8b2e4f10-3c7d-4a9e-b5f1-6d0a2c9e7b34", "type": "message.member", "test": false, "createdAt": 1760515260000, "appId": "…", "data": { "conversationId": "…", "contact": { "id": "…", "externalId": "42", "name": "Awa Diallo", "email": "awa.diallo@example.com" }, "message": { "id": "…", "body": "Votre commande a quitté l’entrepôt ce matin.", "attachments": [], "memberId": "…", "createdAt": 1760515260000 }, "push": { "title": "Kibo Shop", "body": "Votre commande a quitté l’entrepôt ce matin.", "language": "fr", "tokens": ["ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]"], "data": { "zean": "message", "appId": "…", "conversationId": "…" } } }}| Champ | Type | Description |
|---|---|---|
| push.title | string | Le nom de l’App. |
| push.body | string | La réponse, coupée à 150 caractères avec « … ». Pour des fichiers seuls : « A envoyé une photo », « A envoyé 3 photos », « A envoyé un fichier » ou « A envoyé 3 fichiers » pour un Contact qui parle français, « Sent a photo », « Sent 3 photos », « Sent a file » ou « Sent 3 files » sinon. |
| push.language | string | La langue du Contact, comme fr ou pt-BR. Une langue en fr donne un body en français. |
| push.tokens | string[] | Le jeton push de chaque appareil du Contact qui en a donné un avec setPushToken() : Expo, FCM ou APNs. Vide quand il n’y en a aucun. |
| push.data | object | À joindre à la notification comme données. Le SDK la reconnaît au toucher et ouvre le chat. Voir Envoyer des notifications push. |
Livraison
- L’adresse doit être publique et en https : localhost et les réseaux privés sont refusés. Sur votre ordinateur, utilisez la CLI Zean.
- Chaque événement part vers l’adresse du webhook et vers chaque CLI Zean en cours.
- Répondez par un code 2xx en moins de 10 secondes. Faites les traitements longs après avoir répondu.
- Sinon, l’appel à l’adresse est retenté jusqu’à 5 fois : après 1 minute, 5 minutes, 30 minutes, 2 heures, puis 6 heures.
- Chaque essai porte une signature récente, mais le même
id.
Envois récents
Paramètres de l’App > Développeurs > Webhook > « Envois récents » montre les 50 derniers appels de l’App, événements de test et « Renvoyer » compris. Pour chacun :
- l’événement, et où il est parti : « Adresse du webhook » ou « CLI Zean » ;
- le code de réponse de votre serveur, ou l’erreur : délai dépassé, connexion refusée, adresse introuvable, erreur de certificat, pas de réponse ;
- le début de la réponse de votre serveur, le temps de réponse, l’heure et le numéro de l’essai ;
- le badge « Test » pour un événement de test.
« Renvoyer » envoie de nouveau le même événement, avec le même id et le numéro d’essai suivant. Un renvoi réussi vers l’adresse arrête les nouveaux essais automatiques de cet événement.
Événements de test
Un événement de test part seulement vers les CLI Zean en cours, jamais vers l’adresse du webhook : votre serveur de production ne reçoit jamais de test, et aucun vrai Contact n’est prévenu. Son champ test vaut true.
- Lancez la CLI Zean sur votre ordinateur. Voir Recevoir les webhooks sur votre ordinateur.
- Ouvrez le chat depuis une version de développement de votre app ou de votre site : Expo Go, un build React Native en
__DEV__, ou un site sur localhost. Pendant 24 heures, cet appareil peut devenir « Votre appareil de test ». - Dans Paramètres de l’App > Développeurs > Webhook > « Événements de test », choisissez l’événement, puis « Envoyer un événement de test ». Le bouton marche tant qu’une CLI Zean tourne.
- L’événement porte le Contact de votre appareil de test. Sans appareil de test, un Contact d’exemple, avec
externalIdà"user_123". - Pour
message.member, quand votre appareil de test a déjà écrit, Zean écrit une vraie réponse de test dans sa Conversation : la notification push, le badge et l’ouverture au toucher sont réels. Elle est marquée « Réponse de test » dans la boîte de réception ; aucune IA ne la lit et les statistiques ne la comptent pas. - Le résultat s’affiche dans « Envois récents ». Un événement de test n’est jamais retenté.
Tous les événements sont toujours envoyés : ignorez ceux dont vous n’avez pas besoin. Laissez l’adresse vide pour ne plus rien recevoir à l’adresse.