Webhooks & Ereignisse
Signierte HTTP-Callbacks für Analyseergebnisse und weitere Ereignisse: Ereigniskatalog, Nutzlast, HMAC-SHA256-Signaturen, Wiederholungen, Protokoll.
Inhalt geprüft am 26. September 2026
Endpunkt registrieren
Organisationsinhaber und Security-Admins registrieren Endpunkte unter Einstellungen → Workspace & API → Webhooks (Feld Endpunkt-URL). Ein API-Schlüssel mit dem Scope webhooks:manage kann Endpunkte ebenfalls über die API verwalten.
- Die URL muss
httpoderhttpsverwenden; Produktivinstallationen akzeptieren nurhttps. - Das Ziel muss öffentlich erreichbar sein. Adressen in privaten oder Loopback-Netzen werden abgewiesen, sofern der Betreiber private Netze für selbst betriebene Empfänger nicht freigegeben hat.
- Ein ohne Ereignisliste registrierter Endpunkt erhält
analysis.completed,analysis.failedundfinding.critical. Über die API können Sieeventsmit bis zu 50 Ereignistypen übergeben oder*für alle Ereignisse.
Jeder Endpunkt hat ein eigenes Signatur-Secret (whsec_…), das verschlüsselt gespeichert wird. Die API gibt es genau einmal zurück, in der Antwort auf POST /api/v1/webhooks. Das Registrierungsformular in den Einstellungen zeigt es nicht an: Um in der Web-App ein Secret zu erhalten, öffnen Sie Integrationen → Webhooks und wählen Secret rotieren — das neue Secret wird einmal angezeigt.
Ereigniskatalog
GET /api/v1/webhooks/events liefert den Katalog; Integrationen → Webhooks zeigt ihn ebenfalls an.
analysis.completed— eine Analyse ist mit dem StatusCOMPLETEDoderPARTIALabgeschlossen.analysis.failed— eine Analyse ist fehlgeschlagen oder konnte nicht ausgeführt werden.analysis.cancelled— eine Analyse wurde abgebrochen; die Befunde des Laufs wurden verworfen.finding.critical— eine Analyse hat Befunde mitBLOCKERoderCRITICALerzeugt.finding.status_changed— der Prüfstatus eines Befunds hat sich geändert (etwa verifiziert, Risiko akzeptiert, Fehlalarm, behoben).finding.assigned— ein Befund wurde einem Mitglied zugewiesen.connector.unhealthy— ein Konnektor gilt nach wiederholten Fehlern als gestört.traceability.task_dispatched— aus einem Befund wurde ein Arbeitspaket in einem externen System angelegt.change_set.created,change_set.simulated,change_set.approved— ein Change Set wurde angelegt, seine What-if-Simulation ist abgeschlossen oder es wurde freigegeben.agent.proposal_verdict,agent.proposal_approved,agent.proposal_executed— das Agent Gate hat über einen Agentenvorschlag entschieden, eine Person hat ihn freigegeben oder er wurde ausgeführt.test.failed— ein Regressionstestlauf im Test Lab ist fehlgeschlagen oder mit einem Fehler beendet worden.release_watch.changed— eine Release-Beobachtung hat Änderungen in einem neuen Wissens-Snapshot erkannt.organization.plan_changed— der Tarif der Organisation hat sich geändert.webhook.auto_disabled— ein Webhook-Endpunkt wurde nach zu vielen aufeinanderfolgenden Zustellfehlern deaktiviert.usage.threshold_reached— ein Tarifzähler hat 80 % oder 100 % seines Limits erreicht.
Der Katalog enthält jeden Ereignistyp, den die Plattform erzeugt; GET /api/v1/webhooks/events nennt zu jedem die Felder von data. Ein Endpunkt, der * abonniert, erhält alle. Die früheren Namen finding.reviewed und organization.plan_upgraded werden weiterhin angenommen und liefern finding.status_changed bzw. organization.plan_changed.
Nutzlast und Header
Jede Zustellung ist ein HTTP-POST mit einem JSON-Body im immer gleichen Umschlag:
{
"id": "0b6f4c1e-…",
"event": "analysis.completed",
"organizationId": "7d1a…",
"timestamp": "2026-09-26T08:15:30.000Z",
"data": {
"analysisId": "…",
"projectId": "…",
"status": "COMPLETED",
"totalFindings": 12
}
}id ist die Ereignis-ID; data enthält die Fakten des Ereignisses. Bei analysis.completed und analysis.failed sind das analysisId, projectId, triggeredBy, engineTypes, targetRelease, status, totalFindings und engineOutcomes, bei einem fehlgeschlagenen Lauf zusätzlich reason. finding.critical enthält analysisId, projectId, triggeredBy, blockerCount, criticalCount und engines. Das Zustellprotokoll zeigt die genaue Nutzlast jeder Zustellung.
Header jeder Zustellung:
Content-Type: application/jsonundUser-Agent: ERPPreflight-Webhooks/1.0X-ERPPreflight-Event-Id— die Ereignis-ID, identisch bei Wiederholungen und erneutem Senden; nutzen Sie sie zur DeduplizierungX-ERPPreflight-Delivery-IdundX-Delivery-ID— die ID dieser ZustellungX-Event-Type— der EreignistypX-ERPPreflight-Signature—t=<unix seconds>,v1=<hex>X-Hub-Signature-256—sha256=<hex>(GitHub-kompatibel)
Signatur prüfen
Beide Signaturen sind HMAC-SHA256 mit dem Signatur-Secret des Endpunkts als Schlüssel — der vollständigen Zeichenkette einschließlich des Präfixes whsec_:
X-Hub-Signature-256signiert den unveränderten Request-Body.X-ERPPreflight-Signaturesigniert<t>.<raw body>, wobeitder Unix-Zeitstempel aus demselben Header ist. Bevorzugen Sie diese Signatur: Mit dem Zeitstempel können Sie erneut eingespielte Anfragen abweisen.
Prüfen Sie gegen den Body genau so, wie er empfangen wurde, und zwar vor dem Parsen des JSON. Vergleichen Sie in konstanter Zeit und weisen Sie Zeitstempel ab, die mehr als 5 Minuten (300 Sekunden) von Ihrer Uhr abweichen. Beispiel für Node.js:
const crypto = require('node:crypto');
// secret: whsec_…, rawBody: Request-Body wie empfangen (UTF-8-String),
// header: Wert von X-ERPPreflight-Signature
function verifyErpPreflightSignature(secret, rawBody, header, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')));
const t = Number(parts.t);
if (!Number.isFinite(t) || !parts.v1) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSec) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(expected, 'hex');
const b = Buffer.from(parts.v1, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Antworten Sie mit einem 2xx-Status, sobald das Ereignis angenommen ist, verarbeiten Sie es asynchron und deduplizieren Sie anhand von X-ERPPreflight-Event-Id.
Wiederholungen, Zustellprotokoll und erneutes Senden
Eine Zustellung ist erfolgreich, wenn Ihr Endpunkt innerhalb von 10 Sekunden mit einem 2xx-Status antwortet. Andernfalls wird sie wiederholt — insgesamt bis zu 6 Versuche: der erste sofort, dann nach etwa 30 Sekunden, 2 Minuten, 10 Minuten, 30 Minuten und 2 Stunden. Nach dem sechsten Fehlversuch wird die Zustellung als DEAD markiert. Jedes Ereignis wird je Endpunkt höchstens einmal eingereiht.
- Zustellprotokoll: Integrationen → Webhooks → Zustellprotokoll anzeigen listet jede Zustellung mit Ereignis, Status (
PENDING,SUCCEEDED,FAILED,DEAD), Versuchen, letztem HTTP-Status, Fehler, Dauer und nächstem Versuch. - Erneut senden: Erneut senden stellt die Nutzlast einer früheren Zustellung als neue, frisch signierte Zustellung mit derselben Ereignis-ID zu.
- Testereignis: Testereignis senden in den Einstellungen verschickt einmalig ein signiertes
ping-Ereignis; es wird protokolliert, aber nie wiederholt. - Automatisches Deaktivieren: Nach 15 aufeinanderfolgenden Fehlversuchen (Betreibereinstellung) wird der Endpunkt deaktiviert; die Person, die ihn registriert hat, und die Organisationsinhaber werden benachrichtigt. Ein deaktivierter Endpunkt erhält keine neuen Ereignisse; ausstehende Wiederholungen laufen weiter, sobald Sie ihn unter Integrationen → Webhooks mit Aktivieren wieder einschalten. Testereignisse zählen nicht zu diesem Limit.
Verwaltungs-API
Alle Routen erfordern einen Organisationsinhaber oder Security-Admin oder einen API-Schlüssel mit webhooks:manage:
GET /api/v1/webhooks/events Ereigniskatalog
POST /api/v1/webhooks {"url", "events"}; liefert das Secret einmal
GET /api/v1/webhooks Endpunkte mit Status und Zustellzahlen
PATCH /api/v1/webhooks/{id} {"status": "ACTIVE"} oder {"status": "DISABLED"}
DELETE /api/v1/webhooks/{id} Endpunkt löschen
POST /api/v1/webhooks/{id}/test signierten Ping senden
POST /api/v1/webhooks/{id}/rotate-secret neues Secret, einmal zurückgegeben
GET /api/v1/webhooks/{id}/deliveries?limit=50 Zustellprotokoll (höchstens 200, neueste zuerst)
GET /api/v1/webhooks/{id}/deliveries/{deliveryId}/payload Nutzlast einer Zustellung
POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay Zustellung erneut sendenDas Registrieren und Löschen von Endpunkten wird im Audit-Log protokolliert.