> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Alert-Webhooks: Team-Alerts an Ihren Endpoint

> Didit sendet Team-Alerts an Ihren HTTPS-Endpoint: Prüfungen, AML-Hits, Abrechnung und Status. HMAC-SHA256-signiert, Wiederholungen über 24 Stunden.



Alert-Webhook-Prompt
        Prompt in die Zwischenablage kopieren



      
      

\<pre>

\`Add an endpoint that receives Didit alert webhooks (team alerts, not verification results).

\## What to build
A public HTTPS POST endpoint (e.g. /api/didit/alerts) that:
1\. Reads the raw request body as bytes (do NOT parse and re-serialize the JSON before verifying)
2\. Checks that X-Timestamp is within 300 seconds of now
3\. Recomputes X-Signature-V2 = hex(HMAC-SHA256(secret, X-Timestamp + "." + rawBody)), where secret is the FULL signing secret including its "whsec_" prefix
4\. Compares the two signatures in constant time
5\. Parses the JSON, ignores an alert_id it already handled, answers 2xx within 5 seconds, then processes the alert asynchronously
6\. Answers a failed check with 400, not 401 (401, 403, 404 and 410 mark the destination for reconnection)

\## Headers
\- Content-Type: application/json
\- User-Agent: Didit-Alerts/1.0
\- X-Timestamp: Unix seconds, new on every attempt
\- X-Signature-V2: hex HMAC-SHA256 described above
This is NOT the signature scheme of verification webhooks. Alert webhooks send no X-Signature and no X-Signature-Simple.

\## Body (compact JSON, keys sorted)
\{
"alert_id": "alt_<16 hex characters>",  // the same on every retry: deduplicate on it
"created_at": 1791884460,                // Unix seconds when Didit created the alert
"data": { "event": "session_in_review", "label": "Session", "value": "#1042" },
"organization": { "id": "<uuid>", "name": "<your organization>" },
"severity": "info" | "warning" | "critical",
"subtitle": "<English explanation, can be empty>",
"title": "<English headline>",
"url": "<link to the Didit console>",
"webhook_type": "alert.<type>"
}

\## webhook_type values
\- alert.verification.in_review, alert.business_verification.in_review
\- alert.transaction.held, alert.aml.monitoring_hit
\- alert.billing.low_balance, alert.billing.autorefill_failed (data.paused), alert.billing.backup_card_charged
\- alert.webhook.delivery_failing
\- alert.service.degraded (data.status "degraded" or "down"), alert.service.recovered (data.status "recovered")
\- alert.test (sent from the console's Send test button)
Ignore webhook_type values and data keys you do not recognize.

\## Retries
\- 2xx = delivered. Redirects are not followed.
\- Timeout (5 s), connection failure, 5xx, 408, 425 or 429 = retried 5 times, after 1 min, 5 min, 30 min, 3 h and 20 h 24 min (about 24 h).
\- Any other response is final.
\- Test alerts are never retried.

\## Secret rotation
Rotating the secret in the console replaces it at once. There is no overlap and no header signed with the previous secret: deploy the new secret immediately.

Docs: /integration/alert-webhooks`

\</pre>



      
      

Einfügen in

