# رسائل واتساب

هذه النقاط الأربع تفتح إضافة مرسل واتساب عبر الواجهة البرمجية: قوالب رسائل الطلبات التي اعتمدتها المنصة، ورصيد واتساب الخاص بالمتجر، وسجل الرسائل المرسلة للزبائن، ونداء يرسل قالباً واحداً لزبون طلب واحد. الرسالة المرسلة عبر الواجهة البرمجية تخضع لقواعد الرسائل التلقائية نفسها: تُخصم رسالة واحدة من الرصيد عند وضعها في الطابور، وتعود إلى الرصيد إذا لم يفوترها واتساب، سواء رُفضت أو لم تصل أبداً أو وصلت دون فوترة. والرسالة التي لا تُرسل لا يُخصم منها شيء.

لا يمكن إرسال نص حرّ. كل رسالة هي أحد القوالب الستة المذكورة أسفله، تُملأ من بيانات الطلب (الاسم الأول للزبون، رقم الطلب، اسم المتجر، شركة التوصيل، مكتب الاستلام، المبلغ)، بالعربية أو الفرنسية، مع زر "تتبع طلبي".

## قبل أن تبدأ[​](#قبل-أن-تبدأ "رابط مباشر إلى قبل أن تبدأ")

* يجب أن تكون إضافة **مرسل واتساب** مفعّلة في المتجر (صفحة الإضافات في لوحة التحكم). نقاط القراءة الثلاث تعمل بدونها، أما الإرسال فيُرجع `403 addon_not_active`.
* شحن الرصيد يتم من صفحة الإضافة في لوحة التحكم (`/dashboard/whatsapp-sender`، زر **شحن الرصيد**). الواجهة البرمجية تقرأ الرصيد ولا تشحنه.
* الرسائل تُرسل إلى الأرقام الجزائرية للهاتف النقال فقط (05 أو 06 أو 07). أي رقم آخر يُتجاوز بـ `invalid_number` دون أي خصم.
* يحتاج المفتاح صلاحيات واتساب. المفاتيح المُنشأة من لوحة التحكم (**الإعدادات ← واجهة API**، `/dashboard/api`) تحصل على الاثنتين. **الصلاحيات تُجمَّد لحظة إنشاء المفتاح**، فالمفتاح الذي أُنشئ قبل الإصدار v1.6 لا يملكهما: أنشئ مفتاحاً جديداً من لوحة التحكم لاستعمال هذه النقاط. والمفتاح المُنشأ عبر `POST /v1/keys` لا يحصل إلا على الصلاحيات التي يملكها المفتاح الذي أنشأه.

| النطاق          | الوصف                                                                    |
| --------------- | ------------------------------------------------------------------------ |
| `whatsapp:read` | الاطلاع على قوالب رسائل واتساب ورصيدك وسجل الرسائل المرسلة               |
| `whatsapp:send` | إرسال رسائل واتساب لزبائنك بخصوص طلباتهم (تُخصم كل رسالة من رصيد واتساب) |

## `GET /v1/whatsapp/templates`[​](#get-v1whatsapptemplates "رابط مباشر إلى get-v1whatsapptemplates")

قائمة القوالب: النص العربي والفرنسي، وقيم مثال لكل خانة، وحالة الاعتماد لكل لغة.

**المصادقة:** مفتاح منصة بصلاحية `whatsapp:read`.

الحالة هي آخر ما قرأته المنصة من واتساب. تُحدَّث مرة كل 10 دقائق على الأكثر ما دامت الرسائل تُرسل، و`UNKNOWN` تعني أنها لم تُقرأ بعد. هذا النداء لا يتصل بواتساب أبداً. لا تُرسل إلا القوالب المعتمدة `APPROVED`: الإرسال بلغة قالبها غير معتمد يُتجاوز بـ `template_not_approved` دون أي خصم.

### الطلب[​](#الطلب "رابط مباشر إلى الطلب")

```
curl 'https://api.dzbuild.app/v1/whatsapp/templates' \

  -H "Authorization: Bearer $DZ_KEY"
```

### الاستجابة 200[​](#الاستجابة-200 "رابط مباشر إلى الاستجابة 200")

يظهر هنا عنصر واحد من الستة.

