Webhooks
Mit Webhooks können Ihre Systeme Echtzeit-HTTP-POST-Benachrichtigungen empfangen, wenn Warteschlangenereignisse eintreten — ein Ticket tritt bei, wird aufgerufen, abgeschlossen und so weiter.
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.
Speichern Sie Ihr Signaturgeheimnis — es wird nur einmal angezeigt. Um zu prüfen, ob Ihr Endpunkt erreichbar ist, verwenden Sie die Schaltfläche Testanfrage senden auf der Bearbeitungsseite des Endpunkts.
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“Fehlgeschlagene Zustellungen (kein 2xx oder Verbindungsfehler) werden von Cloudflare Queues mit exponentiellem Backoff bis zu 3-mal erneut versucht. Nach 3 Fehlschlägen landet die Zustellung in der Dead-Letter-Queue, und der Zähler aufeinanderfolgende Fehlschläge des Endpunkts erhöht sich.
Sobald ein Endpunkt 20 aufeinanderfolgende Fehlschläge ansammelt, wird er automatisch deaktiviert. Aktivieren Sie ihn über die Bearbeitungsseite des Endpunkts erneut; der Zähler wird auf null zurückgesetzt.
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.
Es gibt kein Überlappungsfenster. Das alte Geheimnis verliert seine Gültigkeit, sobald Sie die Rotation bestätigen. Planen Sie, das neue Geheimnis unmittelbar nach der Rotation auf Ihrem Empfänger bereitzustellen.
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:
- Vermuteter Kompromittierung: Das Geheimnis erschien in einer Protokolldatei, wurde mit einem ausscheidenden Mitarbeiter geteilt oder in einer Bildschirmaufzeichnung erfasst.
- Routinehygiene: regelmäßiges Rotieren begrenzt den Schaden einer unentdeckten Offenlegung.
- Nach jeder Änderung daran, welche Dienste das Geheimnis lesen können (Rotation der Schlüsselverwaltung).
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.