Webhooks
Webhooks lar systemene dine motta sanntids HTTP POST-varsler når køhendelser skjer — en kølapp blir med i køen, ropes opp, fullføres, og så videre.
Komme i gang
Section titled “Komme i gang”- Åpne admin.jonot.io/settings/integrations.
- Klikk Legg til endepunkt.
- Skriv inn en offentlig HTTPS-URL serveren din lytter på.
- Velg hvilke hendelser du vil abonnere på.
- Klikk Lagre.
Lagre signeringshemmeligheten din — den vises bare én gang. For å bekrefte at endepunktet ditt er nåbart, bruk knappen Send testforespørsel på redigeringssiden for endepunktet.
Hendelsestyper
Section titled “Hendelsestyper”| Hendelsesnavn | Når den utløses |
|---|---|
ticket.joined | En kunde stiller seg i en kø |
ticket.called | En ansatt roper opp en kølapp til skranken |
ticket.completed | En kølapp markeres som fullført |
ticket.cancelled | En kunde eller ansatt avbryter en kølapp |
ticket.skipped | En kølapp hoppes over (en utsettelse som kan ropes opp igjen) |
ticket.no_show | En oppropt eller hoppet-over kølapp bekreftes som en uteblivelse |
queue.status_changed | Statusen til en kø endres (ACTIVE, PAUSED, eller CLOSED) |
Nyttelastformat
Section titled “Nyttelastformat”Hver levering er en HTTP POST med:
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: v1Standardkroppen er en JSON-konvolutt. Formen på payload-feltet varierer etter hendelse:
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" }}Verifisere signaturen
Section titled “Verifisere signaturen”Jonot signerer hver levering med HMAC-SHA256 over strengen:
<deliveryId>.<timestamp>.<body>Slik verifiserer du i 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);}Nyttelastmaler
Section titled “Nyttelastmaler”Du kan erstatte standard JSON-kroppen med en egendefinert mal. Maler bruker en forenklet Mustache-syntaks:
{{ path.to.value }}— erstattes og escapes for innholdstypen: JSON-streng-escapet forapplication/json, prosentkodet forapplication/x-www-form-urlencoded, rått fortext/plain{{{ path.to.value }}}— erstattes rått (ingen escaping)
Eksempelmal for application/json (abonnert på ticket.joined):
{ "type": "{{ event }}", "ticketId": "{{ payload.ticket.id }}", "queueName": "{{ payload.queue.name }}"}Malredigeringsverktøy
Section titled “Malredigeringsverktøy”Feltet for nyttelastmalen er en fullstendig kodeeditor med:
- Syntaksmarkering og parentesmatching for JSON-maler.
- Variabelpalett — en alltid synlig rad med innsettingsknapper, én per tilgjengelig variabelbane for de valgte hendelsene dine. Klikk på en knapp for å sette inn et
{{ path }}-tegn ved markøren. - Live-validering — mens du skriver, sjekker redigeringsverktøyet både JSON-strukturen (når innholdstypen er
application/jsonog ingen rå{{{ }}}-tagger er til stede) og variabelbanene. Diagnostikk vises som innebygde markører i redigeringsverktøyet og som et sammendragsbanner under det:- Feil — en bane som er ukjent i alle de valgte hendelsene dine.
- Advarsel — en bane som bare finnes for noen av de valgte hendelsene dine (den vil være tom for leveringer av de andre hendelsene).
Validering kjører også ved lagring på serveren — tilbakemeldingen i redigeringsverktøyet gjenspeiler serverreglene nøyaktig.
Nye leveringsforsøk
Section titled “Nye leveringsforsøk”Cloudflare Queues venter stadig lenger før hvert nye forsøk. En levering mislykkes når endepunktet returnerer en status utenfor 2xx-området eller tilkoblingen feiler. Hvis det første forsøket og alle 3 nye forsøk mislykkes, flyttes leveringen til dødbrevkøen. Da øker også endepunktets teller for påfølgende feil.
Så snart et endepunkt samler opp 20 påfølgende feil, deaktiveres det automatisk. Aktiver det på nytt fra endepunktets redigeringsside; telleren nullstilles.
Leveringshistorikk
Section titled “Leveringshistorikk”Fanen Leveranser på hvert endepunkt viser leveringsforsøkene fra de siste 30 dagene: hendelsestype, HTTP-status, antall forsøk, og tidsstempel. Bruk knappen Last inn mer for å bla gjennom eldre oppføringer.
Grenser
Section titled “Grenser”| Grense | Verdi |
|---|---|
| Endepunkter per organisasjon | 5 |
| Egendefinerte hoder per endepunkt | 10 |
| Lengde på hodeverdi | 1 024 bytes |
| Størrelse på nyttelastmal | 16 KB |
| Leveringstidsavbrudd | 10 s |
| Oppbevaringstid for leveringshistorikk | 30 dager |
| Maks leveringsrate per organisasjon | 120 / 60 s |
Rotere signeringshemmeligheten
Section titled “Rotere signeringshemmeligheten”- Åpne redigeringssiden for endepunktet.
- Klikk Bytt signeringshemmelighet.
- Bekreft rotasjonen i dialogen.
- Kopier den nye hemmeligheten umiddelbart — den vises bare én gang og kan ikke gjenopprettes. Hvis du lukker dialogen uten å lagre den, må du rotere på nytt for å få en ny klartekstverdi.
- Oppdater serveren din til å verifisere signaturer med den nye hemmeligheten.
Det finnes ingen overgangsperiode. Den gamle hemmeligheten slutter å virke straks du bekrefter rotasjonen. Distribuer den nye hemmeligheten til mottakeren med én gang.
Grensesnittet viser Aktiv hemmelighet: ····XXXX (de siste fire tegnene) ved siden av Bytt-knappen, slik at du kan bekrefte hvilken hemmelighet som gjelder for øyeblikket — nyttig for å bekrefte at mottakeren din og serveren er synkronisert etter en rotasjon.
Hygiene for signeringshemmeligheten
Section titled “Hygiene for signeringshemmeligheten”Når du bør rotere:
- Mistenkt kompromittering: hemmeligheten dukket opp i en loggfil, ble delt med en ansatt som sluttet, eller ble fanget i en skjermopptak.
- Rutinehygiene: regelmessig rotasjon begrenser skadeomfanget av en uoppdaget eksponering.
- Etter enhver endring i hvilke tjenester som kan lese hemmeligheten (rotasjon av nøkkelforvaltning).
Slik oppdaterer du mottakeren:
- Roter i admin-grensesnittet og kopier den nye hemmeligheten.
- Oppdater hemmeligheten i mottakerens hemmelighetslager (miljøvariabel, hemmelighetsforvalter osv.).
- Distribuer den oppdaterte mottakeren.
- Bekreft at neste levering lykkes i fanen Leveranser.
Hvis du mistet den nye hemmeligheten før du lagret den:
Roter på nytt. Hver rotasjon genererer en ny tilfeldig hemmelighet. Den forrige klarteksten kan ikke gjenopprettes — bare en AEAD-kryptert form lagres på serversiden.