```
{

  "data": {

    "items": [

      {

        "key": "shipped_home",

        "name": "dz_order_shipped_home",

        "toggle": "shipped",

        "languages": {

          "ar": {

            "body": "أهلاً {{1}}، طلبك رقم {{2}} من {{3}} في الطريق مع {{4}}.\nسيصلك خلال {{5}}. سيتصل بك عامل التوصيل قبل الوصول، يرجى إبقاء هاتفك متاحاً وتجهيز المبلغ: {{6}} دج.\nاضغط على الزر لتتبع طلبك.",

            "example": ["أحمد", "1024", "متجري", "Yalidine", "يوم إلى 3 أيام", "3500"],

            "status": "APPROVED"

          },

          "fr": {

            "body": "Bonjour {{1}}, votre commande n° {{2}} chez {{3}} est en route avec {{4}}.\nLivraison prévue sous {{5}}. Le livreur vous appellera avant d'arriver : restez joignable et préparez le montant de {{6}} DA.\nAppuyez sur le bouton pour suivre votre commande.",

            "example": ["Ahmed", "1024", "Ma Boutique", "Yalidine", "1 à 3 jours", "3500"],

            "status": "APPROVED"

          }

        }

      }

    ]

  }

}
```

### القوالب الستة[​](#القوالب-الستة "رابط مباشر إلى القوالب الستة")

| `key`             | `toggle`          | ما يقرؤه الزبون                                                         |
| ----------------- | ----------------- | ----------------------------------------------------------------------- |
| `received`        | `received`        | وصل طلبه وسيتصل به المتجر لتأكيده.                                      |
| `confirmed`       | `confirmed`       | تم تأكيد طلبه وهو قيد التجهيز، مع المبلغ المطلوب.                       |
| `shipped_home`    | `shipped`         | طلبه في الطريق إلى عنوانه، مع مدة التوصيل المتوقعة المضبوطة في الإضافة. |
| `shipped_desk`    | `shipped`         | طلبه في الطريق إلى مكتب استلام تذكره الرسالة.                           |
| `delivery_failed` | `delivery_failed` | لم يتمكن الموصل من الوصول إليه اليوم وسيعاود المحاولة غداً.             |
| `desk_ready`      | `desk_ready`      | الطرد ينتظره في مكتب الاستلام.                                          |

`toggle` هو مفتاح الرسالة التلقائية في إعدادات الإضافة الذي يتبعه القالب. يتحكم في الرسائل التلقائية فقط، والإرسال عبر الواجهة البرمجية لا يأخذه بعين الاعتبار.

## `GET /v1/whatsapp/balance`[​](#get-v1whatsappbalance "رابط مباشر إلى get-v1whatsappbalance")

الرصيد وحالة الإضافة وعدّادات الرسائل التي تظهر في صفحة الإضافة.

**المصادقة:** مفتاح منصة بصلاحية `whatsapp:read`.

### الطلب[​](#الطلب-1 "رابط مباشر إلى الطلب")

```
curl 'https://api.dzbuild.app/v1/whatsapp/balance' \

  -H "Authorization: Bearer $DZ_KEY"
```

### الاستجابة 200[​](#الاستجابة-200-1 "رابط مباشر إلى الاستجابة 200")

```
{

  "data": {

    "balance": 412,

    "low_balance": false,

    "addon_active": true,

    "stats": {

      "sent": 12,

      "delivered": 230,

      "read": 158,

      "failed": 4,

      "free": 9,

      "used_month": 96

    }

  }

}
```

| الحقل                                                         | المعنى                                                                                                                  |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `balance`                                                     | عدد الرسائل المتبقية في الرصيد. المتجر الذي لم يشحن أبداً رصيده `0`.                                                    |
| `low_balance`                                                 | `true` عندما يقل الرصيد عن 50 رسالة.                                                                                    |
| `addon_active`                                                | هل إضافة مرسل واتساب مفعّلة في المتجر.                                                                                  |
| `stats.sent`، `stats.delivered`، `stats.read`، `stats.failed` | رسائل آخر 30 يوماً حسب حالتها الحالية. `delivered` تشمل الرسائل التي قرأها الزبون، فلا تجمع `delivered` و`read`.        |
| `stats.free`                                                  | رسائل آخر 30 يوماً التي وصلت إلى الزبون ولم يفوترها واتساب. أُعيدت إلى رصيدك.                                           |
| `stats.used_month`                                            | الرسائل المخصومة من الرصيد منذ أول الشهر دون أن تُعاد إليه، أي التي فوترها واتساب والتي لم يبلّغ واتساب عن نتيجتها بعد. |

## `GET /v1/whatsapp/messages`[​](#get-v1whatsappmessages "رابط مباشر إلى get-v1whatsappmessages")

رسائل المتجر من الأحدث إلى الأقدم: الرسائل التلقائية (`source` قيمته `auto`) والمرسلة عبر الواجهة البرمجية (`source` قيمته `api`). رقم هاتف الزبون لا يُرجَع أبداً.

