Webhooks et livraison
Après chaque appel, Hanc.AI peut envoyer l'appel — résumé, transcription, champs extraits — à votre propre système : un système de tickets, un CRM, un ERP ou n'importe quel endpoint HTTPS. Cette page décrit précisément comment cette livraison se comporte : ce qui se passe lorsque votre serveur est indisponible, combien de fois nous réessayons, ce que votre pare-feu doit autoriser et à quoi ressemble la requête.
La livraison post-appel avec nouvelles tentatives et journal de livraison est disponible sur tous les plans, y compris Free.
Ce qui est envoyé, et quand
Une requête part dès que l'appel est terminé et que son analyse est achevée (résumé, sentiment, vos champs extraits) — généralement quelques secondes après le raccrochage.
| Source | Où la configurer |
|---|---|
| Action Appel API | Agent → Actions → Post call → Appel API |
| Étape de workflow | Constructeur de workflow → étape d'outil Appel API avec Quand il s’exécute : Après l’appel |
| Webhook de l'agent | Le champ webhook_url de l'agent (référence API) |
Les requêtes qu'un agent effectue pendant une conversation (outils d'appel en direct) ne sont pas concernées ici : elles sont nécessaires à la seconde même et ne sont jamais répétées par la suite.
Lorsque votre serveur est indisponible
Rien n'est perdu. La requête est enregistrée dans une file d'attente de livraison avant la première tentative, et elle y reste jusqu'à ce que votre serveur l'accepte ou que la planification soit épuisée.
- Une livraison est considérée comme réussie lorsque votre endpoint répond avec n'importe quel statut
2xxdans un délai de 30 secondes. - Tout le reste donne lieu à une nouvelle tentative : connexion refusée, erreurs DNS ou TLS, délai dépassé et tout autre statut —
5xx,429, ainsi que4xx. Si une clé API a expiré et que vous la renouvelez, les appels en attente arrivent d'eux-mêmes. - Chaque tentative envoie la même requête avec le même identifiant de livraison.
Planification des nouvelles tentatives
| Tentative | Pause qui la précède | Temps écoulé depuis la fin de l'appel |
|---|---|---|
| 1 | — (immédiatement) | ~0 |
| 2 | 1 minute | ~1 min |
| 3 | 5 minutes | ~6 min |
| 4 | 30 minutes | ~36 min |
| 5 | 2 heures | ~2 h 36 min |
| 6 | 6 heures | ~8 h 36 min |
| 7 | 24 heures | ~1 jour 8 h |
| 8 | 48 heures | ~3 jours 8 h |
Soit 8 tentatives sur environ 3,4 jours — de quoi couvrir une panne pendant un week-end.
Votre propre planification
Dans une action Appel API (et dans une étape de workflow Appel API exécutée après l'appel), vous pouvez remplacer la planification sous Nouvelles tentatives en cas d'échec :
- jusqu'à 10 nouvelles tentatives,
- chaque pause de 1 minute à 7 jours,
- supprimez toutes les lignes pour envoyer une seule fois, sans nouvelle tentative.
Une action que vous n'avez jamais modifiée suit la planification par défaut ci-dessus.
Après la dernière tentative
La livraison est marquée Non livré, vous recevez une notification par e-mail, sauf si vous avez désactivé cette option, et la requête est conservée pendant 30 jours. Durant cette période, vous pouvez la renvoyer — d'un clic dans le journal de livraison ou par un appel API. Le renvoi est également possible pour une livraison déjà réussie, par exemple après une restauration de votre côté.
Indépendamment de tout webhook, l'appel lui-même reste dans votre compte Hanc.AI — transcription, résumé, enregistrement et champs extraits sont disponibles dans Journaux d'appels et via l'API. Une panne prolongée retarde la transmission à votre système ; elle ne supprime pas la conversation.
La livraison a lieu au moins une fois. Dans de rares cas — par exemple lorsque votre serveur a traité une requête mais que la réponse ne nous est pas parvenue à temps — le même appel arrive deux fois. Utilisez X-Hanc-Delivery-Id pour reconnaître une répétition et l'ignorer.
Notifications en cas d'échec
Vous n'avez pas à surveiller le journal : une action peut vous prévenir par e-mail lorsque sa requête n'est pas livrée. Choisissez sous Notification en cas d'échec dans l'action (ou dans l'étape de workflow) :
| Réglage | Quand l'e-mail est envoyé |
|---|---|
| Après la dernière tentative (par défaut) | Une fois, lorsque la planification des nouvelles tentatives est épuisée et que la requête est marquée Non livré |
| Après chaque tentative échouée | Après chaque tentative échouée, avec l'heure de la suivante — et après la dernière |
| Ne pas notifier | Jamais ; les échecs ne sont visibles que dans le journal |
L'e-mail indique l'action et l'agent, l'hôte de votre serveur, ce qu'il a répondu (par exemple HTTP 503 ou timeout after 30s), de quelle tentative il s'agissait et sur combien, et renvoie par un lien au journal de livraison. Le dernier e-mail précise en outre jusqu'à quand la requête est conservée et qu'elle peut être renvoyée.
Envoyer à définit le destinataire — en général la personne qui exploite le système récepteur. Si le champ est laissé vide, l'e-mail est adressé au titulaire du compte. Il est rédigé dans la langue du compte.
Pour éviter qu'une panne n'inonde votre boîte de réception, les notifications sont limitées par action à 10 par heure et 30 par jour ; la dernière avant une pause indique jusqu'à quand celle-ci dure. Chaque échec reste consigné dans le journal. Une requête que vous renvoyez manuellement ne donne lieu à aucune notification.
Journal de livraison
Chaque tentative est consignée : heure, statut HTTP ou erreur réseau, durée et début de la réponse de votre serveur.
Dans l'application : CRM → Communications → ouvrez une entrée de type Appel API. Vous voyez le statut (Livré, Nouvelle tentative, Non livré), toutes les tentatives, l'heure de la prochaine et le bouton Renvoyer.
Via l'API (authentifiez-vous avec votre clé API dans x-api-key) :
| Requête | Résultat |
|---|---|
GET /v1/webhook-deliveries | Vos livraisons, les plus récentes en premier. Filtres : status (pending, delivered, failed), agent_id, call_id, limit, offset |
GET /v1/webhook-deliveries/{id} | Une livraison avec toutes ses tentatives et le corps de la requête |
POST /v1/webhook-deliveries/{id}/resend | La renvoie immédiatement et retourne le résultat |
{
"id": "6ac71fb82e4f72e709a4a566",
"delivery_id": "0b0f2f0e-6c0f-4f0b-9c55-3c6a3a1f8a11",
"kind": "api_call",
"name": "Create ticket",
"call_id": "6ac71f9d2e4f72e709a4a4f0",
"status": "pending",
"attempts_made": 2,
"attempts_max": 8,
"next_attempt_at": "2026-10-09T11:36:04.000Z",
"attempts": [
{ "n": 1, "at": "2026-10-09T11:30:03.512Z", "duration_ms": 212, "error": "connection refused" },
{ "n": 2, "at": "2026-10-09T11:31:04.007Z", "duration_ms": 187, "status_code": 503, "error": "HTTP 503", "response_preview": "Service Unavailable" }
]
}
Les valeurs des en-têtes de la requête enregistrée (vos clés) ne sont jamais retournées.
Réseau et pare-feu
Hanc.AI appelle votre endpoint — la connexion est toujours ouverte de notre côté vers le vôtre.
| Sens | Sortant depuis Hanc.AI → entrant de votre côté |
| Adresses IP sources | 178.104.10.47 (service de livraison) et 128.140.65.92 (service d'appels, utilisé en solution de repli) |
| Protocole | HTTPS (TLS 1.2 ou version ultérieure). Le HTTP non chiffré fonctionne, mais n'est pas recommandé |
| Port | 443, ou le port indiqué dans votre URL |
| Version IP | IPv4 |
| Certificat | Doit être valide et émis par une autorité de certification publique ; les certificats auto-signés sont refusés |
| Temps de réponse | Répondez dans les 30 secondes — idéalement, accusez réception immédiatement et effectuez le traitement en arrière-plan |
| Redirections | Suivies, 5 au maximum |
Liste d'autorisation : si votre pare-feu ou votre WAF filtre par adresse source, autorisez les deux adresses ci-dessus pour le chemin de votre webhook. Nous annonçons à l'avance tout changement de ces adresses.
Impossible : les adresses situées dans un réseau privé (10.x, 172.16–31.x, 192.168.x, localhost). L'endpoint doit être joignable depuis Internet — directement ou via votre reverse proxy / votre passerelle API.
Navigateur : les webhooks fonctionnent de serveur à serveur. Ni réglages du navigateur, ni extensions, ni ports ouverts sur les postes de travail des collaborateurs n'entrent en jeu.
Format de la requête
POST, PUT et PATCH transportent un corps JSON (Content-Type: application/json, UTF-8).
{
"call_from": "+431234567890",
"call_to": "+439876543210",
"direction": "inbound",
"call_type": "phone",
"call_status": "ended",
"start_timestamp": 1730000000000,
"end_timestamp": 1730000187000,
"duration": 187000,
"call_summary": "Customer reports a broken router and asks for a callback…",
"transcription": [
{ "speaker": "agent", "content": "Hello…", "timestamp": 1730000001000 },
{ "speaker": "user", "content": "Hi…", "timestamp": 1730000003000 }
],
"task_achieved": true,
"sentiment": { "sentiment": "neutral", "explanation": "…" },
"custom_analysis_data": {
"customer_number": "K-20417",
"ticket_category": "Hardware",
"priority": "high"
},
"collected_data": { },
"transfer_history": [ ],
"recording_url": "https://…",
"disconnection_reason": "user_hangup"
}
| Champ | Contenu |
|---|---|
call_summary | Résumé de la conversation |
transcription | Conversation complète, réplique par réplique, avec horodatages |
call_from, call_to, direction | Appelant, numéro appelé, entrant ou sortant |
start_timestamp, end_timestamp, duration | Horodatage Unix et durée en millisecondes |
custom_analysis_data | Vos propres champs, extraits de la conversation — voir Variables de récupération |
collected_data | Données recueillies par l'agent pendant l'appel |
sentiment, task_achieved | Tonalité de la conversation et atteinte ou non de son objectif |
recording_url | Lien vers l'enregistrement, si l'enregistrement est activé |
transfer_history | Transferts effectués pendant l'appel |
Pour GET et DELETE, les mêmes champs sont transmis dans la chaîne de requête ; les valeurs imbriquées telles que transcription sont omises.
En-têtes
| En-tête | Signification |
|---|---|
X-Hanc-Delivery-Id | Identifie la livraison. Identique à chaque tentative — utilisez-le pour ignorer les doublons |
X-Hanc-Attempt | Numéro de la tentative, à partir de 1 |
X-Correlation-Id | Identifiant de trace interne ; mentionnez-le lorsque vous contactez le support |
User-Agent | HANC-Webhooks/1.0 |
| vos en-têtes | Tout ce que vous avez configuré dans l'action |
Authentification
Vous décidez de la manière dont votre endpoint nous reconnaît :
- Clé API ou jeton — ajoutez un en-tête à l'action, par ex.
Authorization: Bearer <token>ouX-API-Key: <key>. Les en-têtes sont envoyés à chaque tentative. - Authentification Basic —
Authorization: Basic <base64(user:password)>. - Paramètre de requête — pour les systèmes qui attendent la clé dans l'URL.
- Adresse source — n'autorisez que les adresses IP indiquées ci-dessus.
Ces méthodes peuvent être combinées ; une clé associée à une liste d'autorisation d'adresses IP constitue la configuration habituelle.
Adapter la requête à votre système
Par défaut, la requête transporte l'appel entier (voir Format de la requête). Pour un système qui attend sa propre structure — c'est le cas de la plupart des systèmes de tickets — vous décrivez vous-même cette structure et la remplissez à partir de l'appel.
Variables
Dans une action Appel API post-appel et dans une étape de workflow Appel API, l'URL, les en-têtes, les paramètres de requête et le corps acceptent des variables entre doubles accolades. Elles sont renseignées à partir de l'appel juste avant le départ de la requête.
| Variable | Valeur |
|---|---|
{{call_id}} | Identifiant de l'appel |
{{call_from}}, {{call_to}} | Appelant et numéro appelé |
{{customer_phone}}, {{customer_email}} | Numéro et e-mail de l'interlocuteur, quel que soit le sens de l'appel |
{{call_direction}}, {{call_type}} | inbound / outbound, phone / web |
{{call_start}}, {{call_end}} | Début et fin, ISO 8601 (UTC) |
{{call_duration}} | Durée en secondes |
{{call_summary}} | Résumé de la conversation |
{{call_transcription}} | Conversation complète sous forme de texte |
{{call_sentiment}}, {{call_task_achieved}} | Tonalité et atteinte ou non de l'objectif |
{{call_recording_url}} | Lien vers l'enregistrement |
{{agent_id}} | Identifiant de l'agent |
| vos champs | Chaque Variable de récupération par son nom, par ex. {{customer_number}}, {{priority}} — ainsi que chaque variable recueillie par un workflow pendant l'appel |
Quelques règles utiles à connaître :
- Un champ du corps constitué d'une seule variable conserve le type de cette variable :
"priority": "{{priority}}"est envoyé comme le nombre3,"urgent": "{{urgent}}"commetrue. Du texte autour d'une variable en fait du texte. - Une valeur placée dans l'URL est automatiquement encodée en pourcentage (
+43…devient%2B43…). - Une variable pour laquelle l'appel n'a aucune valeur est envoyée vide — jamais sous la forme littérale
{{name}}.
Dans l'application, le bouton {x} d'un champ affiche la liste des variables disponibles ; dans le corps, la saisie de {{ les propose.
Corps
Sous Corps (JSON) dans l'action, vous écrivez l'objet JSON attendu par votre système, imbriqué aussi profondément que nécessaire :
{
"ticket": {
"subject": "Call from {{customer_phone}}: {{ticket_category}}",
"comment": { "body": "{{call_summary}}" },
"priority": "{{priority}}",
"custom_fields": [
{ "id": 360001, "value": "{{customer_number}}" },
{ "id": 360002, "value": "{{call_recording_url}}" }
],
"tags": ["phone-agent"]
}
}
Uniquement vos champs
Lorsque Envoyer uniquement mes champs est activé, la requête ne transporte que votre corps et vos paramètres de requête — les données de l'appel ne sont pas ajoutées. Si l'option reste désactivée, vos champs sont envoyés en même temps que l'appel complet.
Envoi sélectif
Une condition en langage naturel (« uniquement si l'appelant signale une panne ») détermine quels appels déclenchent la requête. Plusieurs actions peuvent viser des systèmes ou des endpoints différents.
Connecter un système de tickets
Tout système de tickets doté d'une API HTTP ou d'un webhook entrant peut recevoir des appels — directement, sans logiciel intermédiaire. Ce qu'il faut de votre côté :
- Un endpoint joignable depuis Internet en HTTPS et qui accepte du JSON.
- Un identifiant d'accès pour cet endpoint (clé API, jeton ou authentification Basic), saisi comme en-tête dans l'action.
- Si vous filtrez par adresse — les deux adresses IP ci-dessus dans votre liste d'autorisation.
Ensuite, dans l'action :
- Définissez vos champs. Ajoutez des Variables de récupération telles que numéro client, catégorie du ticket, priorité, rappel demandé. L'agent les renseigne à partir de la conversation.
- Rédigez le corps selon la structure de votre API de tickets et placez les variables là où elles doivent figurer.
- Activez Envoyer uniquement mes champs.
- Cliquez sur Tester la configuration API, puis passez un appel de test.
Nous préparons volontiers avec vous le corps adapté à votre système.
Tests
Test de connexion. Le bouton Tester la configuration API de l'action envoie immédiatement une requête d'exemple et indique si votre endpoint a été atteint.
Test des nouvelles tentatives — pour voir le mécanisme de vos propres yeux :
- Dans l'action, définissez une planification courte sous Nouvelles tentatives en cas d'échec, par exemple trois pauses de 1 minute.
- Arrêtez votre endpoint ou bloquez nos adresses dans le pare-feu.
- Passez un appel de test à l'agent.
- Ouvrez CRM → Communications : l'entrée affiche Nouvelle tentative, la tentative échouée avec son erreur et l'heure de la prochaine.
- Redémarrez l'endpoint (ou levez le blocage). La tentative suivante livre l'appel et l'entrée passe à Livré — ou cliquez sur Renvoyer pour livrer immédiatement.
Liste de contrôle pour votre endpoint
- Répondez
2xxdès que la requête est enregistrée ; effectuez le traitement lourd ensuite. - Traitez
X-Hanc-Delivery-Idcomme une clé d'idempotence. - Répondez
4xx/5xxlorsque vous n'avez pas pu prendre en charge la requête — nous reviendrons. - Gardez le certificat valide et les deux adresses sources autorisées.