Webhooks

Webhooks senden Echtzeit-Ereignisse in Ihre eigenen Systeme, wenn Scans abgeschlossen sind oder sich der Verstoß-Status ändert. Jede Payload ist signiert, damit Ihr Empfänger verifizieren kann, dass sie von AllyProof stammt.

Unterstützte Ereignisse

EreignisAusgelöst, wenn
scan.completedEin Scan-Job in den Status completed wechselt – manuell, geplant oder per API ausgelöst. Die Payload enthält die Website, den Score, die Schweregrad-Aufschlüsselung und Scan-Metadaten.
violation.newEin Verstoß erstmalig auf einer Website erkannt wird (keine vorherige offene oder behobene Zeile für dieselbe Regel). Löst einmal pro Verstoß-Lebenszeit aus – ein erneuter Scan, der einen bereits bekannten Verstoß wieder erkennt, löst NICHT erneut aus. Nützlich für Ticketing-Integrationen, die eine Zeile pro Defekt wünschen. Die Payload enthält violation_id, site_id, site_url, rule_id, impact und first_detected_at.
violation.resolvedEin zuvor offener Verstoß in behoben übergeht. Die Payload enthält resolution_source mit einem von drei Werten: "scanner" (von einem frischen Scan nicht mehr erkannt), "manual" (ein Nutzer hat ihn im Dashboard oder über die REST-API als behoben markiert) oder "jira" (das verknüpfte Jira-Ticket ist in die Kategorie Erledigt gewechselt). Die Übergangsprüfung verhindert doppeltes Auslösen, wenn ein erneutes Update ein No-op ist.
violation.regressedEin zuvor behobener Verstoß im letzten Scan wieder aufgetaucht ist. Löst einmal pro regressiertem Problem pro Scan aus. Die Payload enthält das vorherige resolved_at, damit Ihre Integration "Fix zurückgesetzt"-Zeitlinien markieren kann.

Einrichtung

  1. Öffnen Sie Einstellungen → Benachrichtigungen (Admin- oder Owner-Rolle).
  2. Geben Sie Ihre Webhook-URL ein – den HTTPS-Endpunkt, der Ereignisse empfangen soll. AllyProof lehnt reines HTTP und jede URL ab, die zu einer privaten IP-Range auflöst.
  3. Geben Sie ein Webhook-Geheimnis ein – eine beliebige zufällige Zeichenkette ausreichender Länge. Dies ist der Schlüssel, mit dem jede ausgehende Payload signiert wird. AllyProof generiert es nicht automatisch; ist das Feld leer, wird die Webhook-Zustellung vollständig übersprungen (die Plattform verweigert das Senden unsignierter Payloads).
  4. Speichern.

Jede Organisation hat eine Webhook-URL und ein Geheimnis. Müssen Sie an mehrere Ziele verteilen, richten Sie Ihre URL auf einen schlanken Verteiler-Worker auf Ihrer Seite.

Payload-Format

Alle Ereignisse senden per POST einen JSON-Body mit derselben Struktur auf oberster Ebene:

{
  "event": "scan.completed",
  "timestamp": "2026-04-24T09:12:34.567Z",
  "data": {
    "site_id": "…",
    "site_url": "https://example.com",
    "scan_id": "…",
    "score": 87,
    "summary": {
      "critical": 0,
      "serious": 2,
      "moderate": 5,
      "minor": 10,
      "pages_scanned": 25
    }
  }
}

Das data-Objekt variiert je nach Ereignistyp. Behandeln Sie unbekannte Felder als abwärtskompatible Erweiterungen, nicht als Breaking Changes – neue Felder können ohne Versionssprung auftauchen.

Signaturverifikation

Jede Anfrage enthält den Header X-AllyProof-Signature: den HMAC-SHA256 des rohen Anfrage-Bodys, geschlüsselt mit Ihrem Webhook-Geheimnis, hex-codiert. Verifizieren Sie die Signatur immer, bevor Sie auf die Payload reagieren – behandeln Sie eine nicht verifizierbare Anfrage genau so, als wäre sie nie angekommen.

import crypto from "node:crypto";

function verify(req) {
  const signature = req.headers["x-allyproof-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.ALLYPROOF_WEBHOOK_SECRET)
    .update(req.rawBody, "utf8")
    .digest("hex");

  // Zeitkonstanter Vergleich schützt vor Timing-Angriffen.
  const ok =
    signature.length === expected.length &&
    crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expected)
    );

  if (!ok) throw new Error("invalid signature");
}

Zustellgarantien

  • Best-Effort. AllyProof löst die HTTP-Anfrage einmal aus. Eine Nicht-2xx-Antwort wird protokolliert, aber nicht automatisch wiederholt – ist Ihr Empfänger nicht erreichbar, verlassen Sie sich darauf, die kanonischen Daten über die API erneut zu lesen, sobald er wieder erreichbar ist.
  • Nicht blockierend. Ein langsamer oder nicht erreichbarer Webhook blockiert nie die Scan-Verarbeitung und beeinflusst nie die kundenseitige Oberfläche. Die Zustellung läuft, nachdem der Scan-Datensatz gespeichert wurde.
  • Nur signiert. Ist das Geheimnis nicht gesetzt, wird die Zustellung verweigert. Die Plattform sendet niemals unsignierte Payloads.

Sicherheit

  • Webhook-URLs werden gegen private IP-Ranges validiert, um SSRF zu verhindern; interne Ziele (10/8, 172.16/12, 192.168/16, Loopback) werden beim Speichern abgelehnt.
  • Das Geheimnis wird serverseitig gespeichert und nach dem Setzen nie über die API zurückgegeben. Rotieren Sie es, indem Sie es in den Einstellungen ersetzen – sowohl alte als auch neue Empfänger benötigen dann den neuen Wert.

Typische Anwendungsfälle

  • Scan-Ergebnisse über ein Webhook-Relay in einen Slack-Kanal posten.
  • Jira- oder Linear-Tickets bei violation.new öffnen.
  • Ein internes Compliance-Dashboard bei scan.completed aktualisieren.
  • Einen Behebungs-Workflow in Ihrem PM-Tool auslösen.
  • On-Call alarmieren, wenn ein Verstoß mit kritischem Schweregrad auftaucht (kombiniert mit den Schweregrad-Daten von "Scan abgeschlossen").