**المصادقة:** مفتاح منصة بصلاحية `whatsapp:read`.

### معاملات الاستعلام[​](#معاملات-الاستعلام "رابط مباشر إلى معاملات الاستعلام")

| المعامل    | النوع  | الافتراضي | ملاحظات                                                                                                 |
| ---------- | ------ | --------- | ------------------------------------------------------------------------------------------------------- |
| `order_id` | أرقام  | لا شيء    | رسائل هذا الطلب فقط. أي قيمة ليست أرقاماً فقط تُرجع `400 bad_request`.                                  |
| `limit`    | int    | 50        | من 1 إلى 200.                                                                                           |
| `cursor`   | string | لا شيء    | قيمة `next_cursor` من الصفحة السابقة. انظر [الترقيم](https://dzbuild.com/ar/ar/api-docs/pagination.md). |

### الطلب[​](#الطلب-2 "رابط مباشر إلى الطلب")

```
curl 'https://api.dzbuild.app/v1/whatsapp/messages?order_id=6894' \

  -H "Authorization: Bearer $DZ_KEY"
```

### الاستجابة 200[​](#الاستجابة-200-2 "رابط مباشر إلى الاستجابة 200")

```
{

  "data": {

    "items": [

      {

        "id": 4181,

        "order_id": 6894,

        "event": "shipped_home",

        "source": "api",

        "status": "read",

        "language": "fr",

        "template_name": "dz_order_shipped_home",

        "error_title": null,

        "refunded": false,

        "billing": "charged",

        "created_at": "2026-09-26 10:14:03"

      },

      {

        "id": 4180,

        "order_id": 6894,

        "event": "confirmed",

        "source": "auto",

        "status": "delivered",

        "language": "ar",

        "template_name": "dz_order_confirmed",

        "error_title": null,

        "refunded": true,

        "billing": "free",

        "created_at": "2026-09-25 18:02:41"

      }

    ],

    "next_cursor": null,

    "has_more": false

  }

}
```

| الحقل           | المعنى                                                                                                                                                                     |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`         | في الرسالة التلقائية: حدث الطلب الذي أطلقها (`received` أو `confirmed` أو `shipped` أو `delivery_failed` أو `desk_ready`). في رسالة الواجهة البرمجية: مفتاح القالب المرسل. |
| `source`        | `auto` أو `api`.                                                                                                                                                           |
| `status`        | انظر الجدول أدناه.                                                                                                                                                         |
| `language`      | `ar` أو `fr`.                                                                                                                                                              |
| `template_name` | اسم القالب المسجّل لدى واتساب.                                                                                                                                             |
| `error_title`   | سبب تجاوز الرسالة أو فشلها، وإلا فـ `null`.                                                                                                                                |
| `refunded`      | `true` بعد أن يعود رصيد الرسالة.                                                                                                                                           |
| `billing`       | `charged` عندما يفوتر واتساب الرسالة، و`free` عندما يعود رصيدها (فشلت، أو لم تصل خلال 30 يوماً، أو وصلت دون أن يفوترها واتساب)، و`null` ما دام واتساب لم يبلّغ عن النتيجة. |
| `created_at`    | بصيغة `YYYY-MM-DD HH:MM:SS` بتوقيت الخادم.                                                                                                                                 |

| `status`    | المعنى                                                                                                                                                                                                                                                                                               |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queued`    | مدفوعة وتنتظر (قيد الإرسال). ترسلها المنصة خلال دقيقة تقريباً.                                                                                                                                                                                                                                       |
| `sending`   | تُسلَّم الآن إلى واتساب (قيد الإرسال).                                                                                                                                                                                                                                                               |
| `sent`      | قبلها واتساب (أُرسلت).                                                                                                                                                                                                                                                                               |
| `delivered` | وصلت إلى هاتف الزبون (وصلت).                                                                                                                                                                                                                                                                         |
| `read`      | فتحها الزبون (قُرئت).                                                                                                                                                                                                                                                                                |
| `failed`    | لم يتمكن واتساب من إيصالها (فشلت). إذا فشل الإرسال إلى واتساب نفسه، يعود الرصيد خلال دقائق. وإذا أبلغ واتساب عن الفشل، تنتظر المنصة 24 ساعة قبل إعادة الرصيد، لأن واتساب قد يبلّغ بعدها أنها وصلت إلى جهاز آخر للزبون، فتتحول حالتها إلى `delivered`. تصبح `refunded` قيمتها `true` بعد عودة الرصيد. |
| `skipped`   | لم تُرسل ولم يُخصم منها شيء (لم تُرسل). `error_title` يذكر السبب.                                                                                                                                                                                                                                    |

الرسالة المتجاوزة تحمل أحد هذه الأسباب في `error_title`:

| `error_title`           | المعنى                                          |
| ----------------------- | ----------------------------------------------- |
| `invalid_number`        | رقم غير صالح: الهاتف ليس رقماً جزائرياً للنقال. |
| `suppressed`            | رقم بلا واتساب.                                 |
| `template_not_approved` | القالب بانتظار الموافقة في تلك اللغة.           |
| `empty_param`           | بيانات ناقصة: الطلب ينقصه معطى يحتاجه القالب.   |

## `POST /v1/orders/{id}/whatsapp`[​](#post-v1ordersidwhatsapp "رابط مباشر إلى post-v1ordersidwhatsapp")

يضع قالباً واحداً في طابور الإرسال لزبون طلب واحد ويخصم رسالة واحدة من الرصيد. ترسلها المنصة خلال دقيقة تقريباً.

**المصادقة:** مفتاح منصة بصلاحية `whatsapp:send`. **يتطلب `Idempotency-Key`.**

### الجسم[​](#الجسم "رابط مباشر إلى الجسم")

| الحقل      | النوع        | إلزامي | ملاحظات                                                                                                                                                            |
| ---------- | ------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `template` | string       | نعم    | قيمة `key` من `GET /v1/whatsapp/templates`، أو `shipped` التي تختار `shipped_home` أو `shipped_desk` أو `desk_ready` حسب نوع توصيل الطلب (منزل أو مكتب أو استلام). |
| `language` | `ar` أو `fr` | لا     | الافتراضي هو لغة الرسائل المختارة في إعدادات الإضافة، أو لغة المتجر إن لم تُختر لغة.                                                                               |

### ما يفعله النداء[​](#ما-يفعله-النداء "رابط مباشر إلى ما يفعله النداء")

1. يتحقق من أن الإضافة مفعّلة وأن الطلب تابع للمتجر. طلب متجر آخر يُرجع `404` مثل طلب غير موجود.
2. لا يأخذ مفاتيح الرسائل التلقائية في الإضافة بعين الاعتبار: يمكنك إرسال قالب أوقفه التاجر للرسائل التلقائية.
3. كل قالب يُرسل مرة واحدة لكل طلب عبر الواجهة البرمجية. النداء الثاني يُرجع `409 already_sent` مع `id` و`status` للرسالة السابقة. الاستثناء الوحيد محاولة سابقة تم تجاوزها، مثلاً لأن الرقم كان غير صالح ثم صُحّح في الطلب: عندها يعيد النداء المحاولة.
4. يتحقق من الرقم واعتماد القالب وبيانات الطلب. أي مشكلة تُرجع `422` وسببها هو رمز الخطأ، وتُسجَّل رسالة متجاوزة دون أي خصم.
5. يخصم رسالة واحدة من الرصيد. الرصيد الفارغ يُرجع `402 no_credit` ولا يُسجَّل شيء.
6. يُرجع `202`. تابع الرسالة بـ `GET /v1/whatsapp/messages?order_id=` مع رقم الطلب. الرسالة التي يرفضها واتساب تصبح `failed` وتعود إلى الرصيد.

رسائل الواجهة البرمجية تُحسب منفصلة عن الرسائل التلقائية. إرسال `shipped_home` عبر الواجهة البرمجية لا يمنع رسالة "الطلب في الطريق" التلقائية للطلب نفسه، والرسالة التلقائية لا تمنع الإرسال عبر الواجهة البرمجية. وكل واحدة مدفوعة.

### الطلب[​](#الطلب-3 "رابط مباشر إلى الطلب")

```
curl -X POST 'https://api.dzbuild.app/v1/orders/6894/whatsapp' \

  -H "Authorization: Bearer $DZ_KEY" \

  -H "Content-Type: application/json" \

  -H "Idempotency-Key: wa-6894-shipped-1" \

  -d '{"template": "shipped", "language": "fr"}'
```

### الاستجابة 202[​](#الاستجابة-202 "رابط مباشر إلى الاستجابة 202")

قيمة `template` هي المفتاح الذي وُضع في الطابور، بعد تحويل `shipped` إلى القالب المناسب.

```
{

  "data": {

    "message_id": 4181,

    "status": "queued",

    "template": "shipped_home",

    "language": "fr"

  }

}
```

### الأخطاء[​](#الأخطاء "رابط مباشر إلى الأخطاء")

| HTTP | الرمز                   | السبب                                                                                       |
| ---- | ----------------------- | ------------------------------------------------------------------------------------------- |
| 400  | `bad_request`           | رقم الطلب ليس أرقاماً فقط، أو الجسم ليس JSON صالحاً، أو `Idempotency-Key` غائب أو غير صالح. |
| 402  | `no_credit`             | رصيد واتساب فارغ. لم يُسجَّل شيء.                                                           |
| 403  | `forbidden`             | `Missing scope: whatsapp:send`                                                              |
| 403  | `addon_not_active`      | إضافة مرسل واتساب غير مفعّلة في المتجر.                                                     |
| 404  | `not_found`             | لا يوجد طلب بهذا الرقم في المتجر.                                                           |
| 409  | `already_sent`          | هذا القالب أُرسل من قبل لهذا الطلب عبر الواجهة البرمجية.                                    |
| 422  | `unknown_template`      | `template` ليست `shipped` ولا مفتاحاً من القائمة.                                           |
| 422  | `invalid_language`      | `language` ليست `ar` ولا `fr`.                                                              |
| 422  | `invalid_number`        | هاتف الطلب ليس رقماً جزائرياً للنقال.                                                       |
| 422  | `suppressed`            | هاتف الطلب بلا واتساب.                                                                      |
| 422  | `template_not_approved` | القالب غير معتمد بعد في تلك اللغة.                                                          |
| 422  | `empty_param`           | الطلب ينقصه معطى يحتاجه القالب.                                                             |
| 422  | `idempotency_key_reuse` | استُعمل `Idempotency-Key` نفسه مع جسم مختلف أو لطلب آخر.                                    |
| 500  | `send_failed`           | تعذر وضع الرسالة في الطابور. أعد المحاولة بالمفتاح نفسه.                                    |

هكذا يبدو `409 already_sent`.

```
{

  "error": {

    "code": "already_sent",

    "message": "This template was already sent for this order",

    "id": 4181,

    "status": "delivered"

  }

}
```

### إعادة المحاولة و`Idempotency-Key`[​](#إعادة-المحاولة-وidempotency-key "رابط مباشر إلى إعادة-المحاولة-وidempotency-key")

أول استجابة لكل مفتاح تُحفظ 24 ساعة. إعادة المحاولة بالمفتاح نفسه والجسم نفسه تُرجع تلك الاستجابة مع `Idempotency-Replay: 1`، حتى لو كانت `402` أو `403` أو `422`. لذلك بعد شحن الرصيد أو تفعيل الإضافة أو تصحيح الطلب، **أعد المحاولة بـ `Idempotency-Key` جديد**: المفتاح القديم يبقى يُرجع الخطأ القديم. والـ `202` المُعادة تعني أنه لم تُوضع رسالة ثانية في الطابور.

المفتاح نفسه مع جسم مختلف أو لطلب آخر يُرجع `422 idempotency_key_reuse`. استجابات `5xx` و`429` لا تُحفظ أبداً، فأعد المحاولة بالمفتاح نفسه. وإن كانت الرسالة قد وُضعت في الطابور فعلاً قبل الخطأ، تُرجع إعادة المحاولة `409 already_sent` مع `id` الرسالة، ولا يُخصم شيء مرتين. انظر [Idempotency](https://dzbuild.com/ar/ar/api-docs/idempotency.md).

## حدود معروفة[​](#حدود-معروفة "رابط مباشر إلى حدود معروفة")

* **نص مدة التوصيل.** القالب `shipped_home` يحمل مدة التوصيل المتوقعة كما كتبها التاجر في إعدادات الإضافة. إذا كان هذا الحقل فارغاً، يحمل المدة الافتراضية للإضافة مكتوبة بلغة الرسائل المختارة في إعداداتها (أو لغة المتجر إن لم تُختر لغة). رسالة فرنسية من متجر مدته بالعربية، مكتوبة أو افتراضية، تُظهر ذلك النص العربي وسط الرسالة الفرنسية. المدة المكتوبة بالأرقام فقط، مثل `24-72h`، تُقرأ بالطريقة نفسها في اللغتين.
* **بطء الإرسال بعد فحص الاعتماد.** عندما يمضي أكثر من 10 دقائق على آخر قراءة لحالة اعتماد قالب، يعيد الإرسال قراءتها من واتساب قبل وضع الرسالة في الطابور. يحدث ذلك مرة واحدة على الأكثر لكل قالب ولغة كل 10 دقائق، وقد يؤخر `POST` حتى 15 ثانية، لذا اضبط مهلة عميل HTTP لديك على 20 ثانية على الأقل.
