Signierter Webhook
Der signierte Webhook verbindet Perstat mit Ihren eigenen Gegenstellen: einem Incident-Werkzeug, das generische Alarmquellen annimmt, einer selbst betriebenen Automatisierung oder einem Skript. Chat-Ziele, PagerDuty und Opsgenie haben eigene, darauf zugeschnittene Connectoren.
Einen Endpunkt anlegen
Abschnitt betitelt „Einen Endpunkt anlegen“Legen Sie in der App unter Integrationen einen Connector der Art Webhook an und geben Sie ihm eine URL (Owner und Admin). Perstat erzeugt ein Signatur-Secret und zeigt es genau einmal. Danach erscheint es maskiert, und Sie können es jederzeit rotieren. Die Rotation ersetzt das Secret sofort, und das alte prüft ab diesem Moment nicht mehr. Aktualisieren Sie Ihre Gegenstelle also im selben Schritt.
Mit webhooks:write legt die REST-API Webhooks an, ändert, testet und löscht sie und
rotiert ihre Secrets. So verwalten auch Ihre Provisionierungsskripte die Webhooks.
Das Secret hat die Form whsec_ gefolgt von 64 hexadezimalen Kleinbuchstaben und Ziffern.
Behandeln Sie die ganze Zeichenkette als undurchsichtigen Schlüssel.
http://-URLs werden für lokale Gegenstellen angenommen. Für alles, was ein fremdes Netz
durchquert, verwenden Sie https://. Das Ziel muss öffentlich erreichbar sein: Ein Host, der auf
eine private, Loopback- oder Link-local-Adresse auflöst, wird bei jedem Versand abgewiesen.
Wann eine Zustellung ausgeht
Abschnitt betitelt „Wann eine Zustellung ausgeht“Was ein Endpunkt erhält, hängt davon ab, ob Ihre Organisation eine aktive Eskalationskette hat: einen Tarif mit Bereitschaftsplan (ab Sentinel, siehe Tarife und Limits), eine eingeschaltete Bereitschaft und eine aktivierte Kette.
Ohne aktive Kette (in jedem anderen Tarif, oder wenn Bereitschaft oder Kette ausgeschaltet sind) erhält jeder aktive Endpunkt die Ereignisse, die er unter Integrationen abonniert hat:
| Ereignis | Wann |
|---|---|
incident.opened |
Ein Incident geht auf, kritisch oder eingeschränkt. Ein von einer Abhängigkeitsregel zurückgehaltener Alarm wird zugestellt, sobald er freigegeben ist. |
incident.resolved |
Der Incident wird geschlossen. |
incident.test |
Sie drücken Test am Connector. Synchron zugestellt, nur an diesen Endpunkt. |
Mit aktiver Kette steuert die Kette die ausgehenden Incident-Meldungen. Ein Endpunkt erhält Meldungen zu kritischen Incidents, und zwar von den Stufen, die ihn als Ziel nennen, bei Minute 0 oder später:
| Ereignis | Wann |
|---|---|
incident.escalation |
Eine Stufe, die den Endpunkt nennt, löst aus. Das ist auch die erste Meldung bei einer Stufe zu Minute 0: Das Ereignis sagt “dieser Incident ist unquittiert”, nicht “ein neuer ist gerade aufgegangen”. |
incident.resolved |
Der Incident wird geschlossen. Die Entwarnung geht an jeden Endpunkt, den eine Stufe alarmiert hat, abonniert oder nicht, und an jeden aktiven Endpunkt, der sie abonniert hat. Was die Kette öffnet, schließt die Kette. |
incident.test |
Wie oben. |
Mit aktiver Kette bleibt das Abonnement von incident.opened ohne Wirkung. Eine Stufe
überspringt einen stillgelegten Endpunkt, und sie überspringt alle Endpunkte, solange der
Incident quittiert ist, solange sein Monitor deaktiviert oder archiviert ist und solange der
Monitor in einem Wartungsfenster liegt. Ein während des Incidents stillgelegter Endpunkt erhält
die Entwarnung für einen Incident, über den er alarmiert wurde, trotzdem.
Die Anfrage
Abschnitt betitelt „Die Anfrage“Ein POST je Ereignis, mit JSON-Body:
POST <Ihre URL>content-type: application/jsonuser-agent: perstat-webhook/1.0x-perstat-signature: sha256=<64 Hex-Zeichen, Kleinschreibung>{ "event": "incident.escalation", "incident": { "id": "inc_9f3c2a7e1b4d48c0a6e5f1d2c3b4a596", "severity": "critical", "cause": "HTTP 503", "summary": "API antwortet nicht", "monitor": { "id": "mon_4b1e8d2c7a9f4e6b8c0d1e2f3a4b5c6d", "name": "API" }, "started_at_unix": 1757930400, "resolved_at_unix": null }, "organization": { "id": "org_2d7a9c4e1f3b4a5c8d6e7f8a9b0c1d2e", "name": "Acme" }}| Feld | Bedeutung |
|---|---|
event |
Eines der Ereignisse oben. |
incident.id |
Über alle Ereignisse eines Incidents stabil. Öffnen und schließen Sie damit denselben Fall auf Ihrer Seite. PagerDuty erhält den Wert als dedup_key, Opsgenie als alias. |
incident.severity |
critical oder degraded. Über eine aktive Kette erhalten Sie critical. Der Test sendet ebenfalls critical. |
incident.cause |
Freitext: das Detail des ersten fehlgeschlagenen Checks oder die bei einem manuellen Incident eingetragene Ursache. test bei einer Testzustellung. |
incident.summary |
Optional, null, wenn leer. |
incident.monitor |
id und name des verknüpften Monitors. null bei einem manuellen Incident ohne Monitor und beim Test. |
incident.started_at_unix |
Unix-Sekunden. |
incident.resolved_at_unix |
Unix-Sekunden, null, bis der Incident geschlossen ist. |
organization |
id und name der Organisation, der der Endpunkt gehört. |
Der Body ist stabil und wächst additiv: Lesen Sie, was Sie brauchen, und ignorieren Sie Felder, die Sie nicht kennen.
Die Signatur prüfen
Abschnitt betitelt „Die Signatur prüfen“Der Header trägt sha256= gefolgt vom HMAC-SHA256 über den rohen Anfrage-Body, mit dem
Secret als Schlüssel, genau so, wie es Ihnen angezeigt wurde: Seine ASCII-Bytes sind der
Schlüssel, es wird nicht dekodiert. Berechnen Sie den MAC über die empfangenen Bytes, vor jedem
JSON-Parsen, und vergleichen Sie in konstanter Zeit.
Node:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(secret, rawBody, header) { const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex"); return expected.length === header.length && timingSafeEqual(Buffer.from(expected), Buffer.from(header));}Python:
import hashlibimport hmac
def verify(secret: str, raw_body: bytes, header: str) -> bool: expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, header)Ein Body, der die Prüfung nicht besteht, kam nicht von Perstat oder wurde unterwegs verändert.
Antworten Sie mit 401 und tun Sie sonst nichts.
Die Signatur deckt allein den Body ab, ohne Zeitstempel und ohne Zustellungs-ID, eine
mitgeschnittene Anfrage besteht die Prüfung also auch beim erneuten Einspielen. Stellen Sie über
TLS zu und behandeln Sie ein wiederholtes Paar (incident.id, event) als bereits erledigt: Für
ein Incident-Werkzeug ist ein zweimal geschlossener Alarm harmlos, ein zweimal geöffneter ist
Lärm.
Zustellregeln
Abschnitt betitelt „Zustellregeln“- Eine
2xx-Antwort gilt als zugestellt. Jeder andere Status, auch ein3xx, gilt als fehlgeschlagen, und Weiterleitungen werden nicht verfolgt. - Der Timeout beträgt 10 Sekunden je Zustellung. Antworten Sie schnell und erledigen Sie die Arbeit danach.
- Perstat stellt jedes Ereignis einmal zu.
- Das Ergebnis der letzten Zustellung, mit Fehlertext, falls es einen gab, steht am Connector unter Integrationen und neben der Stufe in der Kette.
Halten Sie die Gegenstelle erreichbar, und gleichen Sie verpasste Ereignisse über die
REST-API ab: Lesen Sie einen Incident über seine incident.id, oder listen Sie mit
incidents:read die offenen Incidents der Organisation auf.
Nächste Schritte
Abschnitt betitelt „Nächste Schritte“- Alarmierung und Rufbereitschaft: den Endpunkt in eine Eskalationskette setzen.
- API: Webhooks verwalten und Incidents mit einem API-Schlüssel lesen.