Webhooks
Webhooks senden eine HTTP-POST-Anfrage an Ihr System, wenn ein Ereignis in einer Warteschlange eintritt. Dazu gehören der Beitritt, Aufruf und Abschluss eines Tickets.
Erste Schritte
Abschnitt betitelt „Erste Schritte“- Öffnen Sie admin.jonot.io/settings/integrations.
- Klicken Sie auf Endpunkt hinzufügen.
- Geben Sie eine öffentliche HTTPS-URL ein, auf der Ihr Server lauscht.
- Wählen Sie die Ereignisse aus, die Sie abonnieren möchten.
- Klicken Sie auf Endpunkt speichern.
Kopieren und speichern Sie das Signaturgeheimnis, wenn es erscheint. Jonot zeigt es nur einmal an. Mit Testanfrage senden auf der Bearbeitungsseite prüfen Sie, ob Jonot den Endpunkt erreicht.
Ereignistypen
Abschnitt betitelt „Ereignistypen“| Ereignisname | Wann es ausgelöst wird |
|---|---|
ticket.joined | Ein Kunde tritt einer Warteschlange bei |
ticket.called | Ein Mitarbeiter ruft ein Ticket zum Schalter auf |
ticket.completed | Ein Ticket wird als abgeschlossen markiert |
ticket.cancelled | Ein Kunde oder Mitarbeiter storniert ein Ticket |
ticket.skipped | Ein Ticket wird übersprungen (ein erneut aufrufbarer Aufschub) |
ticket.no_show | Ein aufgerufenes oder übersprungenes Ticket wird als Nichterscheinen bestätigt |
queue.status_changed | Der Status einer Warteschlange ändert sich (ACTIVE, PAUSED oder CLOSED) |
Payload-Format
Abschnitt betitelt „Payload-Format“Jede Zustellung ist ein HTTP-POST mit:
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: v1Der Standardkörper ist ein JSON-Umschlag. Die Form des payload-Felds variiert je nach Ereignis:
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" }}Die Signatur überprüfen
Abschnitt betitelt „Die Signatur überprüfen“Jonot signiert jede Zustellung mit HMAC-SHA256 über die Zeichenkette:
<deliveryId>.<timestamp>.<body>Überprüfung 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);}Payload-Vorlagen
Abschnitt betitelt „Payload-Vorlagen“Sie können den Standard-JSON-Körper durch eine benutzerdefinierte Vorlage ersetzen. Vorlagen verwenden eine vereinfachte Mustache-Syntax:
{{ path.to.value }}— wird ersetzt und je nach Inhaltstyp escaped: als JSON-String escaped fürapplication/json, prozentkodiert fürapplication/x-www-form-urlencoded, unverändert fürtext/plain{{{ path.to.value }}}— wird unverändert ersetzt (kein Escaping)
Beispielvorlage für application/json (abonniert für ticket.joined):
{ "type": "{{ event }}", "ticketId": "{{ payload.ticket.id }}", "queueName": "{{ payload.queue.name }}"}Vorlageneditor
Abschnitt betitelt „Vorlageneditor“Das Feld für die Payload-Vorlage ist ein vollständiger Code-Editor mit:
- Syntaxhervorhebung und Klammerabgleich für JSON-Vorlagen.
- Variablenpalette — eine stets sichtbare Zeile mit Einfügeschaltflächen, eine pro verfügbarem Variablenpfad für Ihre ausgewählten Ereignisse. Klicken Sie auf eine Schaltfläche, um ein
{{ path }}-Token an der Cursorposition einzufügen. - Live-Validierung — während der Eingabe prüft der Editor sowohl die JSON-Struktur (wenn der Inhaltstyp
application/jsonist und keine rohen{{{ }}}-Tags vorhanden sind) als auch die Variablenpfade. Diagnosen erscheinen als Inline-Markierungen im Editor und als zusammenfassendes Banner darunter:- Fehler — ein Pfad, der in allen Ihren ausgewählten Ereignissen unbekannt ist.
- Warnung — ein Pfad, der nur für einige Ihrer ausgewählten Ereignisse existiert (er ist bei Zustellungen der anderen Ereignisse leer).
Die Validierung läuft auch beim Speichern auf dem Server — die Editor-Rückmeldung entspricht exakt den Serverregeln.
Wiederholungsversuche bei Zustellungen
Abschnitt betitelt „Wiederholungsversuche bei Zustellungen“Cloudflare Queues wiederholt eine fehlgeschlagene Zustellung bis zu 3-mal und wartet vor jedem Versuch länger. Eine Zustellung schlägt fehl, wenn der Endpunkt keinen 2xx-Status zurückgibt oder ein Verbindungsfehler auftritt. Schlagen der erste Versuch und alle 3 Wiederholungen fehl, verschiebt Jonot die Zustellung in die Dead-Letter-Queue und erhöht den Zähler aufeinanderfolgende Fehlschläge.
Nach 20 aufeinanderfolgenden Fehlschlägen deaktiviert Jonot den Endpunkt automatisch. Sie können ihn auf der Bearbeitungsseite wieder aktivieren. Dadurch wird der Zähler auf null gesetzt.
Zustellungsverlauf
Abschnitt betitelt „Zustellungsverlauf“Der Tab Zustellungen jedes Endpunkts zeigt die Zustellversuche der letzten 30 Tage: Ereignistyp, HTTP-Status, Versuchsanzahl und Zeitstempel. Verwenden Sie die Schaltfläche Mehr laden, um ältere Einträge zu durchblättern.
| Limit | Wert |
|---|---|
| Endpunkte pro Organisation | 5 |
| Benutzerdefinierte Header pro Endpunkt | 10 |
| Länge des Header-Werts | 1.024 Bytes |
| Größe der Payload-Vorlage | 16 KB |
| Zustellungs-Timeout | 10 s |
| Aufbewahrungsdauer des Zustellungsverlaufs | 30 Tage |
| Maximale Zustellrate pro Organisation | 120 / 60 s |
Signaturgeheimnis rotieren
Abschnitt betitelt „Signaturgeheimnis rotieren“- Öffnen Sie die Bearbeitungsseite des Endpunkts.
- Klicken Sie auf Signaturgeheimnis rotieren.
- Bestätigen Sie die Rotation im Dialog.
- Kopieren Sie das neue Geheimnis sofort — es wird nur einmal angezeigt und kann nicht wiederhergestellt werden. Schließen Sie den Dialog, ohne es zu speichern, müssen Sie erneut rotieren, um einen neuen Klartextwert zu erhalten.
- Aktualisieren Sie Ihren Server, damit er Signaturen mit dem neuen Geheimnis überprüft.
Das alte und das neue Geheimnis funktionieren nicht gleichzeitig. Sobald Sie die Rotation bestätigen, ist das alte Geheimnis ungültig. Aktualisieren Sie das empfangende System daher direkt nach der Rotation.
Die Oberfläche zeigt Aktives Geheimnis: ····XXXX (die letzten vier Zeichen) neben der Rotieren-Schaltfläche, damit Sie prüfen können, welches Geheimnis derzeit gültig ist — nützlich, um nach einer Rotation zu bestätigen, dass Ihr Empfänger und der Server synchron sind.
Hygiene des Signaturgeheimnisses
Abschnitt betitelt „Hygiene des Signaturgeheimnisses“Wann rotieren:
- Vermutete Offenlegung: Das Geheimnis erschien in einer Protokolldatei, wurde mit einem ausscheidenden Mitarbeiter geteilt oder in einer Bildschirmaufzeichnung erfasst.
- Regelmäßiger Wechsel: Ein regelmäßiger Wechsel begrenzt, wie lange ein offengelegtes Geheimnis verwendet werden kann.
- Zugriffsänderungen: Wechseln Sie das Geheimnis, nachdem Sie geändert haben, welche Dienste darauf zugreifen können.
So aktualisieren Sie den Empfänger:
- Rotieren Sie in der Admin-Oberfläche und kopieren Sie das neue Geheimnis.
- Aktualisieren Sie das Geheimnis im Secret-Store Ihres Empfängers (Umgebungsvariable, Secrets-Manager usw.).
- Stellen Sie den aktualisierten Empfänger bereit.
- Bestätigen Sie im Tab Zustellungen, dass die nächste Zustellung erfolgreich ist.
Falls Sie das neue Geheimnis vor dem Speichern verloren haben:
Rotieren Sie erneut. Jede Rotation erzeugt ein neues zufälliges Geheimnis. Der vorherige Klartext ist nicht wiederherstellbar — serverseitig wird nur eine AEAD-verschlüsselte Form gespeichert.