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

# Webhooks

> استقبل أحداث المكالمات على الـ endpoint الخاصّ بك، وتحقّق من توقيعاتها.

تُخطِر الـ webhooks خادمك عند وقوع أحداث المكالمات. تسجّل endpoint، وتُرسِل إليه Wave عبر POST بيانات JSON موقّعة، وتُعيد المحاولة عند الفشل.

## تسجيل endpoint

تُدار الـ webhook endpoints في لوحة تحكّم Wave ضمن Webhooks: أضِف URL، واختر الأحداث، وانسخ الـ signing secret (يُعرَض مرّة واحدة).

## الأحداث

يمكنك الاشتراك في أيّ حدث أدناه (بحدّ أقصى 5 endpoints لكلّ مشروع). اليوم، يُصدَر `call.initiated` فقط — أمّا البقيّة فمقبولة في قائمة السماح للاشتراك لكنّها لن تُطلَق حتّى يصل تدفّق الأحداث اللحظيّ.

| الحدث                                                                                              | يُصدَر اليوم                |
| -------------------------------------------------------------------------------------------------- | --------------------------- |
| `call.initiated`                                                                                   | ✅ نعم                       |
| `call.answered` · `call.ended` · `call.missed` · `call.timeout` · `call.cancelled` · `call.failed` | قريبًا                      |
| `call.transferred` · `call.held` · `call.resumed`                                                  | مع الـ Calling SDK (لاحقًا) |

## الحمولة (Payload)

كلّ عمليّة تسليم هي جسم JSON يحتوي على نوع الـ `event` وكائن `data`. ويحمل الـ `X-Wave-Event-Id` header معرّفًا فريدًا لضمان عدم التكرار (idempotency).

```json theme={null}
{
  "event": "call.initiated",
  "data": {
    "call_id": "call_abc123",
    "status": "initiated",
    "direction": "outbound",
    "from": "+96651XXXXXXX",
    "customer_number_masked": "+96650••••17",
    "queue_id": null,
    "vitalpbx_channel_id": "…",
    "started_at": "2026-06-17T10:00:00.000Z",
    "metadata": {}
  }
}
```

## التحقّق من التوقيع

كلّ عمليّة تسليم موقّعة. الـ `X-Wave-Signature` header هو `sha256=<hex>` — وهو HMAC-SHA256 لجسم الطلب الخام باستخدام الـ signing secret الخاصّ بالـ endpoint لديك (`whsec_…`). تحقّق منه عبر مقارنة بزمن ثابت (constant-time) قبل الوثوق بالحمولة:

```javascript theme={null}
import crypto from "node:crypto";

function verifyWaveSignature(rawBody, header, secret) {
  if (!header?.startsWith("sha256=")) return false;
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
```

<Warning>
  احسب الـ HMAC على بايتات الجسم الخام، قبل أيّ تحليل/إعادة تسلسل لـ JSON — فإعادة التحويل إلى نصّ قد تُغيّر البايتات وتُفسِد التحقّق.
</Warning>

## إعادة المحاولات والـ dead-letter

لكلّ محاولة مهلة قدرها 10 ثوانٍ. تُعاد عمليّات التسليم الفاشلة حتّى 5 محاولات وفق سلّم تراجع (backoff)، ثمّ تُحوَّل إلى dead-letter:

| المحاولة | الإرسال      |
| -------- | ------------ |
| 1        | فورًا        |
| 2        | بعد 30 ثانية |
| 3        | بعد 5 دقائق  |
| 4        | بعد 30 دقيقة |
| 5        | بعد ساعتين   |

تُحوَّل عمليّات التسليم المُستنفَدة إلى dead-letter (تُحفَظ 72 ساعة) وتظهر — مع إجراء replay — في سجلّات التسليم بلوحة التحكّم.
