> ## 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.

# Webhooks d'alertes: alertes d'equip al teu endpoint

> Rep alertes de Didit al teu endpoint HTTPS: revisions, monitoratge AML, facturació i estat. Signades amb HMAC-SHA256 i reintentades durant 24 hores.



Indicació del webhook d'alertes
        Copia el prompt al porta-retalls



      
      

\<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>



      
      

Enganxa a

Els webhooks d'alertes envien les alertes del vostre equip a un endpoint HTTPS que vosaltres controleu.
Feu-los servir per alimentar una eina de guàrdia, una cua de tiquets o el vostre propi tauler d'operacions.Els webhooks d'alertes són independents dels [webhooks de verificació](https://docs.didit.me/ca/integration/webhooks.md).
Els webhooks de verificació envien els resultats de sessions, entitats i transaccions a la vostra aplicació.
Els webhooks d'alertes avisen el vostre equip que alguna cosa necessita atenció: una verificació pendent de revisió, un pagament fallit o un incident de servei.
Tenen el seu propi payload, secret de signatura, signatura i calendari de reintents.## Configura una destinació del webhookConfigureu els webhooks d'alertes a la Business Console, no mitjançant l'API.
Els membres que poden gestionar la configuració de l'organització poden afegir, modificar i provar les destinacions.**1. Afegiu la destinació**A **Configuració de l’organització** > **Notificacions de l’equip**, afegeix una destinació de tipus **Webhook d'alertes** amb la URL del vostre endpoint.
La URL ha de fer servir `https://` i resoldre a una adreça pública.**2. Desa el secret de signatura**Didit mostra el secret de signatura complet, que comença per `whsec_`, només una vegada.
Deseu-lo ara: després, la consola només mostra els darrers quatre caràcters.**3. Envieu-hi les alertes**Afegir una destinació no envia res encara.
Afegiu la destinació a les regles d'enrutament de les alertes que vulgueu que rebi.**4. Envieu una prova**Feu clic a **Envia una prova** per enviar una alerta `alert.test` i comproveu que el vostre endpoint l'accepta.Una organització pot tenir fins a 25 destinacions a **Notificacions de l’equip**.Només l'activitat en entorn de producció arriba a una destinació.
Les alertes sobre verificacions de sandbox, verificacions d'empreses (KYB), transaccions i coincidències AML mai no s'hi envien.## Tipus d'alertes| `webhook_type` | `severity` | Quan l'envia Didit |
| - | - | - |
| `alert.verification.in_review` | `warning` | S'ha completat una verificació i s'ha marcat per a revisió manual. |
| `alert.business_verification.in_review` | `warning` | Una Verificació d'empreses (KYB) necessita revisió manual. |
| `alert.transaction.held` | `warning` | Les vostres regles de monitoratge de transaccions han marcat una transacció per revisar. |
| `alert.aml.monitoring_hit` | `warning` | El monitoratge AML continu ha trobat una coincidència nova. |
| `alert.billing.low_balance` | `warning` | El saldo de la vostra organització ha baixat del llindar que heu definit. |
| `alert.billing.autorefill_failed` | `critical` | Una recàrrega automàtica del vostre saldo ha fallat perquè la targeta ha estat rebutjada. |
| `alert.billing.backup_card_charged` | `warning` | S'ha rebutjat un cobrament automàtic en una targeta i s'ha pagat amb una targeta de reserva. |
| `alert.webhook.delivery_failing` | `warning` | Els lliuraments a un dels vostres endpoints de [webhook de verificació](https://docs.didit.me/ca/integration/webhooks.md) estan fallant. |
| `alert.service.degraded` | `critical` | Un servei que fa servir la vostra organització està degradat o fora de servei. |
| `alert.service.recovered` | `info` | Aquest servei ha tornat a la normalitat. |
| `alert.test` | `info` | Algú ha fet clic a **Envia una prova** a la destinació. |## PayloadCada alerta és un `POST` amb un cos JSON.
Didit envia el cos com a JSON compacte amb les claus ordenades.
Aquest exemple està formatat per facilitar la lectura:```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"
}
```| Camp | Tipus | Descripció |
| - | - | - |
| `webhook_type` | string | `alert.` seguit del tipus d'alerta. Vegeu [Tipus d'alertes](#tipus-d’alertes). |
| `alert_id` | string | `alt_` seguit de 16 caràcters hexadecimals. Cada reintent d'una alerta porta el mateix `alert_id`, així que useu-lo per ignorar duplicats. |
| `created_at` | integer | Segons Unix del moment en què Didit va crear l'alerta. Es manté igual en els reintents. |
| `severity` | string | `info`, `warning` o `critical`. |
| `organization` | object | L'`id` (UUID) i el `name` de la vostra organització. |
| `title` | string | Títol curt en anglès. |
| `subtitle` | string | Explicació en anglès. Pot estar buida. |
| `data` | object | Sobre què tracta l'alerta. Vegeu més avall. |
| `url` | string | Enllaç a la pàgina relacionada de la consola de Didit. |`data` sempre conté:- `event`: la clau de l'esdeveniment, per exemple `session_in_review`.
- `label` i `value`: sobre què tracta l'alerta, per exemple `Session` i `#1042`.Alguns tipus d'alerta afegeixen claus a `data`:- `alert.billing.autorefill_failed` afegeix `paused`, un booleà que és `true` quan la recàrrega automàtica queda pausada fins que actualitzeu la targeta.
- `alert.service.degraded` i `alert.service.recovered` afegeixen `service`, `status`, `incident_id`, `service_name`, `state`, `affected`, `country_name`, `started_at`, `resolved_at`, `duration_minutes`, `title` i `body`.
  `status` és `degraded` o `down` a `alert.service.degraded`, i `recovered` a `alert.service.recovered`.
  `service` fa servir les claus de servei de [`GET /v3/status/`](https://docs.didit.me/ca/api-reference/service-status), i `incident_id` coincideix amb un `id` d'incident d'aquell endpoint.Les alertes mai no inclouen dades personals ni de documents de l'usuari final.
Identifiquen una sessió, una transacció o un altre element pel seu número i hi enllacen des de la consola.
Ignoreu els valors de `webhook_type` i les claus de `data` que no reconeixeu, perquè els nous no trenquin el vostre endpoint.## Capçaleres de la sol·licitud| Capçalera | Exemple | Significat |
| - | - | - |
| `Content-Type` | `application/json` | El cos és JSON. |
| `User-Agent` | `Didit-Alerts/1.0` | Identifica l'emissor d'alertes de Didit. |
| `X-Timestamp` | `1791884462` | Segons Unix en què Didit ha signat aquest intent. Nou en cada intent. |
| `X-Signature-V2` | 64 caràcters hexadecimals | Signatura HMAC-SHA256 d'aquest intent. |## Verifica la signatura`X-Signature-V2` és el HMAC-SHA256 en hexadecimal de la cadena `<X-Timestamp>.<raw body>`, amb el secret de signatura de la teva destinació.* Fes servir el secret complet exactament tal com el va mostrar Didit, incloent-hi el prefix `whsec_`.
* Signa els bytes sense processar de la petició tal com els has rebut. Analitzar el JSON i tornar-lo a serialitzar pot canviar els bytes i trencar la verificació.
* Compara les signatures en temps constant.
* Rebutja una petició amb un `X-Timestamp` que difereixi més de 5 minuts del teu rellotge. Didit signa cada intent, inclosos tots els reintents, amb una marca de temps nova, de manera que aquesta finestra mai no rebutja un reintent genuí.
* Respon amb `400` quan la verificació falli. Una resposta `401`, `403`, `404` o `410` marca la destinació perquè es torni a connectar (vegeu [Reintents](#reintents)).> [!WARNING]
>
> Els webhooks d'alertes no es signen igual que els webhooks de verificació.
> La capçalera també es diu `X-Signature-V2`, però la cadena signada és diferent, i els webhooks d'alertes no envien cap `X-Signature` ni `X-Signature-Simple`.
> No reutilitzis el verificador del webhook de verificació.### 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
```### Rota el secret de signaturaRotes el secret de la destinació a **Notificacions de l’equip**.
Didit mostra el secret nou una sola vegada i signa amb ell tots els intents posteriors, inclosos els reintents d'alertes creades abans de la rotació.
El secret antic deixa de funcionar de seguida.
No hi ha cap període de solapament, i cap capçalera no porta una signatura feta amb el secret anterior.
Desplega el secret nou al teu endpoint tan bon punt el rotis.## ReintentsDidit considera lliurada qualsevol resposta `2xx`.
Cada intent espera fins a 5 segons la resposta i no segueix les redireccions.Didit reintenta una alerta després d'un temps d'espera, d'un error de connexió, d'una resposta `5xx`, o d'una resposta `408`, `425` o `429`.
Reintenta fins a 5 vegades, durant unes 24 hores:| Reintent | Retard després de l'intent anterior |
| - | - |
| 1r | 1 minut |
| 2n | 5 minuts |
| 3r | 30 minuts |
| 4t | 3 hores |
| 5è | 20 hores 24 minuts |Qualsevol altra resposta és definitiva, incloses les `3xx` i qualsevol altra `4xx`.
Una prova enviada amb **Envia una prova** té un únic intent i mai no es reintenta.Una resposta `401`, `403`, `404` o `410` també marca la destinació perquè es torni a connectar: la consola la mostra amb l'estat **Tornar a connectar**.
També marca la destinació una URL que, quan Didit hi envia, es resol en una adreça privada o bloquejada.
Didit continua enviant alertes noves a la destinació, i torna a estar activa després del següent lliurament satisfactori o quan actualitzes la seva URL.**Notificacions recents** dins de **Notificacions de l’equip** mostra cada lliurament amb el seu resultat, i des d'allà pots reintentar un lliurament fallit.## Relacionat- [Webhooks de verificació](https://docs.didit.me/ca/integration/webhooks.md): resultats de sessió, entitat i transacció per a la teva aplicació.
- [Estat del servei](https://docs.didit.me/ca/api-reference/service-status.md): la font pública en què es basen `alert.service.degraded` i `alert.service.recovered`.
- [Revisió manual](https://docs.didit.me/ca/console/manual-review.md): què fer amb una verificació en revisió.


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