Webhooks
Met webhooks kunnen je systemen realtime HTTP POST-meldingen ontvangen wanneer wachtrijgebeurtenissen plaatsvinden — een ticket sluit aan, wordt opgeroepen, wordt afgerond, enzovoort.
Aan de slag
Section titled “Aan de slag”- Open admin.jonot.io/settings/integrations.
- Klik op Endpoint toevoegen.
- Voer een openbare HTTPS-URL in waar je server naar luistert.
- Kies op welke gebeurtenissen je je wilt abonneren.
- Klik op Opslaan.
Bewaar je ondertekeningsgeheim — dit wordt slechts één keer getoond. Om te controleren of je eindpunt bereikbaar is, gebruik je de knop Testverzoek versturen op de bewerkingspagina van het eindpunt.
Gebeurtenistypen
Section titled “Gebeurtenistypen”| Naam van de gebeurtenis | Wanneer deze afgaat |
|---|---|
ticket.joined | Een klant sluit aan bij een wachtrij |
ticket.called | Een personeelslid roept een ticket op naar de servicebalie |
ticket.completed | Een ticket wordt gemarkeerd als afgerond |
ticket.cancelled | Een klant of personeelslid annuleert een ticket |
ticket.skipped | Een ticket wordt overgeslagen (een terugroepbaar uitstel) |
ticket.no_show | Een opgeroepen of overgeslagen ticket wordt bevestigd als no-show |
queue.status_changed | De status van een wachtrij verandert (ACTIVE, PAUSED of CLOSED) |
Payload-formaat
Section titled “Payload-formaat”Elke aflevering is een HTTP POST met:
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: v1De standaardinhoud is een JSON-envelop. De vorm van het payload-veld varieert per gebeurtenis:
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" }}De handtekening verifiëren
Section titled “De handtekening verifiëren”Jonot ondertekent elke aflevering met HMAC-SHA256 over de string:
<deliveryId>.<timestamp>.<body>Verifiëren in Node.js (≥18):
import { createHmac, timingSafeEqual } from "node:crypto";
/** * Geeft true terug wanneer de signature-header geldig is en het tijdstempel * binnen 5 minuten van nu ligt. Gooit een fout bij misvormde invoer. */function verifySignature(secret, deliveryId, timestamp, body, header) { // Bescherming tegen replay-aanvallen: weiger afleveringen ouder dan 5 minuten. 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 voorkomt timing-oracle-aanvallen. // Buffers moeten dezelfde lengte hebben — als de lengtes verschillen is de // handtekening ongeldig, maar we vergelijken toch een dummy-waarde om // constante tijd te behouden. const expectedBuf = Buffer.from(expected); const headerBuf = Buffer.from(header); if (expectedBuf.length !== headerBuf.length) return false; return timingSafeEqual(expectedBuf, headerBuf);}Payload-sjablonen
Section titled “Payload-sjablonen”Je kunt de standaard JSON-inhoud vervangen door een aangepast sjabloon. Sjablonen gebruiken Mustache-lite-syntaxis:
{{ path.to.value }}— vervangen en geëscaped voor het content-type: JSON-string-geëscaped voorapplication/json, percent-encoded voorapplication/x-www-form-urlencoded, ruw voortext/plain{{{ path.to.value }}}— ruw vervangen (geen escaping)
Voorbeeldsjabloon voor application/json (geabonneerd op ticket.joined):
{ "type": "{{ event }}", "ticketId": "{{ payload.ticket.id }}", "queueName": "{{ payload.queue.name }}"}Sjabloon-editor
Section titled “Sjabloon-editor”Het veld voor het payload-sjabloon is een volledige code-editor met:
- Syntaxismarkering en haakjeskoppeling voor JSON-sjablonen.
- Variabelenpalet — een altijd zichtbare rij invoegknoppen, één per beschikbaar variabelenpad voor je geselecteerde gebeurtenissen. Klik op een knop om een
{{ path }}-token op de cursorpositie in te voegen. - Live validatie — terwijl je typt, controleert de editor zowel de JSON-structuur (wanneer het content-type
application/jsonis en er geen ruwe{{{ }}}-tags aanwezig zijn) als de variabelenpaden. Diagnostiek verschijnt als inline markeringen in de editor en als een samenvattingsbanner eronder:- Fout — een pad dat onbekend is in al je geselecteerde gebeurtenissen.
- Waarschuwing — een pad dat alleen bestaat voor sommige van je geselecteerde gebeurtenissen (het zal leeg zijn voor afleveringen van de andere gebeurtenissen).
Validatie draait ook bij het opslaan op de server — de feedback van de editor weerspiegelt exact dezelfde regels als de server.
Afleverpogingen opnieuw proberen
Section titled “Afleverpogingen opnieuw proberen”Mislukte afleveringen (niet-2xx of verbindingsfout) worden door Cloudflare Queues tot 3 keer opnieuw geprobeerd met exponentiële back-off. Na 3 mislukkingen komt de aflevering in de dead-letter-wachtrij terecht en verhoogt de teller opeenvolgende mislukkingen van het eindpunt.
Zodra een eindpunt 20 opeenvolgende mislukkingen heeft opgebouwd, wordt het automatisch uitgeschakeld. Schakel het weer in vanaf de bewerkingspagina van het eindpunt; de teller wordt teruggezet naar nul.
Afleveringsgeschiedenis
Section titled “Afleveringsgeschiedenis”Het tabblad Afleveringen op elk eindpunt toont de afleverpogingen van de afgelopen 30 dagen: gebeurtenistype, HTTP-status, aantal pogingen en tijdstempel. Gebruik de knop Meer laden om door oudere records te bladeren.
Limieten
Section titled “Limieten”| Limiet | Waarde |
|---|---|
| Eindpunten per organisatie | 5 |
| Aangepaste headers per eindpunt | 10 |
| Lengte van headerwaarde | 1.024 bytes |
| Grootte van payload-sjabloon | 16 KB |
| Time-out voor aflevering | 10 s |
| Bewaartermijn afleveringsgeschiedenis | 30 dagen |
| Max. afleverfrequentie per organisatie | 120 / 60 s |
Het ondertekeningsgeheim roteren
Section titled “Het ondertekeningsgeheim roteren”- Open de bewerkingspagina van het eindpunt.
- Klik op Ondertekeningsgeheim roteren.
- Bevestig de rotatie in het dialoogvenster.
- Kopieer het nieuwe geheim onmiddellijk — het wordt slechts één keer getoond en kan niet worden hersteld. Als je het dialoogvenster sluit zonder het op te slaan, moet je opnieuw roteren om een nieuwe leestekst te verkrijgen.
- Werk je server bij om handtekeningen te verifiëren met het nieuwe geheim.
Er is geen overlapvenster. Het oude geheim stopt met verifiëren zodra je de rotatie bevestigt. Plan om het nieuwe geheim onmiddellijk na het roteren naar je ontvanger te deployen.
De interface toont Actief geheim: ····XXXX (de laatste vier tekens) naast de knop Roteren, zodat je kunt verifiëren welk geheim momenteel actief is — handig om te bevestigen dat je ontvanger en de server na een rotatie synchroon lopen.
Hygiëne van het ondertekeningsgeheim
Section titled “Hygiëne van het ondertekeningsgeheim”Wanneer roteren:
- Vermoede compromittering: het geheim verscheen in een logbestand, werd gedeeld met een vertrekkende medewerker, of werd vastgelegd in een schermopname.
- Routinehygiëne: periodiek roteren beperkt de impactradius van een onopgemerkte blootstelling.
- Na elke wijziging in welke services het geheim kunnen lezen (rotatie van sleutelbeheer).
Hoe je de ontvanger bijwerkt:
- Roteer in de admin-interface en kopieer het nieuwe geheim.
- Werk het geheim bij in de geheimenopslag van je ontvanger (omgevingsvariabele, secrets manager, enz.).
- Deploy de bijgewerkte ontvanger.
- Bevestig dat de volgende aflevering slaagt in het tabblad Afleveringen.
Als je het nieuwe geheim bent kwijtgeraakt voordat je het hebt opgeslagen:
Roteer opnieuw. Elke rotatie genereert een nieuw willekeurig geheim. De vorige leestekst kan niet worden hersteld — server-side wordt alleen een AEAD-versleutelde vorm opgeslagen.