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

# تنبيهات webhook: إرسال تنبيهات الفريق إلى endpoint الخاص بك

> أرسل تنبيهات فريقك من Didit إلى endpoint HTTPS خاص بك. موقّعة بـ HMAC-SHA256 وتُعاد محاولتها لمدة 24 ساعة.



موجّه webhook التنبيهات
        نسخ الموجّه إلى الحافظة



      
      

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



      
      

الصق في

ترسل webhooks التنبيهات تنبيهات فريقك إلى endpoint من نوع HTTPS تملكه.
استخدمها لتغذية أداة المناوبة، أو طابور التذاكر، أو لوحة العمليات الخاصة بك.webhooks التنبيهات منفصلة عن [webhooks التحقق](https://docs.didit.me/ar/integration/webhooks.md).
ترسل webhooks التحقق نتائج الجلسات والكيانات والمعاملات إلى تطبيقك.
أما webhooks التنبيهات فتُخبر فريقك بأن شيئاً يحتاج إلى اهتمام: تحقق ينتظر المراجعة، أو دفعة فاشلة، أو حادثة في خدمة.
ولكل منها payload خاص، وسر توقيع خاص، وتوقيع خاص، وجدول إعادة محاولة خاص.## إعداد الوجهةتُهيَّأ webhooks التنبيهات في Business Console، وليس من خلال API.
يمكن للأعضاء الذين يملكون صلاحية إدارة إعدادات المؤسسة إضافة الوجهات وتعديلها واختبارها.**1. أضف الوجهة**في **إعدادات المؤسسة** > **إشعارات الفريق**، أضف وجهة **webhook التنبيهات** مع عنوان URL لـ endpoint الخاص بك.
يجب أن يستخدم عنوان URL الصيغة `https://` وأن يُحلّ إلى عنوان عام.**2. احفظ سر التوقيع**يعرض Didit سر التوقيع الكامل، الذي يبدأ بـ `whsec_`، مرة واحدة فقط.
احفظه الآن: بعد ذلك تعرض Business Console آخر أربعة أحرف منه فقط.**3. وجّه التنبيهات إليها**إضافة الوجهة لا ترسل إليها أي شيء بعد.
أضف الوجهة إلى قواعد التوجيه الخاصة بالتنبيهات التي تريد أن تستقبلها.**4. أرسل اختبارًا**انقر **إرسال اختبار** لإرسال تنبيه `alert.test`، وتحقق من أن endpoint الخاص بك يقبله.يمكن أن تحتوي المؤسسة على ما يصل إلى 25 وجهة في **إشعارات الفريق**.لا يصل إلى الوجهة إلا النشاط في بيئة الإنتاج.
لا تُرسَل إليها أبداً التنبيهات المتعلقة بعمليات التحقق في البيئة التجريبية، أو بالتحقق من الشركات (KYB)، أو بالمعاملات، أو بتطابقات AML.## أنواع التنبيهات| `webhook_type` | `severity` | متى يرسله Didit |
| - | - | - |
| `alert.verification.in_review` | `warning` | تم إكمال عملية تحقق ووُضعت عليها علامة للمراجعة اليدوية. |
| `alert.business_verification.in_review` | `warning` | يحتاج التحقق من الشركات إلى مراجعة يدوية. |
| `alert.transaction.held` | `warning` | وسمت قواعد مراقبة المعاملات لديك معاملة للمراجعة. |
| `alert.aml.monitoring_hit` | `warning` | وجدت مراقبة AML المستمرة تطابقاً جديداً. |
| `alert.billing.low_balance` | `warning` | انخفض رصيد مؤسستك عن الحد الذي حددته. |
| `alert.billing.autorefill_failed` | `critical` | فشل الشحن التلقائي للرصيد لأن البطاقة رُفضت. |
| `alert.billing.backup_card_charged` | `warning` | رُفض خصم تلقائي على بطاقة واحدة، وتم الدفع بالبطاقة الاحتياطية. |
| `alert.webhook.delivery_failing` | `warning` | تفشل عمليات التسليم إلى إحدى endpoints الخاصة بـ [webhooks التحقق](https://docs.didit.me/ar/integration/webhooks.md) لديك. |
| `alert.service.degraded` | `critical` | تعاني خدمة تستخدمها مؤسستك من تدهور أو تعطل. |
| `alert.service.recovered` | `info` | عادت تلك الخدمة إلى حالتها الطبيعية. |
| `alert.test` | `info` | نقر أحد ما على **إرسال اختبار** في الوجهة. |## payloadكل تنبيه هو طلب `POST` بجسم JSON.
يرسل Didit الجسم بصيغة JSON مضغوطة، مع ترتيب مفاتيحه أبجدياً.
هذا المثال منسّق للقراءة:```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"
}
```| الحقل | النوع | الوصف |
| - | - | - |
| `webhook_type` | string | `alert.` متبوعة بنوع التنبيه. راجع [أنواع التنبيهات](#أنواع-التنبيهات). |
| `alert_id` | string | `alt_` متبوعة بـ 16 حرفاً سداسياً عشرياً. يحمل كل إعادة محاولة للتنبيه القيمة `alert_id` نفسها، لذا استخدمها لتجاهل التكرارات. |
| `created_at` | integer | ثوانٍ Unix لحظة إنشاء Didit للتنبيه. تبقى القيمة نفسها في إعادات المحاولة. |
| `severity` | string | `info` أو `warning` أو `critical`. |
| `organization` | object | `id` مؤسستك (UUID) و`name` الخاصان بها. |
| `title` | string | عنوان قصير بالإنجليزية. |
| `subtitle` | string | شرح بالإنجليزية. قد يكون فارغاً. |
| `data` | object | موضوع التنبيه. راجع أدناه. |
| `url` | string | رابط الصفحة ذات الصلة في وحدة تحكم Didit. |يحتوي `data` دائماً على:- `event`: مفتاح الحدث، مثلاً `session_in_review`.
- `label` و`value`: موضوع التنبيه، مثلاً `Session` و`#1042`.تضيف بعض أنواع التنبيهات مفاتيح إلى `data`:- `alert.billing.autorefill_failed` يضيف `paused`، وهو قيمة منطقية تكون `true` عندما يكون الشحن التلقائي متوقفاً الآن إلى أن تحدّث البطاقة.
- `alert.service.degraded` و`alert.service.recovered` يضيفان `service` و`status` و`incident_id` و`service_name` و`state` و`affected` و`country_name` و`started_at` و`resolved_at` و`duration_minutes` و`title` و`body`.
  قيمة `status` هي `degraded` أو `down` في `alert.service.degraded`، وهي `recovered` في `alert.service.recovered`.
  يستخدم `service` مفاتيح الخدمات في [`GET /v3/status/`](https://docs.didit.me/ar/api-reference/service-status)، ويطابق `incident_id` قيمة `id` لحادثة هناك.لا تتضمن التنبيهات أبداً بيانات شخصية للمستخدم النهائي أو بيانات المستندات.
وهي تحدد الجلسة أو المعاملة أو أي عنصر آخر برقمه، وترتبط به في وحدة التحكم.
تجاهل قيم `webhook_type` ومفاتيح `data` التي لا تعرفها، حتى لا يتعطل endpoint الخاص بك بالعناصر الجديدة.## رؤوس الطلب| الرأس | المثال | المعنى |
| - | - | - |
| `Content-Type` | `application/json` | الجسم بصيغة JSON. |
| `User-Agent` | `Didit-Alerts/1.0` | يحدد مُرسل التنبيهات من Didit. |
| `X-Timestamp` | `1791884462` | ثوانٍ Unix لحظة توقيع Didit لهذه المحاولة. جديد في كل محاولة. |
| `X-Signature-V2` | 64 حرفاً سداسياً عشرياً | توقيع HMAC-SHA256 لهذه المحاولة. |## التحقق من التوقيع`X-Signature-V2` هو قيمة HMAC-SHA256 المُرمَّزة بالست عشري للسلسلة `<X-Timestamp>.<raw body>`، ويُوقَّع باستخدام سر التوقيع الخاص بوجهة webhook لديك.* استخدم السر الكامل كما عرضه Didit تماماً، بما في ذلك البادئة `whsec_`.
* وقّع بايتات الطلب الخام كما استلمتها. قد يؤدي تحليل JSON ثم إعادة تسلسله إلى تغيير البايتات وفشل التحقق.
* قارن التوقيعات بزمن ثابت.
* ارفض أي طلب يتجاوز الفرق بين `X-Timestamp` وساعتك 5 دقائق. يوقّع Didit كل محاولة، بما فيها كل إعادة محاولة، بطابع زمني جديد، لذلك لا ترفض هذه النافذة أي إعادة محاولة صحيحة أبداً.
* استجب لفشل التحقق بالرمز `400`. الاستجابة `401` أو `403` أو `404` أو `410` تُعلّم الوجهة لإعادة الربط (انظر [إعادة المحاولات](#إعادة-المحاولات)).> [!WARNING]
>
> لا تُوقَّع webhook الخاصة بالتنبيهات بالطريقة نفسها التي تُوقَّع بها webhook الخاصة بالتحقق.
> الرأس يحمل الاسم نفسه `X-Signature-V2`، لكن السلسلة الموقّعة مختلفة، ولا ترسل webhook الخاصة بالتنبيهات أي `X-Signature` أو `X-Signature-Simple`.
> لا تعِد استخدام أداة التحقق من webhook الخاصة بالتحقق لديك.### 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
```### تدوير سر التوقيعتُدوّر السر في الوجهة من خلال **إشعارات الفريق**.
يعرض Didit السر الجديد مرة واحدة، ويوقّع بعد ذلك كل محاولة لاحقة به، بما فيها إعادات محاولة التنبيهات التي أُنشئت قبل التدوير.
يتوقف السر القديم عن العمل فوراً.
لا توجد فترة تداخل، ولا يحمل أي رأس توقيعاً صُنع بالسر السابق.
انشر السر الجديد إلى نقطة النهاية لديك فور تدويره.## إعادة المحاولاتيعامل Didit أي استجابة `2xx` على أنها مُسلَّمة.
تنتظر كل محاولة حتى 5 ثوانٍ لاستجابتك، ولا تتبع عمليات إعادة التوجيه.يعيد Didit محاولة التنبيه بعد انتهاء المهلة، أو فشل الاتصال، أو استجابة `5xx`، أو استجابة `408` أو `425` أو `429`.
يعيد المحاولة حتى 5 مرات، على مدى نحو 24 ساعة:| إعادة المحاولة | التأخير بعد المحاولة السابقة |
| - | - |
| الأولى | دقيقة واحدة |
| الثانية | 5 دقائق |
| الثالثة | 30 دقيقة |
| الرابعة | 3 ساعات |
| الخامسة | 20 ساعة و24 دقيقة |كل استجابة أخرى نهائية، بما في ذلك `3xx` وأي `4xx` أخرى.
الاختبار المُرسل بزر **إرسال اختبار** يحصل على محاولة واحدة فقط ولا تتم إعادة محاولته أبداً.الاستجابات `401` و`403` و`404` و`410` تُعلّم الوجهة أيضاً لإعادة الربط، فتعرضها لوحة التحكم بحالة **إعادة الربط**.
وكذلك الأمر إذا كان عنوان URL يُحلّ إلى عنوان خاص أو محظور بطريقة أخرى عندما يرسل Didit.
يواصل Didit إرسال التنبيهات الجديدة إلى الوجهة، وتعود إلى النشاط بعد التسليم الناجح التالي أو عند تحديث عنوان URL الخاص بها.يعرض **الإشعارات الأخيرة** في **إشعارات الفريق** كل عملية تسليم مع نتيجتها، ويمكنك إعادة محاولة عملية تسليم فاشلة من هناك.## ذات صلة- [webhook الخاصة بالتحقق](https://docs.didit.me/ar/integration/webhooks.md): نتائج الجلسات والكيانات والمعاملات لتطبيقك.
- [حالة الخدمة](https://docs.didit.me/ar/api-reference/service-status.md): الخلاصة العامة التي تغذي `alert.service.degraded` و`alert.service.recovered`.
- [المراجعة اليدوية](https://docs.didit.me/ar/console/manual-review.md): ما يجب فعله مع عملية تحقق قيد المراجعة.


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