Webhooki wychodzące
Dzięki webhookowi wychodzącemu exoCortex wysyła żądanie POST do Państwa systemu za każdym razem, gdy wystąpi zasubskrybowane zdarzenie: utworzenie zgłoszenia, zmiana stanu, zbliżający się termin SLA. Dzięki temu system reaguje natychmiast, bez cyklicznego odpytywania API.
Tworzenie subskrypcji
Dział zatytułowany „Tworzenie subskrypcji”- W exoCortex Core należy otworzyć Integrations → Webhooks. Wymagana jest rola administracyjna.
- Należy podać URL, który będzie odbierać zdarzenia. Musi zaczynać się od
https://. - Należy wybrać zdarzenia.
*oznacza wszystkie zdarzenia. - Należy wybrać format:
json: standardowy format exoCortex, opisany na tej stronie;datadog,pagerduty,slack-block: natywny format tych usług, do stosowania, gdy URL należy do nich.
- Jeśli wymaga tego Państwa brama, należy dodać stałe nagłówki, na przykład nagłówek uwierzytelniający.
- Zapisać. Jeśli nie podano sekretu podpisu, exoCortex generuje go (
whsec_…) i wyświetla tylko raz: należy go zapisać, ponieważ jest potrzebny do weryfikacji podpisów.
Działanie testowe wysyła do subskrypcji zdarzenie webhook.test, co pozwala sprawdzić, czy Państwa system je odbiera.
Zdarzenia
Dział zatytułowany „Zdarzenia”| Zdarzenie | Kiedy jest wysyłane |
|---|---|
ticket.created |
Utworzono zgłoszenie |
ticket.comment_added |
Dodano komentarz |
ticket.field_changed |
Zmieniło się pole |
ticket.assignee_changed |
Zmieniła się osoba przypisana |
ticket.status_changed |
Zmienił się stan |
ticket.priority_changed |
Zmienił się priorytet |
ticket.sla_warning |
Zbliża się termin SLA |
ticket.sla_breach |
Termin SLA upłynął |
ticket.resolved |
Zgłoszenie zostało rozwiązane |
ticket.closed |
Zgłoszenie zostało zamknięte |
ticket.reopened |
Zgłoszenie zostało ponownie otwarte |
ticket.link_created |
Utworzono powiązanie między zgłoszeniami |
ticket.link_deleted |
Usunięto powiązanie między zgłoszeniami |
routing.no_match |
Żadna reguła routingu nie znalazła kolejki dla zgłoszenia |
routing.manual_routed |
Operator ręcznie skierował zgłoszenie |
webhook.test |
Wysłano zdarzenie testowe do subskrypcji |
Oprócz nich można subskrybować według nazwy zdarzenia z reguł powiadomień Państwa tenanta, na przykład approval_requested.
exoCortex może dodawać nowe typy zdarzeń: Państwa system musi ignorować te, których nie zna.
Format zdarzenia
Dział zatytułowany „Format zdarzenia”Każde zdarzenie w formacie json ma tę samą strukturę:
{ "id": "evt_8a1f4c2e9b7d4e3f8a6b5c4d3e2f1a00", "type": "ticket.status_changed", "created_at": "2026-11-01T09:31:47.120Z", "api_version": "1", "tenant_id": "ACME", "data": { "ticket": { "key": "ACME-1042", "summary": "Payment gateway returns HTTP 502", "status": "In Progress", "priority": "High", "issuetype": "IT-INC", "assignee": "jane.doe", "created": "2026-11-01T09:14:05.000Z", "updated": "2026-11-01T09:31:47.000Z" }, "actor": "jane.doe", "changes": { "from": "Open", "to": "In Progress" } }}ididentyfikuje zdarzenie i jest taki sam dla wszystkich subskrypcji, które je otrzymują.actorto użytkownik, który spowodował zdarzenie, lubsystem.changeszawiera szczegóły zdarzenia: na przykład poprzedni i nowy stan albo treść komentarza.
Do 30 czerwca 2027 treść zawiera również wycofywane pola event, timestamp i source oraz kopię pól z data na pierwszym poziomie. Nowy system powinien odczytywać wyłącznie pola opisane powyżej.
Nagłówki
Dział zatytułowany „Nagłówki”| Nagłówek | Przykład | Znaczenie |
|---|---|---|
X-Exo-Timestamp |
1793491200 |
Moment złożenia podpisu w sekundach Unix |
X-Exo-Signature |
v1=5257a869… |
Podpis zdarzenia |
X-Exo-Event |
ticket.created |
Typ zdarzenia, taki sam jak type |
X-Exo-Delivery |
dlv_0b9d… |
Unikalny identyfikator próby doręczenia |
Weryfikacja podpisu
Dział zatytułowany „Weryfikacja podpisu”Przed zaufaniem zdarzeniu należy zweryfikować podpis:
- Należy odczytać treść dokładnie w takiej postaci, w jakiej dotarła, bez parsowania i ponownego zapisywania JSON: zmieniłyby się bajty.
- Należy odrzucić żądanie, jeśli brakuje
X-Exo-Timestamplub różni się on o ponad 300 sekund od Państwa zegara. W ten sposób blokuje się powtórzone żądania. Zegar należy synchronizować przez NTP. - Należy obliczyć HMAC-SHA256 z
timestamp + "." + bodyza pomocą sekretu subskrypcji, w zapisie szesnastkowym małymi literami. - Należy porównać wynik, w stałym czasie, z każdą wartością
v1=z nagłówkaX-Exo-Signature. Podczas rotacji sekretu nagłówek może zawierać więcej niż jedną wartość, rozdzielonych przecinkami.
Przykład w Node.js:
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyExoWebhook(rawBody, headers, secret, toleranceSec = 300) { const ts = headers['x-exo-timestamp']; const sigHeader = headers['x-exo-signature'] || ''; if (!ts || Math.abs(Date.now() / 1000 - Number(ts)) > toleranceSec) return false; const expected = Buffer.from(createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex')); return sigHeader .split(',') .map((s) => s.trim()) .filter((s) => s.startsWith('v1=')) .some((s) => { const got = Buffer.from(s.slice(3)); return got.length === expected.length && timingSafeEqual(got, expected); });}Przykład w Pythonie:
import hashlib, hmac, time
def verify_exo_webhook(raw_body: bytes, headers, secret: str, tolerance_sec: int = 300) -> bool: ts = headers.get('X-Exo-Timestamp') if not ts or abs(time.time() - int(ts)) > tolerance_sec: return False expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest() sigs = [s.strip()[3:] for s in headers.get('X-Exo-Signature', '').split(',') if s.strip().startswith('v1=')] return any(hmac.compare_digest(s, expected) for s in sigs)Nagłówek X-NH-Signature, który podpisuje wyłącznie treść bez znacznika czasu, jest wycofywany i zostanie usunięty 30 czerwca 2027.
Odpowiadanie i obsługa duplikatów
Dział zatytułowany „Odpowiadanie i obsługa duplikatów”- Należy odpowiedzieć dowolnym kodem
2xxw ciągu 5 sekund. Jeśli trzeba wykonać długotrwałą pracę, należy umieścić ją w kolejce i odpowiedzieć od razu. - Doręczenie jest gwarantowane co najmniej raz: to samo zdarzenie może dotrzeć więcej niż jeden raz. Do rozpoznawania duplikatów należy używać
idlubX-Exo-Delivery, na przykład przechowując identyfikatory odebrane w ciągu ostatnich 5 minut. - Zdarzenia mogą docierać w innej kolejności niż ta, w której wystąpiły: należy je porządkować według
created_at.