Webhooks
Les webhooks sont des notifications automatisées vers des URLs définies qui informent des événements en temps réel. Ils sont utiles car ils permettent une réponse immédiate à des événements spécifiques sans nécessiter d'interrogation continue. Les webhooks aident à maintenir les systèmes efficaces et réactifs.
Vos webhooks sont appelés immédiatement lorsqu'un événement se produit. Si nous ne pouvons pas atteindre votre URL ou si elle répond avec un statut d'erreur, nous relançons l'envoi selon un plan fixe et vérifions automatiquement sur plusieurs jours si le destinataire est en panne durable. Les détails sont décrits plus bas dans Livraison & retries.
Livraison & retries
Quand nous réessayons un webhook
Un webhook n'est relivré que lorsque la réponse de votre serveur indique une erreur temporaire :
- Name
HTTP 429- Type
- rate-limit
- Description
Votre endpoint signale qu'il reçoit actuellement trop de requêtes.
- Name
HTTP 5xx- Type
- erreur serveur
- Description
Concrètement
500,502,503et504.
- Name
Erreurs de connexion- Type
- réseau
- Description
Timeouts, échecs de résolution DNS, erreurs TLS/handshake ou une connexion interrompue pendant la requête.
Toutes les autres réponses sont considérées comme finales et ne déclenchent pas de nouvelle tentative. Cela inclut les codes 4xx tels que 400, 401, 403 et 404, car ils indiquent généralement une erreur de configuration côté destinataire qui ne peut pas être résolue par un simple retry. Les réponses dans la plage 2xx et 3xx sont considérées comme réussies.
Timeout de requête
Chaque tentative de livraison a un timeout de 5 secondes. Si votre serveur ne répond pas dans ce délai, nous traitons la tentative comme un échec et planifions un retry selon le plan ci-dessous.
Plan de retry
Si une tentative échoue, la suivante est planifiée après un délai fixe et croissant. Nous effectuons jusqu'à 14 tentatives au total ; au-delà, le job est abandonné. La fenêtre totale de livraison s'étend donc sur environ 3,5 jours.
| Tentative | Délai depuis la tentative précédente |
|---|---|
| 1 (initiale) | immédiatement |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 60 minutes |
| 6 | 2 heures |
| 7 à 14 | 10 heures chacune |
Désactivation automatique en cas de pannes persistantes
En complément des retries individuels, nous surveillons en continu le taux d'erreur quotidien par webhook. Un webhook est marqué comme « problématique » dès que, sur une journée donnée,
- le taux d'erreur du jour est supérieur à 80 % et
- au moins 10 erreurs sont survenues ce jour-là.
À partir de ce moment, le webhook est observé pendant plusieurs jours. Si la situation ne s'améliore pas, le système escalade par paliers :
| Jour | Seuil (taux d'erreur rolling) | Action |
|---|---|---|
| 1 | supérieur à 80 % | E-mail d'avertissement niveau 1 |
| 3 | supérieur à 85 % | E-mail d'avertissement niveau 2 |
| 5 | supérieur à 90 % | E-mail d'avertissement niveau 3 |
| 7 | supérieur à 95 % | Le webhook est désactivé automatiquement, entrée dans l'audit-log et e-mail de désactivation |
Les compteurs journaliers sont calculés à partir du jour de détection du problème.
Après une désactivation automatique
Un webhook désactivé automatiquement reste inactif jusqu'à ce que vous le réactiviez manuellement dans le Dashboard. Après la réactivation, les statistiques repartent de zéro.
Qu'est-ce qui compte comme « réussi » ?
Pour l'évaluation du taux d'erreur, toute réponse qui n'est pas un déclencheur de retry compte comme « ok ». Concrètement, les réponses 2xx, 3xx et même 4xx (à l'exception de 429) sont traitées comme réussies, car elles représentent, du point de vue du système d'envoi, une réponse finale et sans ambiguïté.
Cela signifie : un endpoint qui répond durablement par 404 ne sera pas désactivé automatiquement et devra être supprimé ou corrigé manuellement par vous.
Sécurité
Vérifier l'IP source
Tous les webhooks proviennent de notre IPv4 195.201.160.143 ou de l'IPv6 2a01:4f8:13a:8e7::2. Si cela devait changer, vous trouverez tous les détails supplémentaires dans notre Changelog.
Vérifier la signature
Tous les webhooks vers votre serveur sont signés avec la clé de signature de votre compte. Vous pouvez utiliser ces données pour valider l'authenticité des requêtes de notre part pour chaque webhook reçu et éviter la duplication ou les requêtes frauduleuses. Pour cela, vérifiez la signature comme décrit sur la page Signature.
Nous vous envoyons les en-têtes suivants dans chaque webhook :
- Name
X-Signature- Type
- string
- Description
La signature générée par nous
- Name
X-Timestamp- Type
- integer
- Description
Timestamp auquel la signature a été créée par nous
- Name
X-Nonce- Type
- string
- Description
Chaîne générée aléatoirement avec 32 caractères
Exemples en charge utile JSON
SMS
SMS entrant (sms_mo)
{
"data": {
"id": "681590",
"sender": "SMS",
"system": "491771783130",
"text": "Hello World",
"time": "1605878104",
"message_type": "SMS"
},
"webhook_event": "sms_mo",
"webhook_timestamp": "2020-12-02 11:55:44"
}
Changement de statut SMS (dlr)
{
"data": {
"msg_id": "77149843739",
"status": "TRANSMITTED",
"timestamp": "2021-08-24 08:08:00.000000"
},
"webhook_event": "dlr",
"webhook_timestamp": "2021-08-24T08:08:00+02:00"
}
Suivi de performance (tracking)
{
"webhook_event": "tracking",
"webhook_timestamp": "2022-07-27T07:38:18+02:00",
"data": {
"sms_id": "77182424125",
"sms_label": null,
"tracking_url": "https://svn.me/7oz",
"final_url": "https://www.google.com",
"type": "click",
"total_clicks": 5,
"total_views": 3
}
}
Voice
Changement de statut message vocal (voice_status)
{
"data": {
"callerId": "49176123456789",
"duration": "4",
"id": "284195",
"pricePerMinute": 0.075,
"recipient": "4943160049851",
"status": "completed",
"timestamp": 1629786769
},
"webhook_event": "voice_status",
"webhook_timestamp": "2021-08-24T08:32:50+02:00"
}
Appel vocal entrant (voice_call)
{
"webhook_event": "voice_call",
"webhook_timestamp": "2024-08-02T07:28:59+02:00",
"data": {
"id": 0,
"caller": "4943160049851",
"time": 1722576539,
"system": "4915170517246"
}
}
Signal DTMF (voice_dtmf)
{
"webhook_event": "voice_dtmf",
"webhook_timestamp": "2024-08-02T07:28:59+02:00",
"data": {
"id": 0,
"callerId": "4943160049851",
"recipient": "4943160049851",
"status": "completed",
"system": "4915170517246",
"timestamp": 1722576539,
"duration": 2.76,
"pricePerMinute": 0.045,
"dtmf_digit": 9,
"total_price": 0.045
}
}
RCS
Le message a été livré
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T10:01:07+01:00",
"data":
{
"msg_id": "77233699836",
"status": "DELIVERED",
"timestamp": "1709888466.254410",
"foreign_id": null,
"agent_id": "myfancyagent"
}
}
Le message a été lu
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T10:01:09+01:00",
"data":
{
"msg_id": "77233699836",
"status": "READ",
"timestamp": "1709888468.065783",
"foreign_id": null,
"agent_id": "myfancyagent"
}
}
Rapport de statut d'un message envoyé
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T10:00:18+01:00",
"data":
{
"sender": "4915153952979",
"status": "IS_TYPING",
"agent_id": "myfancyagent"
}
}
Un message texte a été envoyé
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T09:47:12+01:00",
"data": {
"id": 1871353,
"sender": "4915153952979",
"time": "1709870553",
"message_type": "RCS",
"content_type": "text",
"text": "Hello",
"agent_id": "myfancyagent"
}
}
Une réponse suggérée a été sélectionnée
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T05:59:33+01:00",
"data": {
"id": 1870983,
"sender": "4915153952979",
"time": "1709870129",
"message_type": "RCS",
"content_type": "suggestion_response",
"suggestion_response": {
"postbackData": "suggestion_2",
"text": "Suggestion #2",
"type": "REPLY"
},
"agent_id": "myfancyagent"
}
}
Une image a été envoyée
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T08:58:20+01:00",
"data": {
"id": 1871195,
"sender": "4915153952979",
"time": "1709870556",
"message_type": "RCS",
"content_type": "user_file",
"user_file": {
"thumbnail": {
"mimeType": "image/jpeg",
"fileSizeBytes": 10166,
"fileUri": "https://static.seven.io/uploads/rbm/61513d3d/6176746a5177553d/4f36357145416a773452537737696e495a366a68454a42344639574937716e62704156765358664d486e42776730337334675a76522b6d4f574b6e32626632546842493d.jpeg"
},
"payload": {
"mimeType": "image/jpeg",
"fileSizeBytes": 611314,
"fileName": "IMG_20240308_050231_01.jpg",
"fileUri": "https://static.seven.io/uploads/rbm/61513d3d/6176746a5177553d/4f76746e45515768746866717653444e6166336a513852375249614d753637656f414a6f4758624d5358417269306e767331493645372b47446654325a66764b3168453d.jpeg"
}
},
"agent_id": "myfancyagent"
}
}
Un fichier a été envoyé
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T11:07:51+01:00",
"data": {
"id": 1871485,
"sender": "4915153952979",
"time": "1709892233",
"message_type": "RCS",
"content_type": "user_file",
"user_file": {
"payload": {
"mimeType": "application/pdf",
"fileSizeBytes": 18810,
"fileName": "sample (1).pdf",
"fileUri": "https://static.seven.io/uploads/rbm/61513d3d/617678715267303d/4f616c675256696b73524c6c75337a4b5a66336a51705570464e665a752f6d4e70464d37546e504b5458423730556a7337314e70514c3241436650304d616e4b3078493d.pdf"
}
},
"agent_id": "myfancyagent"
}
}
Une localisation a été partagée
{
"webhook_event": "rcs",
"webhook_timestamp": "2024-03-08T11:07:51+01:00",
"data": {
"id": 1871485,
"sender": "4915153952979",
"time": 1709892233,
"message_type": "RCS",
"content_type": "location",
"location": {
"latitude": 54.3216562,
"longitude": 10.1350767
},
"agent_id": "myfancyagent"
}
}