Přeskočit na obsah

Webhooky

Když ve frontě nastane událost, odešle Jonot do vašeho systému požadavek HTTP POST. Událostí je například zařazení lístku do fronty, jeho zavolání nebo dokončení.

  1. Otevřete admin.jonot.io/settings/integrations.
  2. Klikněte na Přidat koncový bod.
  3. Zadejte veřejnou URL adresu HTTPS, na které váš server naslouchá.
  4. Zvolte, k jakým událostem se chcete přihlásit.
  5. Klikněte na Uložit.

Jakmile se podpisový tajný klíč zobrazí, zkopírujte si ho a uložte. Jonot ho ukáže jen jednou. Chcete-li ověřit, že Jonot na váš koncový bod dosáhne, použijte tlačítko Odeslat testovací požadavek na stránce úpravy koncového bodu.

Název událostiKdy jej Jonot odešle
ticket.joinedZákazník se připojí k frontě
ticket.calledČlen personálu zavolá lístek na přepážku
ticket.completedLístek je označen jako dokončený
ticket.cancelledZákazník nebo člen personálu zruší lístek
ticket.skippedLístek je přeskočen (odklad s možností znovu vyvolat)
ticket.no_showZavolaný nebo přeskočený lístek je potvrzen jako nedostavení
queue.status_changedZmění se stav fronty (ACTIVE, PAUSED nebo CLOSED)

Každé doručení je HTTP POST s:

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

Výchozí tělo je objekt JSON. Obsah pole payload závisí na události:

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 podepisuje každé doručení pomocí HMAC-SHA256 nad řetězcem:

<deliveryId>.<timestamp>.<body>

Ověření v 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);
}

Výchozí tělo JSON můžete nahradit vlastní šablonou. Šablony používají zjednodušenou syntaxi Mustache:

  • {{ path.to.value }} — Jonot hodnotu dosadí a escapuje podle typu obsahu: pro application/json jako řetězec JSON, pro application/x-www-form-urlencoded procentním kódováním, pro text/plain bez escapování.
  • {{{ path.to.value }}} — Jonot hodnotu dosadí bez escapování.

Příklad šablony pro application/json (přihlášeno k ticket.joined):

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

Pole šablony payloadu je plnohodnotný editor kódu s:

  • Zvýrazněním syntaxe a párováním závorek pro šablony JSON.
  • Seznamem proměnných — řádkem tlačítek s cestami proměnných, které jsou pro vaše vybrané události dostupné. Kliknutím na tlačítko vložíte token {{ path }} na pozici kurzoru.
  • Živou validací — během psaní editor kontroluje cesty proměnných. Pokud je typ obsahu application/json a šablona neobsahuje surové značky {{{ }}}, kontroluje i strukturu JSON. Problémy vyznačí přímo v kódu a vypíše je pod ním:
    • Chyba — cesta, která je neznámá ve všech vašich vybraných událostech.
    • Varování — cesta, která existuje pouze pro některé z vašich vybraných událostí (u doručení ostatních událostí bude prázdná).

Při uložení použije server stejná pravidla validace.

Po neúspěšném prvním pokusu Cloudflare Queues doručení zopakuje až třikrát. Prodleva před každým dalším pokusem se prodlužuje. Doručení selže, když koncový bod vrátí stav mimo rozsah 2xx nebo nastane chyba připojení. Pokud selžou všechny čtyři pokusy, doručení skončí ve frontě nedoručitelných zpráv a zvýší se čítač po sobě jdoucích selhání koncového bodu.

Po 20 po sobě jdoucích selháních Jonot koncový bod automaticky vypne. Znovu jej zapnete na stránce úpravy koncového bodu; tím se čítač vynuluje.

Karta Doručení u každého koncového bodu zobrazuje pokusy o doručení za posledních 30 dní: typ události, stav HTTP, počet pokusů a časové razítko. Tlačítkem Načíst další zobrazíte starší záznamy z tohoto období.

LimitHodnota
Koncové body na organizaci5
Vlastní hlavičky na koncový bod10
Délka hodnoty hlavičky1 024 bajtů
Velikost šablony payloadu16 KB
Časový limit doručení10 s
Uchování historie doručení30 dní
Max. rychlost doručení na organizaci120 / 60 s

Rotace podpisového tajného klíče

Sekce “Rotace podpisového tajného klíče”
  1. Otevřete stránku úpravy koncového bodu.
  2. Klikněte na Otočit podpisový tajný klíč.
  3. Potvrďte rotaci v dialogovém okně.
  4. Ihned zkopírujte nový tajný klíč. Jonot jej zobrazí jen jednou a nedokáže jej obnovit. Pokud dialog zavřete, aniž byste si klíč uložili, získáte nový až další rotací.
  5. Aktualizujte svůj server tak, aby ověřoval podpisy novým tajným klíčem.

Starý a nový tajný klíč nikdy neplatí současně. Starý klíč přestane ověřovat požadavky, jakmile rotaci potvrdíte. Systém, který vaše webhooky přijímá, aktualizujte ihned po rotaci.

Vedle tlačítka Otočit rozhraní zobrazuje Aktivní tajný klíč: ····XXXX. Podle posledních čtyř znaků poznáte, který klíč je po rotaci aktivní.

Hygiena podpisového tajného klíče

Sekce “Hygiena podpisového tajného klíče”

Kdy rotovat:

  • Podezření na únik: tajný klíč se objevil v log souboru, byl sdílen s odcházejícím členem personálu nebo byl zachycen v nahrávce obrazovky.
  • Pravidelná rotace: pravidelná výměna klíče omezuje, jak dlouho lze uniklý klíč zneužít.
  • Změna přístupů: klíč vyměňte poté, co se změní, které služby jej mohou číst.

Jak aktualizovat přijímač:

  1. Otočte klíč v uživatelském rozhraní administrace a zkopírujte nový tajný klíč.
  2. Aktualizujte tajný klíč, který přijímající systém používá. Uložte jej do proměnné prostředí, správce tajných klíčů nebo jiného bezpečného úložiště.
  3. Nasaďte aktualizovaný přijímající systém.
  4. Potvrďte, že další doručení proběhne úspěšně na kartě Doručení.

Pokud jste ztratili nový tajný klíč před jeho uložením:

Otočte klíč znovu. Každá rotace vygeneruje nový náhodný tajný klíč. Předchozí čitelnou hodnotu Jonot obnovit nedokáže, protože server uchovává jen její zašifrovanou podobu.