Webhook
I webhook permettono ai tuoi sistemi di ricevere notifiche HTTP POST in tempo reale quando si verificano eventi di coda — un biglietto si mette in coda, viene chiamato, completato, e così via.
Per iniziare
Sezione intitolata “Per iniziare”- Apri admin.jonot.io/settings/integrations.
- Fai clic su Aggiungi endpoint.
- Inserisci un URL HTTPS pubblico su cui il tuo server è in ascolto.
- Scegli a quali eventi iscriverti.
- Fai clic su Salva.
Salva il tuo segreto di firma — viene mostrato una sola volta. Per verificare che il tuo endpoint sia raggiungibile, usa il pulsante Invia richiesta di prova nella pagina di modifica dell’endpoint.
Tipi di evento
Sezione intitolata “Tipi di evento”| Nome evento | Quando si attiva |
|---|---|
ticket.joined | Un cliente si mette in una coda |
ticket.called | Un membro del personale chiama un biglietto allo sportello |
ticket.completed | Un biglietto viene segnato come completato |
ticket.cancelled | Un cliente o un membro del personale annulla un biglietto |
ticket.skipped | Un biglietto viene saltato (un rinvio richiamabile) |
ticket.no_show | Un biglietto chiamato o saltato viene confermato come assenza |
queue.status_changed | Lo stato di una coda cambia (ACTIVE, PAUSED o CLOSED) |
Formato del payload
Sezione intitolata “Formato del payload”Ogni consegna è una richiesta HTTP POST con:
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: v1Il corpo predefinito è un involucro JSON. La forma del campo payload varia in base all’evento:
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" }}Verificare la firma
Sezione intitolata “Verificare la firma”Jonot firma ogni consegna con HMAC-SHA256 sulla stringa:
<deliveryId>.<timestamp>.<body>Per verificare in Node.js (≥18):
import { createHmac, timingSafeEqual } from "node:crypto";
/** * Returns true when the signature header is valid and the timestamp is * within 5 minutes of now. Throws for malformed input. */function verifySignature(secret, deliveryId, timestamp, body, header) { // Replay-attack guard: reject deliveries older than 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 prevents timing-oracle attacks. // Buffers must be the same length — if lengths differ the signature is // invalid, but we still compare a dummy value to keep constant time. const expectedBuf = Buffer.from(expected); const headerBuf = Buffer.from(header); if (expectedBuf.length !== headerBuf.length) return false; return timingSafeEqual(expectedBuf, headerBuf);}Modelli di payload
Sezione intitolata “Modelli di payload”Puoi sostituire il corpo JSON predefinito con un modello personalizzato. I modelli usano una sintassi Mustache semplificata:
{{ path.to.value }}— sostituito ed escapato in base al tipo di contenuto: escapato come stringa JSON perapplication/json, codificato percentuale perapplication/x-www-form-urlencoded, non modificato pertext/plain{{{ path.to.value }}}— sostituito senza modifiche (nessun escaping)
Modello di esempio per application/json (iscritto a ticket.joined):
{ "type": "{{ event }}", "ticketId": "{{ payload.ticket.id }}", "queueName": "{{ payload.queue.name }}"}Editor di modelli
Sezione intitolata “Editor di modelli”Il campo del modello di payload è un editor di codice completo con:
- Evidenziazione della sintassi e corrispondenza delle parentesi per i modelli JSON.
- Tavolozza delle variabili — una riga sempre visibile di pulsanti di inserimento, uno per ogni percorso di variabile disponibile per gli eventi selezionati. Fai clic su un pulsante per inserire un token
{{ path }}alla posizione del cursore. - Validazione dal vivo — mentre digiti, l’editor controlla sia la struttura JSON (quando il tipo di contenuto è
application/jsone non sono presenti tag{{{ }}}non modificati) sia i percorsi delle variabili. Le diagnosi appaiono come indicatori in linea nell’editor e come banner di riepilogo sotto di esso:- Errore — un percorso sconosciuto in tutti gli eventi selezionati.
- Avviso — un percorso che esiste solo per alcuni degli eventi selezionati (sarà vuoto per le consegne degli altri eventi).
La validazione viene eseguita anche al momento del salvataggio sul server — il feedback dell’editor rispecchia esattamente le regole del server.
Nuovi tentativi di consegna
Sezione intitolata “Nuovi tentativi di consegna”Le consegne fallite (non-2xx o errore di connessione) vengono ritentate fino a 3 volte con backoff esponenziale da Cloudflare Queues. Dopo 3 fallimenti, la consegna finisce nella coda dead-letter e il contatore fallimenti consecutivi dell’endpoint si incrementa.
Una volta che un endpoint accumula 20 fallimenti consecutivi, viene disattivato automaticamente. Riattivalo dalla pagina di modifica dell’endpoint; il contatore si azzera.
Cronologia delle consegne
Sezione intitolata “Cronologia delle consegne”La scheda Consegne di ciascun endpoint mostra i tentativi di consegna degli ultimi 30 giorni: tipo di evento, stato HTTP, numero di tentativi e timestamp. Usa il pulsante Carica altro per scorrere i record più vecchi.
| Limite | Valore |
|---|---|
| Endpoint per organizzazione | 5 |
| Header personalizzati per endpoint | 10 |
| Lunghezza del valore dell’header | 1.024 byte |
| Dimensione del modello di payload | 16 KB |
| Timeout di consegna | 10 s |
| Conservazione della cronologia consegne | 30 giorni |
| Frequenza massima di consegna per organizzazione | 120 / 60 s |
Ruotare il segreto di firma
Sezione intitolata “Ruotare il segreto di firma”- Apri la pagina di modifica dell’endpoint.
- Fai clic su Ruota il segreto di firma.
- Conferma la rotazione nella finestra di dialogo.
- Copia immediatamente il nuovo segreto — viene mostrato una sola volta e non può essere recuperato. Se chiudi la finestra senza salvarlo, dovrai ruotare di nuovo per ottenere un nuovo valore in chiaro.
- Aggiorna il tuo server per verificare le firme con il nuovo segreto.
Non c’è una finestra di sovrapposizione. Il vecchio segreto smette di verificare non appena confermi la rotazione. Pianifica di distribuire il nuovo segreto al tuo ricevitore immediatamente dopo la rotazione.
L’interfaccia mostra Segreto attivo: ····XXXX (gli ultimi quattro caratteri) accanto al pulsante Ruota così puoi verificare quale segreto è attualmente in vigore — utile per confermare che il tuo ricevitore e il server siano sincronizzati dopo una rotazione.
Igiene del segreto di firma
Sezione intitolata “Igiene del segreto di firma”Quando ruotare:
- Sospetto di compromissione: il segreto è apparso in un file di log, è stato condiviso con un dipendente in uscita o è stato catturato in una registrazione dello schermo.
- Igiene di routine: la rotazione periodica limita il raggio d’azione di un’esposizione non rilevata.
- Dopo qualsiasi modifica a quali servizi possono leggere il segreto (rotazione della gestione delle chiavi).
Come aggiornare il ricevitore:
- Ruota nell’interfaccia di Admin e copia il nuovo segreto.
- Aggiorna il segreto nell’archivio segreti del tuo ricevitore (variabile d’ambiente, gestore di segreti, ecc.).
- Distribuisci il ricevitore aggiornato.
- Conferma nella scheda Consegne che la consegna successiva ha successo.
Se hai perso il nuovo segreto prima di salvarlo:
Ruota di nuovo. Ogni rotazione genera un nuovo segreto casuale. Il valore in chiaro precedente non è recuperabile — lato server viene memorizzata solo una forma crittografata AEAD.