Webhooks
Les webhooks permettent à vos systèmes de recevoir des notifications HTTP POST en temps réel lorsque des événements de file d’attente se produisent — un ticket rejoint la file, est appelé, se termine, etc.
Démarrage
Section intitulée « Démarrage »- Ouvrez admin.jonot.io/settings/integrations.
- Cliquez sur Ajouter un point de terminaison.
- Saisissez une URL HTTPS publique que votre serveur écoute.
- Choisissez les événements auxquels vous abonner.
- Cliquez sur Enregistrer.
Enregistrez votre secret de signature — il n’est affiché qu’une seule fois. Pour vérifier que votre point de terminaison est accessible, utilisez le bouton Envoyer une requête de test sur la page de modification du point de terminaison.
Types d’événements
Section intitulée « Types d’événements »| Nom de l’événement | Quand il se déclenche |
|---|---|
ticket.joined | Un client rejoint une file d’attente |
ticket.called | Un membre du personnel appelle un ticket au guichet de service |
ticket.completed | Un ticket est marqué terminé |
ticket.cancelled | Un client ou un membre du personnel annule un ticket |
ticket.skipped | Un ticket est passé (un report rappelable) |
ticket.no_show | Un ticket appelé ou passé est confirmé comme une absence |
queue.status_changed | Le statut d’une file d’attente change (ACTIVE, PAUSED, ou CLOSED) |
Format de la charge utile
Section intitulée « Format de la charge utile »Chaque livraison est une requête HTTP POST avec :
Content-Type: application/jsonX-Jonot-Event: ticket.calledX-Jonot-Delivery-Id: <uuid>X-Jonot-Timestamp: 2024-06-01T12:00:00.000ZX-Jonot-Signature: v1,<base64-hmac-sha256>X-Jonot-Payload-Version: v1Le corps par défaut est une enveloppe JSON. La forme du champ payload varie selon l’événement :
ticket.joined
{ "deliveryId": "<uuid>", "event": "ticket.joined", "timestamp": "2024-06-01T12:00:00.000Z", "org": { "id": "org_…", "name": "My Org" }, "payload": { "ticket": { "id": "tkt_…", "queueId": "q_…" }, "queue": { "id": "q_…", "name": "Main Queue" }, "location": { "id": "loc_…", "name": "Downtown" } }}ticket.called / ticket.completed / ticket.skipped / ticket.no_show
{ "deliveryId": "<uuid>", "event": "ticket.called", "timestamp": "2024-06-01T12:00:00.000Z", "org": { "id": "org_…", "name": "My Org" }, "payload": { "ticket": { "id": "tkt_…", "number": 42, "status": "CALLED", "queueId": "q_…", "createdAt": "2024-06-01T11:58:00.000Z", "updatedAt": "2024-06-01T12:00:00.000Z" } }}ticket.cancelled
{ "deliveryId": "<uuid>", "event": "ticket.cancelled", "timestamp": "2024-06-01T12:00:00.000Z", "org": { "id": "org_…", "name": "My Org" }, "payload": { "ticketId": "tkt_…", "queueId": "q_…" }}queue.status_changed
{ "deliveryId": "<uuid>", "event": "queue.status_changed", "timestamp": "2024-06-01T12:00:00.000Z", "org": { "id": "org_…", "name": "My Org" }, "payload": { "queueId": "q_…", "status": "PAUSED" }}Vérifier la signature
Section intitulée « Vérifier la signature »Jonot signe chaque livraison avec HMAC-SHA256 sur la chaîne :
<deliveryId>.<timestamp>.<body>Pour vérifier en Node.js (≥18) :
import { createHmac, timingSafeEqual } from "node:crypto";
/** * Retourne true lorsque l'en-tête de signature est valide et que * l'horodatage est à moins de 5 minutes de maintenant. Lève une exception * pour une entrée malformée. */function verifySignature(secret, deliveryId, timestamp, body, header) { // Protection contre le rejeu : rejette les livraisons de plus de 5 minutes. const ageMs = Date.now() - new Date(timestamp).getTime(); if (Math.abs(ageMs) > 5 * 60 * 1000) return false;
const expected = "v1," + createHmac("sha256", secret) .update(`${deliveryId}.${timestamp}.${body}`) .digest("base64");
// timingSafeEqual empêche les attaques par oracle de synchronisation. // Les tampons doivent être de la même longueur — si les longueurs // diffèrent, la signature est invalide, mais on compare quand même une // valeur factice pour garder un temps constant. const expectedBuf = Buffer.from(expected); const headerBuf = Buffer.from(header); if (expectedBuf.length !== headerBuf.length) return false; return timingSafeEqual(expectedBuf, headerBuf);}Modèles de charge utile
Section intitulée « Modèles de charge utile »Vous pouvez remplacer le corps JSON par défaut par un modèle personnalisé. Les modèles utilisent une syntaxe Mustache allégée :
{{ path.to.value }}— substitué et échappé selon le type de contenu : échappé chaîne JSON pourapplication/json, encodé en pourcentage pourapplication/x-www-form-urlencoded, brut pourtext/plain{{{ path.to.value }}}— substitué brut (sans échappement)
Exemple de modèle pour application/json (abonné à ticket.joined) :
{ "type": "{{ event }}", "ticketId": "{{ payload.ticket.id }}", "queueName": "{{ payload.queue.name }}"}Éditeur de modèle
Section intitulée « Éditeur de modèle »Le champ de modèle de charge utile est un éditeur de code complet avec :
- Coloration syntaxique et appariement des accolades pour les modèles JSON.
- Palette de variables — une rangée toujours visible de boutons d’insertion, un par chemin de variable disponible pour vos événements sélectionnés. Cliquez sur un bouton pour insérer un jeton
{{ path }}au curseur. - Validation en direct — au fur et à mesure de la saisie, l’éditeur vérifie à la fois la structure JSON (lorsque le type de contenu est
application/jsonet qu’aucune balise brute{{{ }}}n’est présente) et les chemins de variables. Les diagnostics apparaissent comme des marqueurs en ligne dans l’éditeur et comme une bannière récapitulative en dessous :- Erreur — un chemin inconnu dans tous vos événements sélectionnés.
- Avertissement — un chemin qui n’existe que pour certains de vos événements sélectionnés (il sera vide pour les livraisons des autres événements).
La validation s’exécute aussi au moment de l’enregistrement sur le serveur — le retour de l’éditeur reflète exactement les règles du serveur.
Nouvelles tentatives de livraison
Section intitulée « Nouvelles tentatives de livraison »Les livraisons échouées (statut non-2xx ou erreur de connexion) sont retentées jusqu’à 3 fois avec un délai exponentiel par Cloudflare Queues. Après 3 échecs, la livraison atterrit dans la file d’attente des messages morts et le compteur d’échecs consécutifs du point de terminaison s’incrémente.
Une fois qu’un point de terminaison accumule 20 échecs consécutifs, il est automatiquement désactivé. Réactivez-le depuis la page de modification du point de terminaison ; le compteur revient à zéro.
Historique de livraison
Section intitulée « Historique de livraison »L’onglet Livraisons de chaque point de terminaison affiche les tentatives de livraison des 30 derniers jours : type d’événement, statut HTTP, nombre de tentatives, et horodatage. Utilisez le bouton Charger plus pour parcourir les enregistrements plus anciens.
| Limite | Valeur |
|---|---|
| Points de terminaison par organisation | 5 |
| En-têtes personnalisés par point de terminaison | 10 |
| Longueur de valeur d’en-tête | 1 024 octets |
| Taille du modèle de charge utile | 16 Ko |
| Délai d’expiration de livraison | 10 s |
| Rétention de l’historique de livraison | 30 jours |
| Taux de livraison max. par organisation | 120 / 60 s |
Rotation du secret de signature
Section intitulée « Rotation du secret de signature »- Ouvrez la page de modification du point de terminaison.
- Cliquez sur Renouveler le secret de signature.
- Confirmez la rotation dans la boîte de dialogue.
- Copiez le nouveau secret immédiatement — il n’est affiché qu’une seule fois et ne peut pas être récupéré. Si vous fermez la boîte de dialogue sans l’enregistrer, vous devrez faire pivoter à nouveau pour obtenir un nouveau texte en clair.
- Mettez à jour votre serveur pour vérifier les signatures avec le nouveau secret.
Il n’y a pas de fenêtre de chevauchement. L’ancien secret cesse de vérifier dès que vous confirmez la rotation. Prévoyez de déployer le nouveau secret sur votre récepteur immédiatement après la rotation.
L’interface affiche Secret actif : ····XXXX (les quatre derniers caractères) à côté du bouton Rotation afin que vous puissiez vérifier quel secret est actuellement en vigueur — utile pour confirmer que votre récepteur et le serveur sont synchronisés après une rotation.
Hygiène du secret de signature
Section intitulée « Hygiène du secret de signature »Quand faire pivoter :
- Compromission suspectée : le secret est apparu dans un fichier journal, a été partagé avec un employé partant, ou a été capturé dans un enregistrement d’écran.
- Hygiène de routine : une rotation périodique limite le rayon d’impact d’une exposition non détectée.
- Après tout changement des services pouvant lire le secret (rotation de la gestion des clés).
Comment mettre à jour le récepteur :
- Faites pivoter dans l’interface Admin et copiez le nouveau secret.
- Mettez à jour le secret dans le magasin de secrets de votre récepteur (variable d’environnement, gestionnaire de secrets, etc.).
- Déployez le récepteur mis à jour.
- Confirmez que la prochaine livraison réussit dans l’onglet Livraisons.
Si vous avez perdu le nouveau secret avant de l’enregistrer :
Faites pivoter à nouveau. Chaque rotation génère un nouveau secret aléatoire. Le texte en clair précédent n’est pas récupérable — seule une forme chiffrée AEAD est stockée côté serveur.