Ausgehende Webhooks
Mit einem ausgehenden Webhook sendet exoCortex jedes Mal eine POST-Anfrage an Ihr System, wenn ein Ereignis eintritt, das Sie abonniert haben: ein erstelltes Ticket, eine Statusänderung, ein bald ablaufendes SLA. So reagiert Ihr System sofort, ohne die API in Intervallen abzufragen.
Ein Abonnement erstellen
Abschnitt betitelt „Ein Abonnement erstellen“- Öffnen Sie in exoCortex Core Integrations → Webhooks. Sie benötigen eine administrative Rolle.
- Geben Sie die URL an, die die Ereignisse empfangen soll. Sie muss mit
https://beginnen. - Wählen Sie die Ereignisse.
*bedeutet alle Ereignisse. - Wählen Sie das Format:
json: das Standardformat von exoCortex, das auf dieser Seite beschrieben ist;datadog,pagerduty,slack-block: das native Format dieser Services, zu verwenden, wenn die URL zu ihnen gehört.
- Wenn Ihr Gateway es verlangt, fügen Sie feste Header hinzu, zum Beispiel einen Authentifizierungs-Header.
- Speichern Sie. Wenn Sie kein Signatur-Secret angegeben haben, erzeugt exoCortex eines (
whsec_…) und zeigt es nur einmal an: Speichern Sie es, Sie brauchen es zur Prüfung der Signaturen.
Mit der Testaktion senden Sie das Ereignis webhook.test an das Abonnement und prüfen, ob Ihr System es empfängt.
Ereignisse
Abschnitt betitelt „Ereignisse“| Ereignis | Wann es eintrifft |
|---|---|
ticket.created |
Ein Ticket wurde erstellt |
ticket.comment_added |
Ein Kommentar wurde hinzugefügt |
ticket.field_changed |
Ein Feld hat sich geändert |
ticket.assignee_changed |
Der Bearbeiter hat sich geändert |
ticket.status_changed |
Der Status hat sich geändert |
ticket.priority_changed |
Die Priorität hat sich geändert |
ticket.sla_warning |
Ein SLA läuft bald ab |
ticket.sla_breach |
Ein SLA ist abgelaufen |
ticket.resolved |
Das Ticket wurde gelöst |
ticket.closed |
Das Ticket wurde geschlossen |
ticket.reopened |
Das Ticket wurde wieder geöffnet |
ticket.link_created |
Eine Verknüpfung zwischen Tickets wurde erstellt |
ticket.link_deleted |
Eine Verknüpfung zwischen Tickets wurde entfernt |
routing.no_match |
Keine Routing-Regel hat eine Warteschlange für das Ticket gefunden |
routing.manual_routed |
Ein Bearbeiter hat das Ticket manuell weitergeleitet |
webhook.test |
Sie haben ein Testereignis an das Abonnement gesendet |
Darüber hinaus können Sie die Ereignisse der Benachrichtigungsregeln Ihres Tenants namentlich abonnieren, zum Beispiel approval_requested.
exoCortex kann neue Ereignistypen hinzufügen: Ihr System muss unbekannte Typen ignorieren.
Format des Ereignisses
Abschnitt betitelt „Format des Ereignisses“Jedes Ereignis im Format json hat dieselbe 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" } }}ididentifiziert das Ereignis und ist für alle Abonnements, die es empfangen, gleich.actorist der Benutzer, der das Ereignis ausgelöst hat, odersystem.changesenthält die Details des Ereignisses: zum Beispiel vorherigen und neuen Status oder den Text des Kommentars.
Bis zum 30. Juni 2027 enthält der Body auch die veralteten Felder event, timestamp und source sowie eine Kopie der Felder aus data auf oberster Ebene. Ein neues System sollte nur die oben beschriebenen Felder lesen.
| Header | Beispiel | Bedeutung |
|---|---|---|
X-Exo-Timestamp |
1793491200 |
Zeitpunkt der Signatur, in Unix-Sekunden |
X-Exo-Signature |
v1=5257a869… |
Signatur des Ereignisses |
X-Exo-Event |
ticket.created |
Ereignistyp, identisch mit type |
X-Exo-Delivery |
dlv_0b9d… |
Eindeutige Kennung des Zustellversuchs |
Die Signatur prüfen
Abschnitt betitelt „Die Signatur prüfen“Bevor Sie einem Ereignis vertrauen, prüfen Sie die Signatur:
- Lesen Sie den Body so, wie er angekommen ist, ohne das JSON zu parsen und neu zu schreiben: Sonst ändern sich die Bytes.
- Verwerfen Sie die Anfrage, wenn
X-Exo-Timestampfehlt oder um mehr als 300 Sekunden von Ihrer Uhr abweicht. So blockieren Sie wiederholte Anfragen. Halten Sie Ihre Uhr per NTP synchron. - Berechnen Sie den HMAC-SHA256 von
timestamp + "." + bodymit dem Secret des Abonnements, in hexadezimalen Kleinbuchstaben. - Vergleichen Sie das Ergebnis in konstanter Zeit mit jedem
v1=-Wert ausX-Exo-Signature. Während der Rotation des Secrets kann der Header mehrere Werte enthalten, durch Kommas getrennt.
Beispiel in 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); });}Beispiel in Python:
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)Der Header X-NH-Signature, der nur den Body ohne Zeitstempel signiert, ist veraltet und wird am 30. Juni 2027 entfernt.
Antworten und Duplikate behandeln
Abschnitt betitelt „Antworten und Duplikate behandeln“- Antworten Sie innerhalb von 5 Sekunden mit einem beliebigen
2xx-Code. Wenn Sie eine längere Verarbeitung durchführen müssen, stellen Sie sie in eine Warteschlange und antworten Sie sofort. - Die Zustellung erfolgt mindestens einmal: Dasselbe Ereignis kann mehrfach eintreffen. Verwenden Sie
idoderX-Exo-Delivery, um Duplikate zu erkennen, zum Beispiel indem Sie die in den letzten 5 Minuten gesehenen Kennungen speichern. - Ereignisse können in einer anderen Reihenfolge eintreffen, als sie aufgetreten sind: Sortieren Sie sie nach
created_at.