Signierter Webhook
Der signierte Webhook ist der Connector für eigene Gegenstellen: ein Incident-Werkzeug, das generische Alarmquellen annimmt, eine selbst betriebene Automatisierung oder ein Skript. Chat-Ziele, PagerDuty und Opsgenie haben eigene Connectoren; diese Seite behandelt nur die generische Art. Alles hier beschreibt, was heute ausgeliefert ist.
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 (nur Owner und Admin). Perstat erzeugt ein Signatur-Secret und zeigt es genau einmal; danach erscheint es nur maskiert und lässt sich nur noch rotieren. Die Rotation ersetzt das Secret sofort. Es gibt keine Übergangszeit, in der beide gelten.
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 erfährt von einem Ausfall nur, wenn eine Stufe ihn als Ziel nennt, bei Minute 0 oder später, und nur bei kritischen Incidents:
| 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 sehen Sie nur 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 behoben ist. |
organization |
id und name der Organisation, der der Endpunkt gehört. |
Der Body ist stabil und wird nur additiv erweitert: 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 trägt keinen Zeitstempel und keine Zustellungs-ID. Eine mitgeschnittene
Anfrage lässt sich deshalb wieder einspielen und besteht die Prüfung erneut. 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. Alles andere, auch ein3xx, gilt als fehlgeschlagen; Weiterleitungen werden nicht verfolgt. - Der Timeout beträgt 10 Sekunden je Zustellung. Antworten Sie schnell und erledigen Sie die Arbeit danach.
- Ein Versuch je Ereignis. Es gibt keine Wiederholungsschlange; eine fehlgeschlagene Zustellung bleibt fehlgeschlagen.
- Das Ergebnis der letzten Zustellung, mit Fehlertext, falls es einen gab, steht am Connector unter Integrationen und neben der Stufe in der Kette.
Weil es keine Wiederholung gibt, verpasst eine kurz nicht erreichbare Gegenstelle dieses
Ereignis. Wer das vollständige Bild statt der letzten Meldung braucht, liest den Incident
über die API anhand von incident.id.