Hoppa till innehåll

Webhooks

Webhooks låter dina system ta emot realtids-HTTP POST-notiser när köhändelser inträffar — en biljett går med, ropas upp, slutförs och så vidare.

  1. Öppna admin.jonot.io/settings/integrations.
  2. Klicka på Lägg till slutpunkt.
  3. Ange en publik HTTPS-URL som din server lyssnar på.
  4. Välj vilka händelser du vill prenumerera på.
  5. Klicka på Spara slutpunkt.

Spara din signeringshemlighet — den visas bara en gång. För att verifiera att din slutpunkt är nåbar, använd knappen Skicka testförfrågan på slutpunktens redigeringssida.

HändelsenamnNär den utlöses
ticket.joinedEn kund går med i en kö
ticket.calledEn medarbetare ropar upp en biljett till servicedisken
ticket.completedEn biljett markeras som slutförd
ticket.cancelledEn kund eller medarbetare avbryter en biljett
ticket.skippedEn biljett hoppas över (en uppskjutning som kan ropas upp igen)
ticket.no_showEn uppropad eller överhoppad biljett bekräftas som uteblivet besök
queue.status_changedEn kös status ändras (ACTIVE, PAUSED eller CLOSED)

Varje leverans är en HTTP POST med:

Content-Type: application/json
X-Jonot-Event: ticket.called
X-Jonot-Delivery-Id: <uuid>
X-Jonot-Timestamp: 2024-06-01T12:00:00.000Z
X-Jonot-Signature: v1,<base64-hmac-sha256>
X-Jonot-Payload-Version: v1

Standardinnehållet är ett JSON-kuvert. Formen på fältet payload varierar beroende på händelse:

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"
}
}

Jonot signerar varje leverans med HMAC-SHA256 över strängen:

<deliveryId>.<timestamp>.<body>

Så här verifierar 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);
}

Du kan ersätta standard-JSON-innehållet med en anpassad mall. Mallar använder en förenklad Mustache-syntax:

  • {{ path.to.value }} — ersätts och undantas beroende på innehållstyp: JSON-strängescapad för application/json, procentkodad för application/x-www-form-urlencoded, rå för text/plain
  • {{{ path.to.value }}} — ersätts rått (ingen escaping)

Exempelmall för application/json (prenumererad på ticket.joined):

{
"type": "{{ event }}",
"ticketId": "{{ payload.ticket.id }}",
"queueName": "{{ payload.queue.name }}"
}

Fältet för nyttolastmall är en fullständig kodredigerare med:

  • Syntaxmarkering och parentesmatchning för JSON-mallar.
  • Variabelpalett — en alltid synlig rad med infogningsknappar, en per tillgänglig variabelsökväg för dina valda händelser. Klicka på en knapp för att infoga en {{ path }}-token vid markören.
  • Realtidsvalidering — medan du skriver kontrollerar redigeraren både JSON-strukturen (när innehållstypen är application/json och inga råa {{{ }}}-taggar finns) och variabelsökvägarna. Diagnostik visas som infogade markörer i redigeraren och som en sammanfattningsbanner under den:
    • Fel — en sökväg som är okänd i alla dina valda händelser.
    • Varning — en sökväg som bara finns för vissa av dina valda händelser (den kommer att vara tom för leveranser av de andra händelserna).

Validering körs också vid sparande på servern — redigerarens återkoppling speglar exakt serverns regler.

Misslyckade leveranser (icke-2xx eller anslutningsfel) görs om upp till 3 gånger med exponentiell backoff av Cloudflare Queues. Efter 3 misslyckanden hamnar leveransen i dödbrevskön, och slutpunktens räknare för på varandra följande misslyckanden ökar.

När en slutpunkt samlar på sig 20 på varandra följande misslyckanden inaktiveras den automatiskt. Återaktivera den från slutpunktens redigeringssida; räknaren återställs till noll.

Fliken Leveranser på varje slutpunkt visar de senaste 30 dagarnas leveransförsök: händelsetyp, HTTP-status, antal försök och tidsstämpel. Använd knappen Ladda mer för att bläddra genom äldre poster.

GränsVärde
Slutpunkter per organisation5
Anpassade headers per slutpunkt10
Header-värdets längd1 024 byte
Nyttolastmallens storlek16 KB
Leveranstimeout10 s
Kvarhållning av leveranshistorik30 dagar
Max leveransfrekvens per organisation120 / 60 s
  1. Öppna slutpunktens redigeringssida.
  2. Klicka på Rotera signeringshemlighet.
  3. Bekräfta rotationen i dialogrutan.
  4. Kopiera den nya hemligheten omedelbart — den visas bara en gång och kan inte återställas. Om du stänger dialogrutan utan att spara den måste du rotera igen för att få en ny klartext.
  5. Uppdatera din server att verifiera signaturer med den nya hemligheten.

Det finns inget överlappningsfönster. Den gamla hemligheten slutar verifiera så snart du bekräftar rotationen. Planera att driftsätta den nya hemligheten till din mottagare omedelbart efter rotationen.

Gränssnittet visar Active secret: ····XXXX (de fyra sista tecknen) bredvid Rotera-knappen så att du kan verifiera vilken hemlighet som för närvarande gäller — användbart för att bekräfta att din mottagare och servern är synkroniserade efter en rotation.

När du ska rotera:

  • Misstänkt komprometterande: hemligheten dök upp i en loggfil, delades med en avgående medarbetare, eller fångades i en skärminspelning.
  • Rutinhygien: att rotera regelbundet begränsar skadeomfånget av en oupptäckt exponering.
  • Efter varje ändring av vilka tjänster som kan läsa hemligheten (rotation av nyckelhantering).

Så här uppdaterar du mottagaren:

  1. Rotera i admingränssnittet och kopiera den nya hemligheten.
  2. Uppdatera hemligheten i din mottagares hemlighetslager (miljövariabel, secrets manager, osv.).
  3. Driftsätt den uppdaterade mottagaren.
  4. Bekräfta att nästa leverans lyckas på fliken Leveranser.

Om du tappade bort den nya hemligheten innan du sparade den:

Rotera igen. Varje rotation genererar en ny slumpmässig hemlighet. Den tidigare klartexten går inte att återställa — bara en AEAD-krypterad form lagras på serversidan.