# الشحن

تغطي هذه النقاط ما تحفظه لوحة التحكم في صفحات الشحن: سعر التوصيل للمنزل وللمكتب في كل ولاية، وقواعد الشحن المجاني، وشركات التوصيل المرتبطة بالمتجر. وتقدّم أيضاً قوائم الولايات والبلديات التي يحتاجها نموذج الطلب، والبلديات ومكاتب الاستلام التي تخدمها شركة توصيل المتجر.

الأسعار بالدينار الجزائري (`DZD`). يحسب `POST /v1/orders` سعر التوصيل من هذه الأسعار ويتجاهل أي تكلفة شحن تُرسل في الجسم، لذلك تقرأ واجهة المتجر الخاصة هذه الأسعار لتعرض تقديراً وتترك الطلب يحسب المبلغ. انظر [الثيمات والواجهات المخصصة](https://dzbuild.com/ar/ar/api-docs/guides/custom-storefronts.md).

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

* يحتاج المفتاح صلاحيات الشحن. المفاتيح المُنشأة من لوحة التحكم (**الإعدادات ← واجهة API**، `/dashboard/api`) تملك الاثنتين. الصلاحيات تُجمَّد لحظة إنشاء المفتاح، فالمفتاح القديم الذي تنقصه يُرجع `403 forbidden`: أنشئ مفتاحاً جديداً من لوحة التحكم.
* المتجر الذي يبيع منتجات رقمية ليس له إعداد شحن: كل كتابة في هذه الصفحة تُرجع فيه `422 shipping_not_available`.
* كل كتابة تحتاج الترويسة `Idempotency-Key`. انظر [Idempotency](https://dzbuild.com/ar/ar/api-docs/idempotency.md).
* اختبار شركة توصيل وربطها يتصلان بخوادم الشركة أثناء النداء، ومزامنة الأسعار تتصل بها في الخلفية. هذه النداءات الثلاثة و`POST /v1/orders/{id}/send-to-delivery` تتقاسم ميزانية خاصة بشركات التوصيل لكل متجر، فوق [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md).
* يمكن التراجع عن كتابة الأسعار والإعدادات. أما ربط شركة توصيل وفصلها وتغيير الشركة الافتراضية فلا. قسم التراجع في آخر هذه الصفحة يشرح الطريقة.
* قراءات الشحن لا تُخزَّن مؤقتاً على الحافة: نداء `GET` يُرسل مباشرة بعد كتابة يُرجع القيم الجديدة.

| النطاق           | الوصف                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------ |
| `shipping:read`  | قراءة أسعار الشحن وإعداداته، وشركات التوصيل المرتبطة، وتغطية شركات التوصيل، وقوائم الولايات والبلديات. |
| `shipping:write` | تعديل أسعار الشحن وإعداداته، وربط شركات التوصيل واختبارها وفصلها ومزامنة أسعارها.                      |

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

الولايات التي يوصل إليها المتجر حسب نظام الولايات فيه: من 1 إلى 58 في النظام المتوافق مع شركات التوصيل، ومن 1 إلى 69 في نظام 69 ولاية. الأسماء بالعربية والفرنسية والإنجليزية. القائمة كلها تأتي في استجابة واحدة، دون ترقيم صفحات.

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

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

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

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

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

تظهر هنا ولايتان من 58 ولاية. الحقل `mode_note` جملة واحدة بالإنجليزية تشرح النظام.

```
{

  "data": {

    "wilaya_mode": "58",

    "mode_note": "Courier-compatible mode: wilayas 1-58 only.",

    "count": 58,

    "wilayas": [

      { "id": 1, "name_ar": "أدرار", "name_fr": "Adrar", "name_en": "Adrar" },

      { "id": 16, "name_ar": "الجزائر", "name_fr": "Alger", "name_en": "Algiers" }

    ]

  }

}
```

## `GET /v1/wilayas/{id}/communes`[​](#get-v1wilayasidcommunes "رابط مباشر إلى get-v1wilayasidcommunes")

بلديات ولاية واحدة، مرتبة حسب الاسم الفرنسي. يُجاب عن أي ولاية من 1 إلى 69 مهما كان نظام الولايات في المتجر. القائمة كلها تأتي في استجابة واحدة.

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

هذه قائمة البلديات الخاصة بالمنصة. لا تقول أي البلديات تخدمها شركة التوصيل: هذا دور `GET /v1/shipping/coverage`.

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

```
curl 'https://api.dzbuild.app/v1/wilayas/16/communes' \

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

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

تظهر هنا بلديتان من 57 بلدية في الولاية 16.

```
{

  "data": {

    "wilaya_id": 16,

    "count": 57,

    "communes": [

      { "id": 564, "wilaya_id": 16, "name_ar": "عين بنيان", "name_fr": "Ain Benian" },

      { "id": 558, "wilaya_id": 16, "name_ar": "عين طاية", "name_fr": "Ain Taya" }

    ]

  }

}
```

المعرّف الذي ليس أرقاماً فقط يُرجع `400 bad_request`. والولاية غير الموجودة تُرجع `404 not_found`.

## `GET /v1/shipping/rates`[​](#get-v1shippingrates "رابط مباشر إلى get-v1shippingrates")

سعر التوصيل لكل ولاية لها سعر في المتجر، مفهرساً برقم الولاية. الولاية التي ليس لها سعر لا تظهر في `rates`.

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

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

```
curl 'https://api.dzbuild.app/v1/shipping/rates' \

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

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

تظهر هنا ولاية واحدة.

```
{

  "data": {

    "wilaya_mode": "58",

    "currency": "DZD",

    "limits": {

      "max_price": 100000,

      "max_delivery_days": 60

    },

    "count": 58,

    "rates": {

      "16": {

        "home_price": 400,

        "home_enabled": true,

        "desk_price": 300,

        "desk_enabled": true,

        "days": 1,

        "is_active": true,

        "synced_provider": null,

        "synced_at": null

      }

    }

  }

}
```

| الحقل                          | المعنى                                                                                                                     |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| `wilaya_mode`                  | `58` أو `69`، وهي القيمة نفسها التي في `GET /v1/shipping/settings`.                                                        |
| `limits`                       | أعلى سعر وأعلى قيمة `days` يقبلهما `POST /v1/shipping/rates`.                                                              |
| `count`                        | عدد الولايات في `rates`.                                                                                                   |
| `home_price`، `desk_price`     | سعر التوصيل للمنزل وسعر التوصيل للمكتب، بالدينار الجزائري.                                                                 |
| `home_enabled`، `desk_enabled` | هل يقدّم المتجر نوع التوصيل هذا في هذه الولاية.                                                                            |
| `days`                         | مدة التوصيل بالأيام.                                                                                                       |
| `synced_provider`، `synced_at` | شركة التوصيل التي كتبت قائمة أسعارها هذا السعر آخر مرة، ومتى (`YYYY-MM-DD HH:MM:SS`). القيمة `null` إن لم تكتبه أي مزامنة. |

## `POST /v1/shipping/rates`[​](#post-v1shippingrates "رابط مباشر إلى post-v1shippingrates")

ينشئ أسعار الولايات التي ترسلها أو يعدّلها. الولايات الأخرى لا تُمَس.

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

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

`rates` كائن مفهرس برقم الولاية مكتوباً بأرقام فقط (`"16"` وليس `"016"`)، ويضم من 1 إلى 69 ولاية. كل قيمة تحمل الحقول المراد ضبطها، وكل حقل اختياري.

| الحقل          | النوع  | ملاحظات                                                                            |
| -------------- | ------ | ---------------------------------------------------------------------------------- |
| `home_price`   | number | بالدينار، يُقرَّب إلى رقمين بعد الفاصلة، من 0 إلى 100000. يُقبل النص الرقمي أيضاً. |
| `home_enabled` | bool   | `true` أو `false`. وتُقبل أيضاً `0` و`1` و`"0"` و`"1"`.                            |
| `desk_price`   | number | القواعد نفسها التي لـ `home_price`.                                                |
| `desk_enabled` | bool   | القواعد نفسها التي لـ `home_enabled`.                                              |
| `days`         | int    | عدد صحيح من الأيام، من 0 إلى 60.                                                   |

الحقل الذي تتركه أو ترسله `null` يحتفظ بقيمته المحفوظة. والولاية التي لم يكن لها سعر تبدأ بسعر `0` وبنوعَي التوصيل مفعّلين وبمدة `3` أيام.

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

```
curl -X POST 'https://api.dzbuild.app/v1/shipping/rates' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: rates-2026-10-06-1" \

  -d '{"rates": {"16": {"home_price": 450, "desk_price": 350}, "31": {"desk_enabled": false}}}'
```

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

الحقل `rates` يضم الولايات المكتوبة فقط، كما حُفظت بعد الكتابة.

```
{

  "data": {

    "updated": 2,

    "wilaya_ids": [16, 31],

    "rates": {

      "16": { "home_price": 450, "home_enabled": true, "desk_price": 350, "desk_enabled": true, "days": 1 },

      "31": { "home_price": 500, "home_enabled": true, "desk_price": 350, "desk_enabled": false, "days": 2 }

    }

  }

}
```

القيم السابقة تُحفظ، فيمكن التراجع عن الكتابة. الاستجابة لا تحمل `change_id`: انظر قسم التراجع.

## `GET /v1/shipping/settings`[​](#get-v1shippingsettings "رابط مباشر إلى get-v1shippingsettings")

قواعد الشحن المجاني ونظام الولايات.

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

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

```
curl 'https://api.dzbuild.app/v1/shipping/settings' \

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

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

تحمل الاستجابة أيضاً كائن `notes` فيه جملتان بالإنجليزية تعيدان شرح قاعدة الحد الأدنى وقاعدة نظام الولايات. المثال لا يعرضه.

```
{

  "data": {

    "free_shipping": false,

    "free_shipping_threshold": 8000,

    "free_shipping_threshold_active": true,

    "wilaya_mode": "58"

  }

}
```

| الحقل                            | المعنى                                                                                                          |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `free_shipping`                  | `true` عندما يكون التوصيل مجانياً لكل الطلبات.                                                                  |
| `free_shipping_threshold`        | المجموع الفرعي للطلب بالدينار الذي يصبح التوصيل مجانياً ابتداءً منه. القيمة `0` أو `null` تعني أنه لا يوجد حد.  |
| `free_shipping_threshold_active` | `true` فقط عندما يكون الحد أكبر من `0`.                                                                         |
| `wilaya_mode`                    | `"58"`: الولايات الـ 58 التي تعمل بها شركات التوصيل. `"69"`: كل الولايات الـ 69، وهو نظام يُضبط من لوحة التحكم. |

## `PATCH /v1/shipping/settings`[​](#patch-v1shippingsettings "رابط مباشر إلى patch-v1shippingsettings")

يغيّر إعداداً أو أكثر من الإعدادات الثلاثة. أرسل واحداً على الأقل، والحقول الأخرى تُتجاهل.

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

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

| الحقل                     | النوع          | ملاحظات                                                                                                                                                                                           |
| ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `free_shipping`           | bool           | `true` أو `false`. وتُقبل أيضاً `0` و`1` و`"0"` و`"1"`.                                                                                                                                           |
| `free_shipping_threshold` | number أو null | بالدينار، يُقرَّب إلى رقمين بعد الفاصلة، من 0 إلى 99999999.99. القيمة `0` أو `null` تُلغي الحد.                                                                                                   |
| `wilaya_mode`             | string         | `"58"` فقط، وهي تُرجع متجراً في نظام 69 ولاية إلى 58 ولاية. التحويل إلى 69 ولاية يتم من صفحة **أسعار الشحن** في لوحة التحكم (`/dashboard/shipping`)، ويُرجع هنا `422 wilaya_mode_69_unsupported`. |

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

```
curl -X PATCH 'https://api.dzbuild.app/v1/shipping/settings' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: settings-2026-10-06-1" \

  -d '{"free_shipping_threshold": 8000}'
```

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

الإعدادات بعد الكتابة، دون `notes`. القيم السابقة تُحفظ، فيمكن التراجع عن التغيير.

## `GET /v1/shipping/providers`[​](#get-v1shippingproviders "رابط مباشر إلى get-v1shippingproviders")

كل شركات التوصيل التي تدعمها المنصة، مرتبطة بالمتجر أو لا، مع ما تطلبه كل واحدة عند ربطها. قيم بيانات الدخول لا تُرجع أبداً: الحقلان `has_id` و`has_token` يقولان فقط هل توجد قيمة محفوظة. القائمة كلها تأتي في استجابة واحدة.

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

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

```
curl 'https://api.dzbuild.app/v1/shipping/providers' \

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

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

تظهر هنا شركة واحدة. وتحمل الاستجابة أيضاً جملة `note` لا يعرضها المثال.

```
{

  "data": {

    "count": 103,

    "providers": [

      {

        "provider": "yalidine",

        "family": "yalidine",

        "credentials": {

          "api_id": { "label": "API ID", "required": true },

          "api_token": { "label": "API Token", "required": true },

          "_note": "Send an empty string to keep the currently stored value. Credentials are never returned by this API."

        },

        "extra_fields": {

          "delivery_tier": {

            "label": "Service tier",

            "required": false,

            "values": ["express"],

            "note": "Only \"express\" is valid here: this courier rejects the economic parameter outright and every order push would fail."

          }

        },

        "supports_rate_sync": true,

        "linked": true,

        "source": "store_delivery_providers",

        "is_enabled": true,

        "is_default": true,

        "is_send_default": true,

        "has_id": true,

        "has_token": true,

        "delivery_tier": "express",

        "economic_available": null,

        "credentials_failed_at": null,

        "synced_tier": "express",

        "stock_account": null,

        "auto_validate": null,

        "custom_name": null,

        "linked_at": "2026-09-14 10:12:00",

        "updated_at": "2026-09-14 10:12:00"

      }

    ]

  }

}
```

| الحقل                                                | المعنى                                                                                                                                                                                        |
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `family`                                             | `yalidine` أو `procolis` أو `ecotrack` أو `standalone`.                                                                                                                                       |
| `credentials`                                        | ما يعنيه `api_id` و`api_token` عند هذه الشركة، بتسمياتها هي. `api_token` غائب عند الشركة التي تأخذ قيمة واحدة.                                                                                |
| `extra_fields`                                       | الحقول الأخرى التي تقبلها هذه الشركة عند ربطها، مفهرسة بأسمائها. مصفوفة فارغة عندما لا توجد.                                                                                                  |
| `supports_rate_sync`                                 | هل يعمل `POST /v1/shipping/rates/sync` مع هذه الشركة.                                                                                                                                         |
| `linked`                                             | هل هذه الشركة مربوطة بالمتجر.                                                                                                                                                                 |
| `source`                                             | `store_delivery_providers` لشركة رُبطت من قائمة شركات التوصيل (عبر هذه الواجهة أو لوحة التحكم)، و`store_row` لشركة ضُبطت بالطريقة القديمة مباشرة في إعدادات المتجر، و`null` إن لم تكن مربوطة. |
| `is_enabled`                                         | هل الربط مفعّل.                                                                                                                                                                               |
| `is_default`                                         | هل هذه هي شركة التوصيل الافتراضية للمتجر.                                                                                                                                                     |
| `is_send_default`                                    | الشركة التي يستعملها `POST /v1/orders/{id}/send-to-delivery` عندما لا يحدد النداء شركة.                                                                                                       |
| `delivery_tier`، `synced_tier`، `economic_available` | مستوى الخدمة عند شركات عائلة Yalidine: المستوى المختار، والمستوى الذي استعملته آخر مزامنة للأسعار، وهل كان الحساب يقدّم المستوى الاقتصادي عند تلك المزامنة.                                   |
| `stock_account`، `auto_validate`، `custom_name`      | الحقول الإضافية المحفوظة لهذه الشركة، و`null` إن لم تُضبط.                                                                                                                                    |
| `credentials_failed_at`                              | وقت بصيغة `ISO 8601`، يُضبط عندما تظل الشركة ترفض بيانات الدخول المحفوظة. الإرسال لهذه الشركة يُرفض ما دام مضبوطاً. وربط الشركة من جديد يمحوه.                                                |
| `linked_at`، `updated_at`                            | `YYYY-MM-DD HH:MM:SS`. القيمة `null` لشركة مضبوطة في إعدادات المتجر.                                                                                                                          |

### ما يحمله `api_id` و`api_token`[​](#ما-يحمله-api_id-وapi_token "رابط مباشر إلى ما-يحمله-api_id-وapi_token")

| `provider`                                                               | `api_id`             | `api_token`  |
| ------------------------------------------------------------------------ | -------------------- | ------------ |
| `yalidine`، `yalitec`، `guepex`، `easyandspeed`، `economiqua`، `wecan`   | API ID               | API Token    |
| `zrexpress`، `abexexpress`، `leopardexpress`، `colilog`، `flashdelivery` | Token                | Key          |
| `zrexpressnew`                                                           | API Key (secret key) | Tenant ID    |
| `noest`                                                                  | API Token            | User GUID    |
| `colivraison`                                                            | Public Key           | Bearer Token |
| `ecomdelivery`                                                           | API Key              | API Token    |
| `neardelivery`                                                           | ApiKey               | ApiSecret    |
| `maystro`                                                                | API Token            | لا شيء       |
| `zimou`                                                                  | Bearer Token         | لا شيء       |
| `elogistia`                                                              | API Key              | لا شيء       |
| `mdm`                                                                    | x-api-key            | لا شيء       |
| `customecotrack` وكل شركات عائلة `ecotrack`                              | Bearer Token         | لا شيء       |

الحقول الإضافية، وكلها اختيارية ما لم يُذكر غير ذلك:

* `delivery_tier`، عائلة Yalidine: القيمة `express`. وتقبل `guepex` أيضاً `economic`.
* `stock_account`، عائلة `ecotrack`: تجهيز الطلبات من مخزون شركة التوصيل.
* `auto_validate`، `noest`: اعتماد الطلبات تلقائياً لدى شركة التوصيل.
* `api_url` و`custom_name`، `customecotrack`، وكلاهما إلزامي للربط: عنوان Ecotrack الخاص بالشركة بصيغة `https` (نطاق ينتهي بـ `.ecotrack.dz`، أو `platform.dhd-dz.com` أو `app.conexlog-dz.com`)، والاسم الذي يظهر لها، حتى 100 حرف.

## `POST /v1/shipping/providers/test`[​](#post-v1shippingproviderstest "رابط مباشر إلى post-v1shippingproviderstest")

يرسل بيانات الدخول إلى شركة التوصيل ويخبرك هل قبلتها. لا يُحفظ شيء. إذا كان `api_id` أو `api_token` فارغاً أو غائباً تُستعمل القيمة المحفوظة لهذه الشركة، فيمكنك إعادة اختبار شركة مربوطة دون أن تملك بيانات دخولها.

**المصادقة:** مفتاح منصة بصلاحية `shipping:write`. **يتطلب `Idempotency-Key`.** يُحسب من ميزانية شركات التوصيل.

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

| الحقل           | النوع  | إلزامي                  | ملاحظات                                                                                              |
| --------------- | ------ | ----------------------- | ---------------------------------------------------------------------------------------------------- |
| `provider`      | string | نعم                     | معرّف من `GET /v1/shipping/providers`.                                                               |
| `api_id`        | string | ما لم يكن محفوظاً       | القيمة الأولى من بيانات الدخول.                                                                      |
| `api_token`     | string | ما لم يكن محفوظاً       | القيمة الثانية، للشركات التي تأخذ قيمتين.                                                            |
| `api_url`       | string | لـ `customecotrack` فقط | عنوان Ecotrack الخاص بالشركة. عند إعادة استعمال بيانات الدخول المحفوظة يجب أن يطابق العنوان المحفوظ. |
| `delivery_tier` | string | لا                      | `express` أو `economic`. لا تُقبل `economic` إلا لـ `guepex`.                                        |

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

```
curl -X POST 'https://api.dzbuild.app/v1/shipping/providers/test' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: test-yalidine-1" \

  -d '{"provider": "yalidine", "api_id": "YOUR_API_ID", "api_token": "YOUR_API_TOKEN"}'
```

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

الشركة التي ترفض بيانات الدخول تُرجع أيضاً `200`، مع `ok: false` و`message` نتيجة الفحص لدى الشركة. الحقل `resolved_provider` يُضبط لـ `zrexpressnew` فقط: منصة ZR Express التي قبلت الزوج.

```
{

  "data": {

    "provider": "yalidine",

    "ok": true,

    "message": "تم الاتصال بنجاح",

    "resolved_provider": null,

    "saved": false

  }

}
```

## `POST /v1/shipping/providers`[​](#post-v1shippingproviders "رابط مباشر إلى post-v1shippingproviders")

يربط شركة توصيل، أو يعيد حفظ شركة مربوطة. تختبر المنصة بيانات الدخول مع الشركة أولاً، ولا تحفظ شيئاً إن رفضتها الشركة.

**المصادقة:** مفتاح منصة بصلاحية `shipping:write`. **يتطلب `Idempotency-Key`.** يُحسب من ميزانية شركات التوصيل.

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

حقول نداء الاختبار، مع:

| الحقل           | النوع  | الافتراضي       | ملاحظات                                                                              |
| --------------- | ------ | --------------- | ------------------------------------------------------------------------------------ |
| `enabled`       | bool   | `true`          | تفعيل الربط أو تعطيله.                                                               |
| `set_default`   | bool   | `false`         | جعل هذه الشركة الشركةَ الافتراضية للمتجر.                                            |
| `custom_name`   | string | لا شيء          | لـ `customecotrack` فقط، وهو إلزامي هناك. تُزال وسوم `HTML` ويُقص الاسم إلى 100 حرف. |
| `stock_account` | bool   | القيمة المحفوظة | عائلة `ecotrack`.                                                                    |
| `auto_validate` | bool   | القيمة المحفوظة | `noest`.                                                                             |

* الحقل `api_id` أو `api_token` الفارغ يحتفظ بالقيمة المحفوظة، فيمكن إعادة حفظ شركة مربوطة دون إرسال بيانات دخولها من جديد.
* أول شركة يربطها المتجر تصبح شركته الافتراضية. في الاستجابة يكون `is_default` مساوياً لـ `true` فقط عندما يجعل هذا النداء الشركة افتراضية، فالشركة الافتراضية التي يُعاد حفظها دون `set_default` تبقى افتراضية بينما تقول الاستجابة `false`. ويُظهر `GET /v1/shipping/providers` الحالة الحقيقية.
* `zrexpress` و`zrexpressnew` شركة واحدة: ربط إحداهما يحل محل الأخرى. والزوج `zrexpressnew` الذي تقبله منصة ZR Express القديمة يُحفظ باسم `zrexpress`، ويظهر ذلك في الحقل `provider` في الاستجابة.

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

```
curl -X POST 'https://api.dzbuild.app/v1/shipping/providers' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: link-yalidine-1" \

  -d '{"provider": "yalidine", "api_id": "YOUR_API_ID", "api_token": "YOUR_API_TOKEN", "set_default": true}'
```

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

```
{

  "data": {

    "provider": "yalidine",

    "is_enabled": true,

    "is_default": true,

    "has_id": true,

    "has_token": true,

    "undoable": false,

    "note": "Courier credentials are never recorded, so linking cannot be undone. To revert, link the previous courier again or unlink this one."

  }

}
```

بيانات الدخول المرفوضة تُرجع `422 credentials_rejected` مع رسالة الشركة، ولا يُحفظ شيء.

## `POST /v1/shipping/providers/default`[​](#post-v1shippingprovidersdefault "رابط مباشر إلى post-v1shippingprovidersdefault")

يجعل شركة مربوطة الشركةَ الافتراضية للمتجر. الإرسالات الجديدة إلى التوصيل تذهب إليها.

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

الحقل `provider` في الجسم يسمّي الشركة. لا تصبح شركة افتراضية إلا إذا رُبطت من قائمة شركات التوصيل، والشركة المضبوطة في إعدادات المتجر تُرجع `404 provider_not_linked`. وعندما تكون الشركة المختارة معطّلة، يقول `warning` إن الإرسال يبقى متوقفاً إلى أن تُفعَّل من جديد.

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

```
curl -X POST 'https://api.dzbuild.app/v1/shipping/providers/default' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: default-noest-1" \

  -d '{"provider": "noest"}'
```

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

```
{

  "data": {

    "provider": "noest",

    "is_default": true,

    "previous_default": "yalidine",

    "undoable": false,

    "warning": "New send-to-delivery pushes now go to \"noest\". "

  }

}
```

## التأكيد قبل مزامنة الأسعار أو فصل شركة[​](#التأكيد-قبل-مزامنة-الأسعار-أو-فصل-شركة "رابط مباشر إلى التأكيد قبل مزامنة الأسعار أو فصل شركة")

مزامنة الأسعار تكتب فوق أسعار التاجر نفسه، وفصل الشركة يزيل بيانات دخول محفوظة، لذلك يطلب النداءان تأكيداً قبل التنفيذ.

1. نادِ دون تأكيد. الرد يكون `422 confirmation_required`، ويضيف الكائن `error` الحقول `confirm_token` (يُستعمل مرة واحدة) و`confirm_token_expires_in` (`600` ثانية) و`action` و`will_change`، وهو الملخص الذي تعرضه على التاجر.
2. بعد موافقة التاجر، أعد النداء ومعه `confirm_token` في الجسم وبمفتاح `Idempotency-Key` **جديد**. المفتاح الأول مرتبط بالجسم الذي لا يحوي الرمز، فإعادة استعماله تُرجع `422 idempotency_key_reuse`.

الرمز يعمل مرة واحدة، وللمفتاح الذي تلقّاه فقط، وما دام ما يصفه لم يتغير: جدول الأسعار في حالة المزامنة، وفي حالة الفصل عدد الشركات المربوطة وهل هذه الشركة هي الافتراضية. الرمز المستعمل أو المنتهي أو الذي لم يعد يطابق يُرجع `422 confirmation_stale` مع رمز وملخص جديدين.

المفتاح الذي لا يستعمله المساعد المدمج في لوحة التحكم يمكنه إرسال `"confirm": true` بدل الرمز وتخطي الخطوة 1. أما المفاتيح التي يستعملها المساعد فيجب أن ترسل الرمز.

هكذا يبدو الرد الأول للمزامنة.

```
{

  "error": {

    "code": "confirmation_required",

    "message": "Syncing overwrites your own prices for every wilaya \"yalidine\" serves. Show the merchant the summary below; when they approve, re-send with the confirm_token.",

    "confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",

    "confirm_token_expires_in": 600,

    "action": "shipping.rates_sync:yalidine",

    "will_change": {

      "action": "Overwrite shipping rates from yalidine",

      "wilayas_at_risk": 58,

      "reversible": true,

      "note": "The prior prices are saved to the change log first, so this can be undone."

    }

  }

}
```

في حالة الفصل يضم `will_change` الحقول `action` و`was_store_default` و`remaining_providers` و`consequence` و`reversible` (`false`) و`note`.

## `POST /v1/shipping/rates/sync`[​](#post-v1shippingratessync "رابط مباشر إلى post-v1shippingratessync")

يستبدل أسعار المتجر بقائمة أسعار شركة التوصيل نفسها، لكل ولاية من 1 إلى 58 تسعّرها الشركة. تجري المزامنة في الخلفية. قبل وضع أي شيء في الطابور يُحفظ جدول الأسعار كله، و`change_id` في الاستجابة يتراجع عن المزامنة.

**المصادقة:** مفتاح منصة بصلاحية `shipping:write`. **يتطلب `Idempotency-Key`** وتأكيداً. يُحسب من ميزانية شركات التوصيل.

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

| الحقل           | النوع  | إلزامي     | ملاحظات                                                                                |
| --------------- | ------ | ---------- | -------------------------------------------------------------------------------------- |
| `provider`      | string | نعم        | شركة رُبطت من قائمة شركات التوصيل ومفعّلة. `mdm` و`neardelivery` ليس لهما قائمة أسعار. |
| `confirm_token` | string | انظر أعلاه | من الرد `confirmation_required`.                                                       |
| `confirm`       | bool   | انظر أعلاه | `true`، للمفاتيح التي لا يستعملها المساعد.                                             |

### ما تغيّره المزامنة[​](#ما-تغيّره-المزامنة "رابط مباشر إلى ما تغيّره المزامنة")

* تكتب `home_price` و`desk_price` وتضبط `synced_provider` و`synced_at`. مفاتيح التفعيل و`days` في الولاية التي كان لها سعر تبقى كما هي. والولاية التي لم يكن لها سعر تأخذ `3` أيام.
* شركات عائلة Yalidine تحتاج ولاية المتجر، وتُضبط بالحقل `wilaya_id` في `PATCH /v1/store` (انظر [المتجر](https://dzbuild.com/ar/ar/api-docs/resources/store.md)). دونها يُرجع النداء `422 store_wilaya_required`.
* تابع النتيجة بـ `GET /v1/shipping/rates`: الأسعار التي كتبتها المزامنة تحمل اسم الشركة في `synced_provider` وقيمة جديدة في `synced_at`. وإذا لم ترسل الشركة أي أسعار تبقى الأسعار كما كانت.
* ما دامت مزامنة للشركة نفسها جارية، يُرجع النداء `202` مع `status: already_running` و`sync_id` تلك المزامنة و`change_id: null`، دون طلب تأكيد.
* بعد نجاح مزامنة، يمكن مزامنة الشركة نفسها من جديد بعد 5 دقائق. والنداء قبل ذلك يُرجع `429 sync_cooldown`.

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

```
curl -X POST 'https://api.dzbuild.app/v1/shipping/rates/sync' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: sync-yalidine-2" \

  -d '{"provider": "yalidine", "confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'
```

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

```
{

  "data": {

    "status": "queued",

    "sync_id": "a1b2c3d4e5f6a7b8c9d0e1f2",

    "change_id": 500,

    "note": "The sync runs in the background and overwrites your prices for every wilaya this courier serves. Poll GET /v1/shipping/rates for the result; undo change_id to restore the prior prices."

  }

}
```

## `DELETE /v1/shipping/providers/{provider}`[​](#delete-v1shippingprovidersprovider "رابط مباشر إلى delete-v1shippingprovidersprovider")

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

**المصادقة:** مفتاح منصة بصلاحية `shipping:write`. **يتطلب `Idempotency-Key`** وتأكيداً.

* `provider` في المسار هو معرّف الشركة. لا يمكن فصل شركة هنا إلا إذا رُبطت من قائمة شركات التوصيل، وأي شركة أخرى تُرجع `404 provider_not_linked`.
* الجسم يحمل التأكيد فقط: `confirm_token`، أو `confirm: true` للمفاتيح التي لا يستعملها المساعد.
* عندما تكون الشركة المفصولة هي الافتراضية، تصبح الشركة الافتراضية هي الشركة المفعّلة الأخرى التي رُبطت قبل غيرها.
* وإن لم توجد، لا تبقى شركة افتراضية ويتوقف الإرسال إلى التوصيل في المتجر كله. وتحمل الاستجابة حينها `new_default: null` و`send_to_delivery_active: false`.

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

```
curl -X DELETE 'https://api.dzbuild.app/v1/shipping/providers/yalidine' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: unlink-yalidine-2" \

  -d '{"confirm_token": "cft_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}'
```

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

```
{

  "data": {

    "provider": "yalidine",

    "unlinked": true,

    "undoable": false,

    "remaining_providers": 1,

    "new_default": "noest",

    "send_to_delivery_active": true,

    "warning": "The store default is now \"noest\"; new send-to-delivery pushes go there."

  }

}
```

## `GET /v1/shipping/coverage`[​](#get-v1shippingcoverage "رابط مباشر إلى get-v1shippingcoverage")

الولايات والبلديات ومكاتب الاستلام التي تخدمها شركة توصيل مربوطة، من بيانات الشركة نفسها. والشركة المضبوطة في إعدادات المتجر تُعد مربوطة هنا.

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

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

| المعامل     | النوع  | الافتراضي | ملاحظات                                                                                                                                                                         |
| ----------- | ------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`  | string | لا شيء    | معرّف شركة مربوطة. دونه تُستعمل الشركة المعلَّمة بـ `is_send_default`، وإلا فأول شركة مربوطة.                                                                                   |
| `wilaya_id` | int    | 0         | القيمة `0` تعطي عدداً لكل ولاية. من `1` إلى `69` تضيف بلديات تلك الولاية ومكاتب الاستلام فيها و`desk_send_allowed`. القيمة خارج المجال من `0` إلى `69` تُرجع `400 bad_request`. |

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

```
curl 'https://api.dzbuild.app/v1/shipping/coverage?wilaya_id=16' \

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

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

تظهر هنا بلدية واحدة ومكتب واحد.

```
{

  "data": {

    "provider": "yalidine",

    "is_send_default": true,

    "knowledge_synced_at": "2026-10-05 03:12:44",

    "wilayas": [

      { "wilaya_id": 16, "name": "Alger", "communes": 57, "communes_home": 57, "communes_desk": 12, "desks": 9 }

    ],

    "wilaya_id": 16,

    "desk_send_allowed": true,

    "communes": [

      { "commune_id": 521, "name": "Alger Centre", "name_ar": "الجزائر الوسطى", "home": true, "desk": true }

    ],

    "desks": [

      { "desk_id": "160101", "name": "Agence Alger Centre", "address": "Alger Centre", "phone": null, "commune_id": 521 }

    ]

  }

}
```

| الحقل                 | المعنى                                                                                                                                                                                                                                          |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `knowledge_synced_at` | آخر مرة حدّثت فيها المنصة بلديات هذه الشركة ومكاتبها. القيمة `null` إن لم تحدّثها أبداً.                                                                                                                                                        |
| `wilayas`             | لكل ولاية: عدد البلديات `communes`، وكم منها فيه توصيل للمنزل (`communes_home`) وتوصيل للمكتب (`communes_desk`)، وعدد المكاتب `desks`. ومع `wilaya_id` تظهر تلك الولاية وحدها.                                                                  |
| `desk_send_allowed`   | هل يقبل `POST /v1/orders/{id}/send-to-delivery` طلب توصيل للمكتب إلى هذه الولاية مع هذه الشركة. إنه الفحص نفسه.                                                                                                                                 |
| `communes`            | `commune_id` هو المعرّف الذي في `GET /v1/wilayas/{id}/communes`، أو `null` عندما لا تطابق بلديةُ الشركة أي بلدية في تلك القائمة، ويكون `name` حينها الاسم الذي تعطيه الشركة للبلدية. `home` و`desk` يقولان أي نوعَي التوصيل تقدّمه الشركة هناك. |
| `desks`               | مكاتب الاستلام لدى الشركة في الولاية. يشرح دليل [الثيمات والواجهات المخصصة](https://dzbuild.com/ar/ar/api-docs/guides/custom-storefronts.md) كيف تعرضها عند إتمام الطلب.                                                                        |

المتجر الذي ليس له شركة توصيل يُرجع `422 no_courier_linked`. والقيمة `provider` لشركة لم يربطها المتجر تُرجع `404 provider_not_linked`.

## التراجع عن تغييرات الأسعار والإعدادات[​](#التراجع-عن-تغييرات-الأسعار-والإعدادات "رابط مباشر إلى التراجع عن تغييرات الأسعار والإعدادات")

`POST /v1/shipping/rates` و`PATCH /v1/shipping/settings` ومزامنة الأسعار تحفظ القيم التي تستبدلها، فيمكن التراجع عن كل منها بـ `POST /v1/changes/{id}/undo`.

* مزامنة الأسعار تُرجع `change_id` الخاص بها. أما الكتابتان الأخريان فلا: ابحث عن التغيير بـ `GET /v1/changes?entity=shipping.rates` أو `GET /v1/changes?entity=shipping.settings`، الأحدث أولاً. عرض التغييرات يحتاج `store:read`.
* التراجع يحتاج `shipping:write` و`Idempotency-Key`. والتراجع نفسه تغيير مستقل، `undo_change_id`، يمكنك التراجع عنه بدوره، إلا التراجع عن مزامنة فإنه يُرجع `422 nothing_to_restore`. انظر [التغييرات والتراجع عنها](https://dzbuild.com/ar/ar/api-docs/resources/changes.md).
* التراجع عن كتابة أسعار يحذف أسعار الولايات التي أنشأتها تلك الكتابة. والتراجع عن مزامنة يُرجع الولايات التي كان لها سعر قبلها، أما الولاية التي أضافتها المزامنة فتحتفظ بسعرها الجديد.
* التراجع يعيد كتابة القيم المحفوظة حتى لو تغيّرت الأسعار أو الإعدادات بعد ذلك، من لوحة التحكم أو عبر الواجهة البرمجية.
* التغيير الذي يُتراجع عنه مرة ثانية يُرجع `409 already_undone`.
* رمز التطبيق المثبّت لا يستطيع عرض التغييرات ولا التراجع عنها: كلاهما يُرجع `403 forbidden`.

```
curl -X POST 'https://api.dzbuild.app/v1/changes/500/undo' \

  -H "Authorization: Bearer $DZ_KEY" \

  -H "Idempotency-Key: undo-500"
```

```
{

  "data": {

    "undone": true,

    "change_id": 500,

    "entity": "shipping.rates",

    "undo_change_id": 510

  }

}
```

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

| HTTP     | الرمز                                         | السبب                                                                                                                                                             |
| -------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400      | `bad_request`                                 | الجسم ليس كائن `JSON`، أو `rates` غائب أو ليس كائناً، أو معرّف في المسار غير صالح، أو `wilaya_id` خارج المجال من 0 إلى 69، أو `Idempotency-Key` غائب أو غير صالح. |
| 400      | `invalid_rates`                               | `rates` فارغ أو فيه أكثر من 69 ولاية، أو سعر ليس كائناً، أو مفتاح تفعيل ليس قيمة منطقية.                                                                          |
| 400، 422 | `invalid_wilaya`                              | 400: مفتاح في `rates` ليس أرقاماً فقط. 422: لا توجد ولاية بهذا الرقم.                                                                                             |
| 400، 422 | `invalid_price`                               | 400: ليس رقماً. 422: سالب أو أكبر من 100000.                                                                                                                      |
| 400، 422 | `invalid_days`                                | 400: ليس عدداً صحيحاً. 422: خارج المجال من 0 إلى 60.                                                                                                              |
| 400      | `nothing_to_update`                           | `PATCH /v1/shipping/settings` دون أي حقل من حقوله الثلاثة.                                                                                                        |
| 400      | `invalid_free_shipping`                       | `free_shipping` ليس قيمة منطقية.                                                                                                                                  |
| 400، 422 | `invalid_threshold`                           | 400: ليس رقماً ولا `null`. 422: سالب أو أكبر من 99999999.99.                                                                                                      |
| 400      | `invalid_wilaya_mode`                         | `wilaya_mode` ليس `"58"` ولا `"69"`.                                                                                                                              |
| 422      | `wilaya_mode_69_unsupported`                  | `wilaya_mode` هو `"69"`، وهذا يُضبط من لوحة التحكم.                                                                                                               |
| 400      | `provider_required`                           | `provider` غائب.                                                                                                                                                  |
| 400      | `credentials_required`                        | لم يُرسل `api_id` ولم يُحفظ، أو لا يوجد `api_token` لشركة تأخذ قيمتين.                                                                                            |
| 400      | `invalid_credentials_format`                  | قيم `zrexpressnew` تحوي أقواس `JSON` أو مسافات أو أسطراً جديدة، أو تبدأ بـ `http`، أو تتجاوز 128 حرفاً.                                                           |
| 400      | `api_url_required`، `custom_name_required`    | `customecotrack` دون عنوانها، أو ربط دون اسمها.                                                                                                                   |
| 400، 422 | `invalid_delivery_tier`                       | 400: ليس `express` ولا `economic`. 422: `economic` لشركة غير `guepex`.                                                                                            |
| 422      | `unsupported_provider`                        | المعرّف ليس في `GET /v1/shipping/providers`.                                                                                                                      |
| 422      | `invalid_api_url`، `api_url_mismatch`         | عنوان `customecotrack` ليس عنوان Ecotrack بصيغة `https`، أو يختلف عن العنوان المحفوظ مع إعادة استعمال بيانات الدخول المحفوظة.                                     |
| 422      | `credentials_rejected`                        | رفضت الشركة بيانات الدخول. لم يُحفظ شيء.                                                                                                                          |
| 422      | `rate_sync_unsupported`                       | `mdm` و`neardelivery` ليس لهما قائمة أسعار.                                                                                                                       |
| 422      | `provider_not_linked`                         | مزامنة الأسعار: الشركة لم تُربط من قائمة شركات التوصيل، أو معطّلة.                                                                                                |
| 404      | `provider_not_linked`                         | الشركة الافتراضية أو الفصل أو التغطية: المتجر لم يربط هذه الشركة.                                                                                                 |
| 422      | `store_wilaya_required`                       | مزامنة أسعار شركة من عائلة Yalidine قبل ضبط ولاية المتجر.                                                                                                         |
| 422      | `confirmation_required`، `confirmation_stale` | انظر قسم التأكيد أعلاه.                                                                                                                                           |
| 422      | `snapshot_too_large`، `snapshot_failed`       | تعذّر حفظ الأسعار السابقة، فرُفضت الكتابة بدل أن تصبح غير قابلة للتراجع.                                                                                          |
| 422      | `no_courier_linked`                           | التغطية لمتجر ليس له شركة توصيل.                                                                                                                                  |
| 422      | `shipping_not_available`                      | كتابة على متجر يبيع منتجات رقمية.                                                                                                                                 |
| 422      | `idempotency_key_reuse`                       | المفتاح `Idempotency-Key` نفسه مع جسم مختلف.                                                                                                                      |
| 403      | `forbidden`                                   | المفتاح لا يملك الصلاحية، مثلاً `Missing scope: shipping:write`، أو مفتاح تاجر متجره ليس على خطة Enterprise سارية.                                                |
| 404      | `not_found`                                   | بلديات ولاية غير موجودة.                                                                                                                                          |
| 404      | `store_not_found`                             | متجر المفتاح لم يعد موجوداً.                                                                                                                                      |
| 429      | `sync_cooldown`                               | جرت مزامنة الشركة نفسها قبل أقل من 5 دقائق. الرسالة تقول كم دقيقة بقيت.                                                                                           |
| 429      | `rate_limited`، `too_many_concurrent`         | استُنفدت ميزانية شركات التوصيل أو حد طلبات المتجر. انظر [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md).                                         |
| 503      | `sync_queue_failed`                           | تعذّر بدء المزامنة ولم تتغير الأسعار. أعد المحاولة لاحقاً.                                                                                                        |
| 500      | `server_error`                                | أعد المحاولة بالمفتاح `Idempotency-Key` نفسه.                                                                                                                     |
