# قوائم المتجر

قائمة المتجر هي الروابط التي يختارها التاجر لشريط التنقل وللقائمة الجانبية على الهاتف وللتذييل. تقرأها الواجهة البرمجية وتكتبها كوثيقة واحدة: حتى 12 رابطاً في الأعلى مع حتى 10 روابط فرعية لكل واحد، وحتى 3 مجموعات في التذييل من 10 روابط، وزر واحد للوحة الفئات العريضة. المتجر الذي لم يحفظ قائمة أبداً يعرض الروابط التلقائية، وتُرجع له هاتان النقطتان `automatic: true`.

يعدّل التاجر الوثيقة نفسها من لوحة التحكم، في صفحة التخصيص، سطر **القائمة والروابط**. انظر [القائمة وروابط التذييل](https://dzbuild.com/ar/docs/storefront/menus) في دليل التاجر.

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

* تحتاج القراءة إلى `store:read` وتحتاج الكتابات إلى `store:write`. مفاتيح التاجر تحمل الاثنتين.
* `PUT` تستبدل الوثيقة كلها. اقرأها أولاً، وغيّر ما تحتاجه، ثم أرسلها مع قيمة `version` التي قرأتها.
* `Idempotency-Key` اختياري مع `PUT`. و`PUT` الذي يحمل مفتاحاً يُعاد جوابه لمدة 24 ساعة. انظر [Idempotency](https://dzbuild.com/ar/ar/api-docs/idempotency.md).

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

| الحقل    | النوع              | ملاحظات                                                                                                                                                           |
| -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `v`      | int                | دائماً `1`.                                                                                                                                                       |
| `mega`   | boolean            | `true` يفعّل لوحة الفئات العريضة. انظر [اللوحة العريضة](#the-wide-panel).                                                                                         |
| `top`    | array من العناصر   | روابط شريط التنقل بالترتيب. من 1 إلى 12. `home` و`products` و`categories` و`track` و`contact` و`cart` يظهر كل منها مرة واحدة على الأكثر هنا، دون حساب `children`. |
| `footer` | array من المجموعات | أعمدة التذييل بالترتيب. حتى 3.                                                                                                                                    |

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

| الحقل                | النوع            | ملاحظات                                                                                                                                           |
| -------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`               | string           | واحد من `home` و`products` و`categories` و`category` و`page` و`track` و`contact` و`cart` و`url`. انظر [أنواع العناصر](#item-types).               |
| `label`              | string           | حتى 40 حرفاً. الفارغ يعني اسم الهدف نفسه، بلغة الزائر في الأنواع الجاهزة. إلزامي مع `url`.                                                        |
| `ref`                | int أو null      | رقم الفئة مع `category`، ورقم الصفحة مع `page`، و`null` مع الأنواع الأخرى.                                                                        |
| `url`                | string           | العنوان مع `url`، حتى 500 بايت. فارغ مع الأنواع الأخرى.                                                                                           |
| `show_subcategories` | boolean          | عناصر `category` في المستوى الأعلى فقط: يعرض أيضاً حتى 10 فئات فرعية لتلك الفئة. يُحفظ `false` في كل مكان آخر، بما فيه `children` وروابط التذييل. |
| `children`           | array من العناصر | عناصر الأعلى فقط: حتى 10 روابط فرعية. الرابط الفرعي ليس له `children` خاص به ولا يمكن أن يكون عنصر `categories`.                                  |

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

| الحقل   | النوع            | ملاحظات                                                                                                                                                               |
| ------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `key`   | string أو null   | `quick_links` أو `categories` للمجموعتين التلقائيتين، و`null` لمجموعة تضيفها أنت.                                                                                     |
| `label` | string           | عنوان العمود، حتى 40 حرفاً. يمكن أن يكون فارغاً فقط إذا كان `key` موجوداً: يعرض المتجر حينها العنوان التلقائي بلغة الزائر. والعنوان المكتوب يظهر كما هو في كل اللغات. |
| `links` | array من العناصر | من رابط واحد إلى 10 روابط. روابط التذييل ليس لها `children` ولا `show_subcategories`.                                                                                 |

تُحفظ الأسماء نصاً عادياً: تُحذف وسوم HTML وتُزال المسافات من الطرفين. والوثيقة كلها 16 KB على الأكثر.

### أنواع العناصر[​](#item-types "رابط مباشر إلى أنواع العناصر")

| `type`       | يفتح الرابط                                                                                                                                            |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `home`       | `/`، الصفحة الرئيسية للمتجر.                                                                                                                           |
| `products`   | `/products`، كل المنتجات.                                                                                                                              |
| `categories` | قائمة منسدلة بالفئات الرئيسية وفئاتها الفرعية، مع سطر لكل المنتجات. وفي التذييل، جزء الفئات في الصفحة الرئيسية.                                        |
| `category`   | `/category/{ref}`. يجب أن يكون `ref` فئة من هذا المتجر.                                                                                                |
| `page`       | `/pages/{slug}` للصفحة `ref`. يجب أن يكون `ref` صفحة منشورة من هذا المتجر. انظر [صفحات المتجر](https://dzbuild.com/ar/ar/api-docs/resources/pages.md). |
| `track`      | `/track-order`.                                                                                                                                        |
| `contact`    | جزء الاتصال في الصفحة الرئيسية.                                                                                                                        |
| `cart`       | `/cart`.                                                                                                                                               |
| `url`        | `url`: مسار في المتجر مثل `/pages/delivery`، أو مرساة مثل `#products`، أو عنوان `http://` أو `https://`، أو `tel:` أو `mailto:`.                       |

قيمة `url` بلا بروتوكول تشبه نطاقاً، مثل `instagram.com/x`، تُحفظ `https://instagram.com/x`. و`javascript:` و`data:` و`//` والشرطات المائلة العكسية وعلامات الاقتباس والمسافات والأقواس الزاوية مرفوضة بالرمز `bad_url`.

في المتجر، الرابط إلى فئة حُذفت منذ ذلك، أو إلى صفحة أُرجعت مسودة، يُترك مع روابطه الفرعية. والفئة غير المفعّلة لا تظهر.

### اللوحة العريضة[​](#the-wide-panel "رابط مباشر إلى اللوحة العريضة")

مع `"mega": true`، عنصر الأعلى الذي لروابطه الفرعية روابط فرعية خاصة بها يظهر على الحاسوب كلوحة عريضة، فيها عمود لكل رابط فرعي. وهذا حال العنصر `categories` إذا كان لفئة رئيسية فئات فرعية. وعنصر `category` مع `show_subcategories` يعرض حتى 10 فئات فرعية، ومع `mega` حتى 10 من فئاتها الفرعية لكل واحدة، أي مستوى ثالثاً. والعنصر `categories` يحتفظ بحدود القائمة التلقائية: 10 فئات رئيسية مع 5 فئات فرعية لكل واحدة في شريط التنقل، و12 مع 6 في قالب Promobi. وعلى الهاتف تعرض القائمة الجانبية المستويات نفسها كقائمة تنفتح وتنغلق.

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

قائمة المتجر. للمتجر الذي لم يحفظ قائمة أبداً، `menus` هي القائمة التلقائية و`automatic` قيمتها `true`.

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

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

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

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

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

`version` هي القيمة التي ترسلها مع `PUT`. و`max` يعطي الحدود و`types` أنواع العناصر المقبولة.

```
{

  "data": {

    "automatic": false,

    "menus": {

      "v": 1,

      "mega": false,

      "top": [

        {"type": "home", "label": "", "ref": null, "url": "", "show_subcategories": false, "children": []},

        {"type": "category", "label": "", "ref": 152, "url": "", "show_subcategories": true, "children": []},

        {"type": "page", "label": "", "ref": 7, "url": "", "show_subcategories": false, "children": []}

      ],

      "footer": [

        {"label": "Infos", "links": [{"type": "track", "label": "", "ref": null, "url": ""}, {"type": "url", "label": "Instagram", "ref": null, "url": "https://instagram.com/my-store"}]}

      ]

    },

    "version": "3f9a1c07d2e4b851",

    "max": {"top": 12, "children": 10, "groups": 3, "links": 10, "label": 40},

    "types": ["home", "products", "category", "page", "track", "contact", "cart", "url", "categories"]

  },

  "meta": {"request_id": "5d2a8e1f07c3b946", "api_version": "v1"}

}
```

## `PUT /v1/store/menus`[​](#put-v1storemenus "رابط مباشر إلى put-v1storemenus")

تستبدل القائمة كلها.

**المصادقة:** مفتاح منصة بصلاحية `store:write`. و`Idempotency-Key` اختياري.

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

| الحقل     | النوع          | إلزامي | ملاحظات                                                                                                                               |
| --------- | -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `menus`   | object أو null | نعم    | الوثيقة الجديدة. `null` يُرجع القائمة التلقائية.                                                                                      |
| `version` | string         | لا     | قيمة `version` التي قرأتها. إذا لم تعد تطابق، يُرجع النداء `409 write_conflict` ولا يغيّر شيئاً. وبدونها يكتب النداء فوق ما هو محفوظ. |

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

```
curl -X PUT 'https://api.dzbuild.app/v1/store/menus' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: menus-sizes-1" \

  -d '{"version": "3f9a1c07d2e4b851", "menus": {"v": 1, "mega": false, "top": [{"type": "home", "label": "", "ref": null, "url": "", "show_subcategories": false, "children": []}, {"type": "page", "label": "Guide des tailles", "ref": 9, "url": "", "show_subcategories": false, "children": []}], "footer": []}}'
```

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

`menus` هي الوثيقة كما حُفظت، و`version` القيمة الجديدة، و`change_id` رقم التغيير في سجل التغييرات. الجسم الذي لا يغيّر شيئاً يُرجع `change_id: null`.

```
{

  "data": {

    "menus": {

      "v": 1,

      "mega": false,

      "top": [

        {"type": "home", "label": "", "ref": null, "url": "", "show_subcategories": false, "children": []},

        {"type": "page", "label": "Guide des tailles", "ref": 9, "url": "", "show_subcategories": false, "children": []}

      ],

      "footer": []

    },

    "version": "b70e4d2a9c15f383",

    "change_id": 90420,

    "automatic": false

  },

  "meta": {"request_id": "a81c3f5e92d07b64", "api_version": "v1"}

}
```

`"menus": null` يُرجع `automatic: true` مع القائمة التلقائية في `menus`.

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

تُرجع `PUT` قيمة `change_id`. و`POST /v1/changes/{change_id}/undo` يُرجع القائمة كما كانت قبل ذلك النداء، بما فيها القائمة التلقائية. يحتاج التراجع إلى `store:write` وإلى `Idempotency-Key`.

* إذا تغيّرت القائمة مرة أخرى بعد ذلك النداء، يُرجع التراجع `409 menus_changed` ولا يغيّر شيئاً. تراجع عن التغيير الأحدث أولاً.
* التغيير الذي تتراجع عنه مرة ثانية يُرجع `409 already_undone`.
* القوائم التي يحفظها التاجر من صفحة التخصيص لا تُسجَّل، فلا يمكن التراجع عنها عبر الواجهة البرمجية.
* `GET /v1/changes?entity=store.menus` يعرض تغييرات القائمة، الأحدث أولاً، مع `store:read`. و`entity_id` قيمته `menus`.
* رمز التطبيق المثبّت لا يستطيع قراءة التغييرات ولا التراجع عنها: `GET /v1/changes` والتراجع يُرجعان `403 forbidden`. وأجوبة الكتابة تحمل `change_id` رغم ذلك.

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

  -H "Authorization: Bearer $DZ_KEY" \

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

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

| HTTP | الرمز                   | السبب                                                                                                                                                                                                                                                     |
| ---- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400  | `bad_request`           | الجسم ليس كائن JSON، أو `menus` غائب أو ليس كائناً ولا `null`، أو `version` ليس نصاً.                                                                                                                                                                     |
| 401  | `unauthorized`          | مفتاح خاطئ أو غائب.                                                                                                                                                                                                                                       |
| 402  | `quota_exceeded`        | انتهت حصة الطلبات الشهرية للمتجر. انظر [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md).                                                                                                                                                  |
| 403  | `forbidden`             | `Missing scope: store:read` أو `Missing scope: store:write`، أو `API access requires an active Enterprise plan` لمفتاح تاجر متجره ليس على خطة Enterprise سارية.                                                                                           |
| 404  | `not_found`             | المتجر غير موجود.                                                                                                                                                                                                                                         |
| 409  | `write_conflict`        | قيمة `version` التي أرسلتها لم تعد تطابق: يحمل الخطأ `menus` الحالية (`null` ما دام المتجر يعرض الروابط التلقائية) و`version` الحالية، فتدمج ثم تعيد المحاولة. والرمز نفسه بدونهما يعني أن كتابة أخرى وصلت في اللحظة نفسها: اقرأ من جديد ثم أعد المحاولة. |
| 409  | `menus_changed`         | في التراجع فقط: تغيّرت القائمة بعد التغيير الذي تتراجع عنه.                                                                                                                                                                                               |
| 409  | `already_undone`        | في التراجع فقط: سبق التراجع عن هذا التغيير.                                                                                                                                                                                                               |
| 413  | `payload_too_large`     | الجسم يتجاوز 1 MB.                                                                                                                                                                                                                                        |
| 422  | `invalid_menus`         | رُفضت قيمة. يعطي `fields` القيمتين `{path, code}` لها. انظر الرموز أسفله.                                                                                                                                                                                 |
| 422  | `idempotency_key_reuse` | استُعمل `Idempotency-Key` نفسه مع جسم آخر.                                                                                                                                                                                                                |
| 429  | `rate_limited`          | طلبات كثيرة. انتظر `Retry-After`.                                                                                                                                                                                                                         |
| 500  | `server_error`          | فشل الطلب. أعد المحاولة بـ `Idempotency-Key` نفسه.                                                                                                                                                                                                        |

يبدأ `path` بـ `menus.` ويشير إلى القيمة المرفوضة، مثل `menus.top.0.url` أو `menus.footer.1.links.10`، ويكون `menus` وحدها مع `too_large`. و`code` واحد من هذه.

| `code`             | السبب                                                                                                                  |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| `bad_url`          | `url` فارغ أو مرفوض أو طويل جداً.                                                                                      |
| `invalid`          | خطأ في الشكل: قائمة مكان كائن أو العكس، مثل `top` ليس array.                                                           |
| `too_many`         | أكثر من 12 عنصراً في الأعلى، أو 10 روابط فرعية، أو 3 مجموعات، أو 10 روابط في مجموعة. يذكر `path` أول عنصر يتجاوز الحد. |
| `top_required`     | `top` فارغ. لترك قائمة خاصة، أرسل `"menus": null`.                                                                     |
| `unknown_type`     | `type` ليس من الأنواع التسعة.                                                                                          |
| `unknown_key`      | قيمة `key` لمجموعة تذييل غير `quick_links` و`categories` و`null`.                                                      |
| `unknown_category` | `ref` ليس فئة من هذا المتجر.                                                                                           |
| `unknown_page`     | `ref` ليس صفحة منشورة من هذا المتجر.                                                                                   |
| `label_required`   | عنصر `url` بلا اسم، أو مجموعة تذييل بلا اسم وبلا `key`.                                                                |
| `label_too_long`   | اسم يتجاوز 40 حرفاً.                                                                                                   |
| `links_required`   | مجموعة تذييل بلا رابط.                                                                                                 |
| `duplicate_type`   | عنصر ثانٍ من `home` أو `products` أو `categories` أو `track` أو `contact` أو `cart` في `top`.                          |
| `nested_too_deep`  | `children` داخل رابط فرعي أو رابط تذييل، أو عنصر `categories` كرابط فرعي.                                              |
| `too_large`        | الوثيقة تتجاوز 16 KB.                                                                                                  |

```
{

  "error": {

    "code": "invalid_menus",

    "message": "Invalid menu at menus.top.0.url (bad_url); the caps and types are in GET /v1/store/menus.",

    "fields": [{"path": "menus.top.0.url", "code": "bad_url"}]

  },

  "meta": {"request_id": "c27e90b4f13a5d68", "api_version": "v1"}

}
```

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

* **القائمة العلوية**: 12 عنصراً، لكل واحد حتى 10 روابط فرعية.
* **التذييل**: 3 مجموعات من 10 روابط على الأكثر.
* **الاسم**: 40 حرفاً. **العنوان**: 500 بايت. **الوثيقة**: 16 KB.
* الحدود نفسها في كل الخطط.

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

يعطي خادم MCP، النسخة 1.9.0، المساعد الذكي أداتين للقائمة بالقواعد نفسها: `menus_get` تُرجع الوثيقة كلها مع `version` والحدود، و`menus_set` تكتبها مع `version` نفسها، و`change_undo` تتراجع عن كتابة.