Alert-Webhooks senden die Alerts Ihres Teams an einen HTTPS-Endpoint, den Sie betreiben.
Nutzen Sie sie, um ein Bereitschaftstool, eine Ticket-Warteschlange oder Ihr eigenes Operations-Dashboard zu speisen.Alert-Webhooks sind von [Verifizierungs-Webhooks](https://docs.didit.me/de/integration/webhooks.md) getrennt.
Verifizierungs-Webhooks senden Sitzungs-, Entitäts- und Transaktionsergebnisse an Ihre Anwendung.
Alert-Webhooks benachrichtigen Ihr Team, wenn etwas Aufmerksamkeit erfordert: eine Verifizierung, die auf eine manuelle Prüfung wartet, eine fehlgeschlagene Zahlung oder ein Dienstvorfall.
Sie haben ihre eigene Payload, ihr eigenes Signaturgeheimnis, ihre eigene Signatur und einen eigenen Wiederholungszeitplan.## Ziel einrichtenSie konfigurieren Alert-Webhooks in der Business Console, nicht über die API.
Mitglieder, die die Organisationseinstellungen verwalten können, können Ziele hinzufügen, ändern und testen.**1. Ziel hinzufügen**Fügen Sie unter **Organisationseinstellungen** > **Team-Benachrichtigungen** ein **Alert-Webhook**-Ziel mit der URL Ihres Endpoints hinzu.
Die URL muss `https://` verwenden und zu einer öffentlichen Adresse auflösen.**2. Signaturgeheimnis speichern**Didit zeigt das vollständige Signaturgeheimnis, das mit `whsec_` beginnt, nur einmal an.
Speichern Sie es jetzt: Danach zeigt die Konsole nur noch die letzten vier Zeichen an.**3. Alerts an das Ziel weiterleiten**Das Hinzufügen eines Ziels sendet noch nichts an dieses.
Fügen Sie das Ziel den Routing-Regeln der Alerts hinzu, die es empfangen soll.**4. Test senden**Klicken Sie auf **Test senden**, um einen `alert.test`-Alert zu senden, und prüfen Sie, ob Ihr Endpoint diesen akzeptiert.Eine Organisation kann bis zu 25 Ziele in **Team-Benachrichtigungen** haben.Nur Live-Aktivitäten erreichen ein Ziel.
Alerts zu Sandbox-Verifizierungen, Unternehmensverifizierungen, Transaktionen und AML-Treffern werden niemals an dieses gesendet.## Alert-Typen| `webhook_type` | `severity` | Wann Didit ihn sendet |
| - | - | - |
| `alert.verification.in_review` | `warning` | Eine Verifizierung wurde abgeschlossen und für eine manuelle Prüfung markiert. |
| `alert.business_verification.in_review` | `warning` | Eine Unternehmensverifizierung erfordert eine manuelle Prüfung. |
| `alert.transaction.held` | `warning` | Ihre Regeln zur Transaktionsüberwachung haben eine Transaktion zur Prüfung markiert. |
| `alert.aml.monitoring_hit` | `warning` | Die laufende AML-Überwachung hat einen neuen Treffer gefunden. |
| `alert.billing.low_balance` | `warning` | Das Guthaben Ihrer Organisation ist unter den von Ihnen festgelegten Schwellenwert gefallen. |
| `alert.billing.autorefill_failed` | `critical` | Eine automatische Aufladung Ihres Guthabens ist fehlgeschlagen, da die Karte abgelehnt wurde. |
| `alert.billing.backup_card_charged` | `warning` | Eine automatische Belastung wurde bei einer Karte abgelehnt und mit einer Backup-Karte bezahlt. |
| `alert.webhook.delivery_failing` | `warning` | Zustellungen an einen Ihrer Endpoints für [Verifizierungs-Webhooks](https://docs.didit.me/de/integration/webhooks.md) schlagen fehl. |
| `alert.service.degraded` | `critical` | Ein Dienst, den Ihre Organisation nutzt, ist beeinträchtigt oder ausgefallen. |
| `alert.service.recovered` | `info` | Dieser Dienst funktioniert wieder normal. |
| `alert.test` | `info` | Jemand hat für das Ziel auf **Test senden** geklickt. |## PayloadJeder Alert ist ein `POST`-Aufruf mit einem JSON-Body.
Didit sendet den Body als kompaktes JSON mit sortierten Schlüsseln.
Dieses Beispiel ist zur besseren Lesbarkeit formatiert:```json theme={null}
{
  "alert_id": "alt_9f2c4e1a7b3d5c80",
  "created_at": 1791884460,
  "data": {
    "event": "session_in_review",
    "label": "Session",
    "value": "#1042"
  },
  "organization": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "name": "Example Org"
  },
  "severity": "warning",
  "subtitle": "A KYC or KYB verification was completed and flagged for manual review.",
  "title": "Verification in review",
  "url": "https://business.didit.me/console/3fa85f64-5717-4562-b3fc-2c963f66afa6/9b2d1c4e-8f3a-4e6b-a1d2-5c7e9f0b3a14/verifications?session-id=1b4e28ba-2fa1-41d2-883f-0016d3cca427",
  "webhook_type": "alert.verification.in_review"
}
```| Feld | Typ | Beschreibung |
| - | - | - |
| `webhook_type` | string | `alert.` gefolgt vom Alert-Typ. Siehe [Alert-Typen](#alert-typen). |
| `alert_id` | string | `alt_` gefolgt von 16 Hexadezimalzeichen. Jeder Wiederholungsversuch eines Alerts enthält dieselbe `alert_id`; verwenden Sie diese, um Duplikate zu ignorieren. |
| `created_at` | integer | Zeitpunkt in Unix-Sekunden, zu dem Didit den Alert erstellt hat. Bleibt bei Wiederholungsversuchen unverändert. |
| `severity` | string | `info`, `warning` oder `critical`. |
| `organization` | object | Die `id` (UUID) und der `name` Ihrer Organisation. |
| `title` | string | Kurze englische Überschrift. |
| `subtitle` | string | Englische Erklärung. Kann leer sein. |
| `data` | object | Worauf sich der Alert bezieht. Siehe unten. |
| `url` | string | Link zur entsprechenden Seite in der Didit-Konsole. |`data` enthält immer:- `event`: der Ereignisschlüssel, zum Beispiel `session_in_review`.
- `label` und `value`: worauf sich der Alert bezieht, zum Beispiel `Session` und `#1042`.Einige Alert-Typen fügen `data` weitere Schlüssel hinzu:- `alert.billing.autorefill_failed` fügt `paused` hinzu, einen booleschen Wert, der `true` ist, wenn die automatische Aufladung jetzt pausiert wurde, bis Sie die Karte aktualisieren.
- `alert.service.degraded` und `alert.service.recovered` fügen `service`, `status`, `incident_id`, `service_name`, `state`, `affected`, `country_name`, `started_at`, `resolved_at`, `duration_minutes`, `title` und `body` hinzu.
  `status` ist bei `alert.service.degraded` entweder `degraded` oder `down` und bei `alert.service.recovered` entsprechend `recovered`.
  `service` verwendet die Dienstschlüssel aus [`GET /v3/status/`](https://docs.didit.me/de/api-reference/service-status), und `incident_id` der `id` eines Vorfalls dort entspricht.Alerts enthalten niemals personenbezogene Daten von Endbenutzern oder Dokumentdaten.
Sie identifizieren eine Sitzung, eine Transaktion oder ein anderes Element anhand seiner Nummer und verlinken darauf in der Konsole.
Ignorieren Sie unbekannte `webhook_type`-Werte und `data`-Schlüssel, damit neue Werte Ihren Endpoint nicht beeinträchtigen.## Anfrage-Header| Header | Beispiel | Bedeutung |
| - | - | - |
| `Content-Type` | `application/json` | Der Body ist JSON. |
| `User-Agent` | `Didit-Alerts/1.0` | Identifiziert Didits Alert-Sender. |
| `X-Timestamp` | `1791884462` | Zeitpunkt in Unix-Sekunden, zu dem Didit diesen Versuch signiert hat. Neu bei jedem Versuch. |
| `X-Signature-V2` | 64 Hexadezimalzeichen | HMAC-SHA256-Signatur dieses Versuchs. |## Signatur prüfen`X-Signature-V2` ist der hex-codierte HMAC-SHA256 des Strings `<X-Timestamp>.<raw body>`, berechnet mit dem Signiergeheimnis Ihres Ziels als Schlüssel.* Verwenden Sie das vollständige Geheimnis genau so, wie Didit es angezeigt hat, einschließlich des Präfixes `whsec_`.
* Signieren Sie die rohen Anfrage-Bytes genau so, wie Sie sie empfangen haben. Das Parsen und erneute Serialisieren des JSON kann die Bytes verändern und die Überprüfung fehlschlagen lassen.
* Vergleichen Sie die Signaturen in konstanter Zeit.
* Weisen Sie Anfragen ab, deren `X-Timestamp` um mehr als 5 Minuten von Ihrer Systemzeit abweicht. Didit signiert jeden Versuch, einschließlich jedes Wiederholungsversuchs, mit einem neuen Zeitstempel, sodass dieses Zeitfenster niemals einen echten Wiederholungsversuch abweist.
* Beantworten Sie eine fehlgeschlagene Prüfung mit `400`. Eine Antwort mit `401`, `403`, `404` oder `410` markiert das Ziel für eine erneute Verbindung (siehe [Wiederholungsversuche](#wiederholungsversuche)).> [!WARNING]
>
> Alert-Webhooks werden nicht wie Verifizierungs-Webhooks signiert.
> Der Header heißt zwar ebenfalls `X-Signature-V2`, aber der signierte String ist ein anderer, und Alert-Webhooks senden weder `X-Signature` noch `X-Signature-Simple`.
> Verwenden Sie Ihren Verifizierer für Verifizierungs-Webhooks nicht wieder.### Node.js (Express)```javascript theme={null}
const express = require("express");
const crypto = require("crypto");

const app = express();
// The full secret Didit showed when you added the destination, including "whsec_".
const ALERT_SECRET = process.env.DIDIT_ALERT_SECRET;
const TOLERANCE_SECONDS = 300;

// express.raw keeps the body as the exact bytes Didit sent.
app.post("/api/didit/alerts", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.get("X-Timestamp") || "";
  const signature = Buffer.from(req.get("X-Signature-V2") || "", "utf8");

  const now = Math.floor(Date.now() / 1000);
  if (!/^\d+$/.test(timestamp) || Math.abs(now - Number(timestamp)) > TOLERANCE_SECONDS) {
    return res.status(400).send("Stale or missing timestamp");
  }

  const expected = Buffer.from(
    crypto.createHmac("sha256", ALERT_SECRET).update(`${timestamp}.`).update(req.body).digest("hex"),
    "utf8",
  );
  if (signature.length !== expected.length || !crypto.timingSafeEqual(signature, expected)) {
    return res.status(400).send("Invalid signature");
  }

  const alert = JSON.parse(req.body.toString("utf8"));
  res.sendStatus(204); // answer within 5 seconds, then process
  handleAlert(alert); // skip an alert_id you already handled
});
```### Python (Flask)```python theme={null}
import hashlib
import hmac
import json
import os
import time

from flask import Flask, request

app = Flask(__name__)
# The full secret Didit showed when you added the destination, including "whsec_".
ALERT_SECRET = os.environ["DIDIT_ALERT_SECRET"].encode("utf-8")
TOLERANCE_SECONDS = 300


@app.post("/api/didit/alerts")
def didit_alert():
    raw_body = request.get_data()  # the exact bytes Didit sent
    timestamp = request.headers.get("X-Timestamp", "")
    signature = request.headers.get("X-Signature-V2", "")

    try:
        too_old = abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS
    except ValueError:
        too_old = True
    if too_old:
        return "Stale or missing timestamp", 400

    expected = hmac.new(ALERT_SECRET, timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected.encode(), signature.encode()):
        return "Invalid signature", 400

    alert = json.loads(raw_body)
    handle_alert(alert)  # skip an alert_id you already handled; keep this fast
    return "", 204
```### Signiergeheimnis rotierenSie rotieren das Geheimnis auf dem Ziel unter **Team-Benachrichtigungen**.
Didit zeigt das neue Geheimnis einmalig an und signiert jeden späteren Versuch damit, einschließlich Wiederholungsversuchen von Alerts, die vor der Rotation erstellt wurden.
Das alte Geheimnis verliert sofort seine Gültigkeit.
Es gibt keinen Übergangszeitraum, und kein Header enthält eine mit dem vorherigen Geheimnis erstellte Signatur.
Deployen Sie das neue Geheimnis auf Ihrem Endpoint, sobald Sie es rotiert haben.## WiederholungsversucheDidit behandelt jede `2xx`-Antwort als zugestellt.
Jeder Versuch wartet bis zu 5 Sekunden auf Ihre Antwort und folgt keinen Weiterleitungen.Didit wiederholt einen Alert nach einem Timeout, einem Verbindungsfehler, einer `5xx`-Antwort oder einer `408`-, `425`- bzw. `429`-Antwort.
Die Wiederholung erfolgt bis zu 5-mal über einen Zeitraum von etwa 24 Stunden:| Wiederholungsversuch | Verzögerung nach dem vorherigen Versuch |
| - | - |
| 1. | 1 Minute |
| 2. | 5 Minuten |
| 3. | 30 Minuten |
| 4. | 3 Stunden |
| 5. | 20 Stunden 24 Minuten |Jede andere Antwort ist endgültig, einschließlich `3xx` und aller anderen `4xx`.
Ein über **Test senden** versendeter Test wird nur einmal gesendet und niemals wiederholt.Eine Antwort mit `401`, `403`, `404` oder `410` markiert das Ziel außerdem für eine erneute Verbindung: Die Konsole zeigt es mit dem Status **Erneut verbinden** an.
Dasselbe gilt für eine URL, die beim Senden durch Didit zu einer privaten oder anderweitig blockierten Adresse aufgelöst wird.
Didit sendet weiterhin neue Alerts an das Ziel, und es wird nach der nächsten erfolgreichen Zustellung oder bei einer Aktualisierung seiner URL wieder aktiv.Unter **Letzte Benachrichtigungen** in **Team-Benachrichtigungen** wird jede Zustellung mit ihrem Ergebnis aufgeführt, und Sie können eine fehlgeschlagene Zustellung von dort aus wiederholen.## Verwandte Themen- [Verifizierungs-Webhooks](https://docs.didit.me/de/integration/webhooks.md): Sitzungs-, Entitäts- und Transaktionsergebnisse für Ihre Anwendung.
- [Dienststatus](https://docs.didit.me/de/api-reference/service-status.md): Der öffentliche Feed hinter `alert.service.degraded` und `alert.service.recovered`.
- [Manuelle Prüfung](https://docs.didit.me/de/console/manual-review.md): Vorgehensweise bei einer Verifizierung in Prüfung.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.