# أقسام الصفحة الرئيسية

تخطيط الصفحة الرئيسية هو القائمة المرتّبة للأقسام التي يعرضها المتجر في صفحته الرئيسية. لكل قسم نوع وإعدادات. يمكن إضافة عشرة أنواع في كل قالب: `category-products` و`featured` و`categories` و`banner` و`image-with-text` و`rich-text` و`trust-badges` و`testimonials` و`faq` و`video`. ويقدّم قالب مبني على الأقسام مثل `atlas` أيضاً `hero` و`product-grid`. يعطي `types` في استجابة `GET` إعدادات كل نوع. كل كتابة في هذه الصفحة تظهر في المتجر بمجرد أن تُرجع استجابتها.

هذه النقاط ليست `GET /v1/store/home-sections` التي تقرأ مفاتيح الصفحة الرئيسية في قوالب Digital وAriana وPrestige. وهذه المفاتيح مشروحة في آخر هذه الصفحة.

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

* تحتاج `GET` إلى `store:read`، وتحتاج الكتابات إلى `store:write`. مفاتيح التاجر تحمل الاثنتين.
* تحتاج `POST` و`PATCH` و`DELETE` إلى `Idempotency-Key`. وهو اختياري مع `PUT`. انظر [Idempotency](https://dzbuild.com/ar/ar/api-docs/idempotency.md).
* رقم الفئة يأتي من `GET /v1/categories` التي تحتاج إلى `products:read`.

## كائن القسم[​](#كائن-القسم "رابط مباشر إلى كائن القسم")

| الحقل       | النوع  | ملاحظات                                                                                            |
| ----------- | ------ | -------------------------------------------------------------------------------------------------- |
| `id`        | int    | ثابت ما دام القسم موجوداً. القسم الذي يعود بالتراجع يأخذ رقماً جديداً.                             |
| `type`      | string | إحدى قيم `type` المذكورة في `types` ضمن `GET /v1/store/home-layout`.                               |
| `settings`  | object | كل إعدادات النوع، والقيم الافتراضية مملوءة.                                                        |
| `is_active` | bool   | `false` تُخفي القسم عن الزبائن وتُبقيه في القائمة.                                                 |
| `available` | bool   | `false` عندما لا يعود قالب المتجر يملك هذا النوع. يبقى القسم كما خُزّن، ويمكن لأي كتابة أن تُبقيه. |

### إعدادات `category-products`[​](#إعدادات-category-products "رابط مباشر إلى إعدادات-category-products")

| الإعداد         | النوع    | الافتراضي | القواعد                                                                                                                    |
| --------------- | -------- | --------- | -------------------------------------------------------------------------------------------------------------------------- |
| `category`      | رقم فئة  | `0`       | فئة من هذا المتجر. `0` تعني بلا فئة، وعندها لا يعرض القسم شيئاً للزبائن. رقم فئة من متجر آخر يُرجع `422 invalid_settings`. |
| `title`         | text     | `""`      | حتى 80 حرفاً، ويُزال منه HTML. الفارغ يُظهر اسم الفئة.                                                                     |
| `count`         | range    | `8`       | من 4 إلى 12. الرقم خارج هذا المجال يُنقل إلى أقرب حدّ.                                                                     |
| `layout`        | select   | `grid`    | `grid` أو `slider`.                                                                                                        |
| `show_view_all` | checkbox | `true`    | رابط إلى صفحة الفئة.                                                                                                       |

الفئة التي لا منتجات فيها لا تعرض شيئاً للزبائن كذلك. اقرأ قواعد أي نوع من `settings_schema` الخاص به بدل كتابتها في برنامجك: قائمة الأنواع تتبع قالب المتجر.

### صيغ الإعدادات[​](#صيغ-الإعدادات "رابط مباشر إلى صيغ الإعدادات")

| نوع الإعداد | القيمة المقبولة                                                                                                                                                                                                         |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `category`  | رقم من `GET /v1/categories`، أو `0` لعدم الاختيار.                                                                                                                                                                      |
| `link`      | `#anchor`، أو مسار `/path` داخل المتجر، أو عنوان `http://` أو `https://`، أو رابط `tel:` أو `mailto:`، حتى 500 حرف، أو `""`. العنوان المرسل بلا بادئته، مثل `wa.me/213...`، يُحفظ مع `https://` في أوله.                |
| `youtube`   | رابط فيديو YouTube أو معرّفه ذو 11 حرفاً. يُحفظ المعرّف.                                                                                                                                                                |
| `image`     | مسار صورة رُفعت من لوحة التحكم لهذا المتجر، `/uploads/banners/{store_id}/...`، أو `""`. لا يمكن رفع الصور عبر الواجهة البرمجية حالياً: يرفع التاجر الصورة أولاً من إعدادات القسم في لوحة التحكم، ثم تُرجع `GET` مسارها. |

### متى يرى الزبائن القسم[​](#متى-يرى-الزبائن-القسم "رابط مباشر إلى متى يرى الزبائن القسم")

القسم الذي لم يُملأ محتواه بعد يُخزَّن وتُرجع الكتابة `2xx`، لكن الزبائن لا يرونه حتى يُملأ:

| النوع               | يراه الزبائن عندما                                                                    |
| ------------------- | ------------------------------------------------------------------------------------- |
| `category-products` | تكون `category` فئة من المتجر فيها منتجات.                                            |
| `featured`          | تكون في `source` المختار منتجات.                                                      |
| `categories`        | تكون في المتجر فئة فيها منتجات، أو أي فئة عندما تكون `show_empty` بقيمة `true`.       |
| `banner`            | تُملأ `image`.                                                                        |
| `image-with-text`   | تُملأ `image` مع `title` أو `text`.                                                   |
| `rich-text`         | يُملأ `title` أو `text`.                                                              |
| `trust-badges`      | دائماً. الشارتان 1 و2 الفارغتان تُظهران سطري التوصيل والدفع عند الاستلام الافتراضيين. |
| `testimonials`      | يُملأ `tN_text` واحد على الأقل.                                                       |
| `faq`               | يُملأ `qN` واحد على الأقل مع `aN` الخاص به.                                           |
| `video`             | تحمل `video` معرّف فيديو YouTube.                                                     |

لا تتغيّر `rendered` لهذا السبب: فهي تقول إن كان القالب يعرض الأقسام المخزّنة، لا إن كان قسم بعينه ظاهراً. في قالب مبني على الأقسام (`atlas`) لا تحلّ الأقسام المحفوظة محل الصفحة الرئيسية للقالب إلا ما دامت تتضمن قسم `product-grid` ظاهراً، وتبقى `rendered` بقيمة `false` حتى ذلك الحين؛ وقبل ذلك يرى الزبائن الصفحة الأصلية للقالب، ولا تعرض `GET` إلا الأقسام المحفوظة، لا أقسام القالب نفسه.

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

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

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

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

```
curl 'https://api.dzbuild.app/v1/store/home-layout' \

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

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

```
{

  "data": {

    "theme": "starter",

    "rendered": true,

    "max_sections": 25,

    "cap": 25,

    "version": "9c1e04b7a2d35f68",

    "sections": [

      {

        "id": 412,

        "type": "category-products",

        "settings": {

          "category": 57,

          "title": "",

          "count": 8,

          "layout": "grid",

          "show_view_all": true

        },

        "is_active": true,

        "available": true

      },

      {

        "id": 415,

        "type": "category-products",

        "settings": {

          "category": 61,

          "title": "Nos parfums",

          "count": 10,

          "layout": "slider",

          "show_view_all": false

        },

        "is_active": false,

        "available": true

      }

    ],

    "types": [

      {

        "type": "category-products",

        "name": {"ar": "منتجات فئة", "fr": "Produits d'une catégorie"},

        "description": {"ar": "اعرض منتجات فئة واحدة في شبكة أو شريط تمرير.", "fr": "Affichez les produits d'une catégorie en grille ou en carrousel."},

        "icon": "bi-grid-3x3-gap",

        "limit": 12,

        "settings_schema": [

          {"id": "category", "type": "category", "default": 0, "label": {"ar": "الفئة", "fr": "Catégorie"}},

          {"id": "title", "type": "text", "max": 80, "default": "", "label": {"ar": "العنوان (إذا تركته فارغاً يظهر اسم الفئة)", "fr": "Titre (si vide, le nom de la catégorie s'affiche)"}},

          {"id": "count", "type": "range", "min": 4, "max": 12, "default": 8, "label": {"ar": "عدد المنتجات", "fr": "Nombre de produits"}},

          {"id": "layout", "type": "select", "options": ["grid", "slider"], "default": "grid", "label": {"ar": "طريقة العرض", "fr": "Affichage"}, "option_labels": {"ar": ["شبكة", "شريط تمرير"], "fr": ["Grille", "Carrousel"]}},

          {"id": "show_view_all", "type": "checkbox", "default": true, "label": {"ar": "زر عرض الكل", "fr": "Lien « Voir tout »"}}

        ]

      }

    ]

  },

  "meta": {"request_id": "8f2c1a9d4b7e6035", "api_version": "v1"}

}
```

| الحقل          | المعنى                                                                                                                                                                                                 |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `theme`        | مفتاح قالب المتجر.                                                                                                                                                                                     |
| `rendered`     | `false` عندما لا يعرض قالب المتجر الحالي أقسام الصفحة الرئيسية. تبقى الأقسام محفوظة وتظهر من جديد مع قالب يعرضها. وفي قالب مبني على الأقسام لا تكون `true` إلا ما دام قسم `product-grid` ظاهر محفوظاً. |
| `max_sections` | 25، أقصى عدد من الأقسام تحمله صفحة رئيسية واحدة.                                                                                                                                                       |
| `cap`          | عدد الأقسام الذي تسمح به خطة المتجر: 3 في الخطة المجانية أو خطة منتهية، و25 ابتداءً من Pro.                                                                                                            |
| `version`      | بصمة التخطيط المخزَّن. أرسلها في `version` مع `PUT` لرفض تخطيط تغيّر منذ هذه القراءة.                                                                                                                  |
| `sections`     | الأقسام بترتيب عرضها، ومعها الأقسام المخفية.                                                                                                                                                           |
| `types`        | الأنواع التي يمكن إضافتها في هذا القالب، مع `name` و`description` و`icon` و`limit` (أقصى عدد من أقسام هذا النوع في الصفحة) و`settings_schema`. يعرض المثال أعلاه نوعاً واحداً منها.                    |

### القراءة بعد الكتابة[​](#القراءة-بعد-الكتابة "رابط مباشر إلى القراءة بعد الكتابة")

عبر `api.dzbuild.app` يُخدَم كل طلب `GET` حديثًا: طلب `GET` المُرسَل مباشرة بعد الكتابة يُرجع التخطيط الجديد. ونادرًا ما تحتاج إليه، لأن كل كتابة تُرجع القائمة كاملة بترتيب العرض مع `version` الجديدة.

## `POST /v1/store/home-layout/sections`[​](#post-v1storehome-layoutsections "رابط مباشر إلى post-v1storehome-layoutsections")

يضيف قسماً واحداً.

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

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

| الحقل      | النوع  | إلزامي | ملاحظات                                                            |
| ---------- | ------ | ------ | ------------------------------------------------------------------ |
| `type`     | string | نعم    | قيمة `type` من `types`.                                            |
| `settings` | object | لا     | الإعدادات التي لا ترسلها تأخذ القيم الافتراضية للنوع.              |
| `position` | int    | لا     | 0 يضع القسم في الأعلى، و24 آخر مكان. بدونه يُضاف القسم في النهاية. |

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

```
curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/sections' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: hs-add-sacs-1" \

  -d '{"type": "category-products", "settings": {"category": 64, "layout": "slider"}, "position": 0}'
```

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

```
{

  "data": {

    "section": {

      "id": 418,

      "type": "category-products",

      "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true},

      "is_active": true,

      "available": true

    },

    "sections": [

      {"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},

      {"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},

      {"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 10, "layout": "slider", "show_view_all": false}, "is_active": false, "available": true}

    ],

    "version": "e27a90c4b1f36d05",

    "change_id": 90231,

    "rendered": true

  },

  "meta": {"request_id": "3b7d0e5a9c14f862", "api_version": "v1"}

}
```

## `PATCH /v1/store/home-layout/sections/{id}`[​](#patch-v1storehome-layoutsectionsid "رابط مباشر إلى patch-v1storehome-layoutsectionsid")

يغيّر قسماً واحداً. الإعدادات التي ترسلها تُدمج فوق الإعدادات المخزّنة. أرسل `settings` أو `is_active` أو كليهما.

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

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

| الحقل       | النوع  | إلزامي | ملاحظات                                                                    |
| ----------- | ------ | ------ | -------------------------------------------------------------------------- |
| `settings`  | object | لا     | تُدمج فوق الإعدادات المخزّنة.                                              |
| `is_active` | bool   | لا     | `false` تُخفي القسم، و`true` تُظهره.                                       |
| `replace`   | bool   | لا     | مع `settings`، القيمة `true` تُرجع كل إعداد لا ترسله إلى قيمته الافتراضية. |

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

```
curl -X PATCH 'https://api.dzbuild.app/v1/store/home-layout/sections/415' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: hs-415-show-1" \

  -d '{"settings": {"count": 6}, "is_active": true}'
```

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

للاستجابة الحقول نفسها التي لاستجابة `POST`: `section` (القسم بعد التغيير)، و`sections`، و`version`، و`change_id`، و`rendered`.

```
{

  "data": {

    "section": {

      "id": 415,

      "type": "category-products",

      "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false},

      "is_active": true,

      "available": true

    },

    "sections": [

      {"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},

      {"id": 412, "type": "category-products", "settings": {"category": 57, "title": "", "count": 8, "layout": "grid", "show_view_all": true}, "is_active": true, "available": true},

      {"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}

    ],

    "version": "51d8c3e06fa2b974",

    "change_id": 90232,

    "rendered": true

  },

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

}
```

## `DELETE /v1/store/home-layout/sections/{id}`[​](#delete-v1storehome-layoutsectionsid "رابط مباشر إلى delete-v1storehome-layoutsectionsid")

يحذف قسماً واحداً.

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

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

```
curl -X DELETE 'https://api.dzbuild.app/v1/store/home-layout/sections/412' \

  -H "Authorization: Bearer $DZ_KEY" \

  -H "Idempotency-Key: hs-del-412-1"
```

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

```
{

  "data": {

    "deleted": true,

    "id": 412,

    "sections": [

      {"id": 418, "type": "category-products", "settings": {"category": 64, "title": "", "count": 8, "layout": "slider", "show_view_all": true}, "is_active": true, "available": true},

      {"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}, "is_active": true, "available": true}

    ],

    "version": "0f6b2d9e84a1c357",

    "change_id": 90233,

    "rendered": true

  },

  "meta": {"request_id": "71e4b08c3a5d9f26", "api_version": "v1"}

}
```

## `POST /v1/store/home-layout/reorder`[​](#post-v1storehome-layoutreorder "رابط مباشر إلى post-v1storehome-layoutreorder")

يحدّد ترتيب العرض. تذكر `ids` كل أقسام الصفحة مرة واحدة بالضبط، ومعها الأقسام المخفية.

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

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

```
curl -X POST 'https://api.dzbuild.app/v1/store/home-layout/reorder' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: hs-order-2" \

  -d '{"ids": [415, 418]}'
```

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

تحمل الاستجابة `sections` بالترتيب الجديد، و`version`، و`change_id`، و`rendered`. الرقم الذي ليس في الصفحة يُرجع `404 section_not_found`. والرقم الناقص أو المكرر يُرجع `422 invalid_order`.

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

يستبدل التخطيط كله بالقائمة التي ترسلها، بترتيبها.

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

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

| الحقل      | النوع  | إلزامي | ملاحظات                                                                                                                                       |
| ---------- | ------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `sections` | array  | نعم    | 25 عنصراً على الأكثر، كل عنصر `{id?, type, settings?, is_active?}`. القائمة الفارغة تحذف كل الأقسام.                                          |
| `version`  | string | لا     | قيمة `version` من آخر قراءة لك. إذا تغيّر التخطيط منذها، يُرجع النداء `409 write_conflict` مع `sections` و`version` الحاليتين ولا يكتب شيئاً. |

كيف يُقرأ كل عنصر:

* العنصر الذي يحمل `id` يُبقي ذلك القسم. ويجب أن يكون `type` هو النوع الحالي للقسم.
* العنصر الذي بلا `id` ينشئ قسماً.
* كل قسم في الصفحة غير موجود في القائمة يُحذف.
* `settings` هو الكائن كاملاً: الإعداد الذي تتركه يعود إلى قيمته الافتراضية. أرسل الإعدادات كاملة لكل قسم تُبقيه.
* قيمة `is_active` الافتراضية `true`.

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

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

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: hs-replace-7" \

  -d '{

    "version": "0f6b2d9e84a1c357",

    "sections": [

      {"id": 415, "type": "category-products", "settings": {"category": 61, "title": "Nos parfums", "count": 6, "layout": "slider", "show_view_all": false}},

      {"type": "category-products", "settings": {"category": 57}}

    ]

  }'
```

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

تحمل الاستجابة `sections` و`version` و`change_id` و`rendered`. القسم 418 لم يُرسل، لذلك يُحذف. وإعادة إرسال التخطيط الذي قرأته كما هو تُرجع `change_id: null`.

مع `Idempotency-Key`، إعادة المحاولة بالمفتاح نفسه والجسم نفسه تُرجع الاستجابة المخزّنة لمدة 24 ساعة مع `Idempotency-Replay: 1`، والمفتاح نفسه مع جسم آخر يُرجع `422 idempotency_key_reuse`. وبدون مفتاح يُنفَّذ النداء في كل مرة، وهذا آمن: إرسال القائمة نفسها مرتين يترك التخطيط نفسه.

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

كل كتابة تُرجع `change_id`، أو `null` عندما لا تغيّر شيئاً. يُرجع `POST /v1/changes/{change_id}/undo` الصفحة الرئيسية كلها كما كانت قبل ذلك التغيير.

* يمكن التراجع عن إضافة قسم أيضاً: التراجع يزيله. في الموارد الأخرى يرفض التراجع أي تغيير أنشأ شيئاً.
* إذا تغيّرت الصفحة الرئيسية بعد ذلك التغيير، عبر الواجهة البرمجية أو من لوحة التحكم، يُرجع التراجع `409 layout_changed` ولا يكتب شيئاً. اقرأ التخطيط واكتب ما تريده مباشرة.
* القسم الذي يعود بعد حذفه يأخذ رقماً جديداً.
* التراجع نفسه يُسجَّل تغييراً مستقلاً، `undo_change_id`، ويمكنك التراجع عنه بدوره. التراجع عن تراجعٍ عن حذف يُرجع `409 layout_changed`، لأن القسم عاد برقم جديد.
* التغييرات التي يحفظها التاجر من لوحة التحكم لا تُسجَّل، فلا يمكن التراجع عنها عبر الواجهة البرمجية.
* يعرض `GET /v1/changes?entity=store.home_layout` تغييرات تخطيط الصفحة الرئيسية، الأحدث أولاً، بصلاحية `store:read`.
* لا يستطيع رمز التطبيق المثبّت قراءة التغييرات ولا التراجع عنها: يُرجع `GET /v1/changes` والتراجع `403 forbidden` (`Apps cannot use this endpoint`). وتبقى استجابات الكتابة تحمل `change_id`.
* لا تحمل استجابة التراجع التخطيط. اقرأه من جديد عبر `GET /v1/store/home-layout`؛ القراءة تُخدَم حديثًا.

يحتاج التراجع إلى `store:write` وإلى `Idempotency-Key`.

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

  -H "Authorization: Bearer $DZ_KEY" \

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

```
{

  "data": {

    "undone": true,

    "change_id": 90231,

    "entity": "store.home_layout",

    "undo_change_id": 90240

  },

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

}
```

التغيير الذي تتراجع عنه مرة ثانية يُرجع `409 already_undone`.

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

| HTTP | الرمز                   | السبب                                                                                                                                                                                                                                                                                                                                    |
| ---- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400  | `bad_request`           | الجسم ليس كائن JSON، أو حقل من نوع خاطئ (`type` غائب، أو `settings` ليس كائناً، أو `is_active` أو `replace` ليس قيمة منطقية، أو `position` خارج 0 إلى 24، أو `ids` ليس مصفوفة من أرقام الأقسام، أو `version` ليس نصاً)، أو رقم القسم في المسار ليس رقماً موجباً، أو `Idempotency-Key` غائب أو غير صالح مع `POST` أو `PATCH` أو `DELETE`. |
| 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 سارية.                                                                                                                                                                          |
| 403  | `plan_required`         | الكتابة تترك أقساماً أكثر مما تسمح به الخطة. يحمل الخطأ `plan` و`cap`.                                                                                                                                                                                                                                                                   |
| 404  | `section_not_found`     | لا يوجد قسم بهذا الرقم في الصفحة.                                                                                                                                                                                                                                                                                                        |
| 409  | `write_conflict`        | وصلت كتابة أخرى قبلك، أو `version` المرسلة مع `PUT` ليست الحالية. عندما يحمل الخطأ `sections` و`version` فهما التخطيط الحالي: أعد المحاولة انطلاقاً منهما. وإلا فاقرأ التخطيط وأعد المحاولة.                                                                                                                                             |
| 409  | `layout_changed`        | للتراجع فقط: تغيّرت الصفحة الرئيسية بعد هذا التغيير.                                                                                                                                                                                                                                                                                     |
| 409  | `already_undone`        | للتراجع فقط: سبق التراجع عن هذا التغيير.                                                                                                                                                                                                                                                                                                 |
| 413  | `payload_too_large`     | الجسم أكبر من 1 ميغابايت.                                                                                                                                                                                                                                                                                                                |
| 422  | `invalid_settings`      | رُفضت قيمة. تذكر `fields` كل إعداد مرفوض في القسم، مثل `settings.category`. ومع `PUT` تذكر إعدادات أول قسم مرفوض فقط، مثل `sections.2.settings.layout`، وتشمل أيضاً `id` ليس في الصفحة (`sections.N.id`) وقسماً مُبقى أُرسل بنوع آخر (`sections.N.type`). وتذكر `message` المسارات أيضاً.                                                |
| 422  | `invalid_section_type`  | النوع غير موجود أو لا يمكن إضافته في هذا القالب. تعطي `fields` المسار.                                                                                                                                                                                                                                                                   |
| 422  | `limit_reached`         | أكثر من 25 قسماً، أو أكثر من `limit` لنوع واحد. يحمل الخطأ `limit`، إلا عندما ترسل `PUT` أكثر من 25 عنصراً.                                                                                                                                                                                                                              |
| 422  | `invalid_order`         | `ids` في إعادة الترتيب ينقصها قسم أو تكرر قسماً.                                                                                                                                                                                                                                                                                         |
| 422  | `no_changes`            | `PATCH` بلا `settings` ولا `is_active`.                                                                                                                                                                                                                                                                                                  |
| 422  | `idempotency_key_reuse` | استُعمل `Idempotency-Key` نفسه مع جسم آخر.                                                                                                                                                                                                                                                                                               |
| 429  | `rate_limited`          | طلبات كثيرة، ومنها أكثر من 30 كتابة على تخطيط الصفحة الرئيسية في الدقيقة للمتجر. انتظر المدة في `Retry-After`.                                                                                                                                                                                                                           |
| 429  | `too_many_concurrent`   | أكثر من 5 كتابات على تخطيط الصفحة الرئيسية تعمل في الوقت نفسه للمتجر. أعد المحاولة بعد ثوانٍ.                                                                                                                                                                                                                                            |
| 500  | `server_error`          | فشل الطلب. أعد المحاولة بالـ `Idempotency-Key` نفسه.                                                                                                                                                                                                                                                                                     |

هكذا تبدو استجابة `invalid_settings`.

```
{

  "error": {

    "code": "invalid_settings",

    "message": "Invalid value at settings.category: category not found in this store; accepted values are in settings_schema of GET /v1/store/home-layout",

    "fields": [{"path": "settings.category", "code": "invalid"}]

  },

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

}
```

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

* **25 قسماً** في الصفحة الرئيسية (`max_sections`).
* **حدّ الخطة** (`cap`): 3 أقسام في الخطة المجانية أو خطة منتهية، و25 ابتداءً من Pro. الأقسام المخفية تُحسب. المتجر الذي تجاوز حدّه بعد نزول خطته يُبقي أقسامه ويستطيع تعديلها وإخفاءها وترتيبها وحذفها. الكتابة التي تترك أقساماً أكثر من الحدّ وأكثر مما كانت تُرجع `403 plan_required`.
* **لكل نوع**: لكل نوع `limit` في `types`، وهو 12 لـ `category-products`.
* **الإعدادات**: 8 كيلوبايت لكل قسم بعد الترميز. النص الأطول يُقصّ عند `max` الخاص بالإعداد.
* **الجسم**: 1 ميغابايت.
* **الكتابات**: 30 في الدقيقة و5 في الوقت نفسه لكل متجر، فوق حدّ المتجر في الدقيقة. انظر [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md).

## مفاتيح الصفحة الرئيسية في Digital وAriana وPrestige[​](#مفاتيح-الصفحة-الرئيسية-في-digital-وariana-وprestige "رابط مباشر إلى مفاتيح الصفحة الرئيسية في Digital وAriana وPrestige")

تبني قوالب Digital وAriana وPrestige صفحتها الرئيسية من كتل ثابتة. ومجموعة أقدم من المفاتيح تُظهر هذه الكتل أو تخفيها وتحدّد عناوينها وفئاتها وبنراتها. يقرأ `GET` و`PATCH /v1/store/home-sections` هذه المفاتيح ويغيّرانها. وهي محفوظة بمعزل عن تخطيط الصفحة الرئيسية المشروح أعلاه، فالكتابة في أحدهما لا تغيّر الآخر أبداً.

| القالب          | الحقول التي يقرؤها                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Digital وAriana | `show_hero_slider`، `hero_slides`، `show_sidebar_widget`، `sidebar_widget_title`، `sidebar_widget_category_id`، `show_category_cards`، `show_top_sellers`، `top_sellers_title`، `show_popular_by_category`، `popular_by_category_title`، `show_promo_banners`، `banner_1_*` و`banner_2_*` (`title` و`subtitle` و`button_text` و`button_link` و`image`)، `show_multi_column_lists`، من `column_1_title` إلى `column_4_title`، من `column_1_category_id` إلى `column_4_category_id`، `section_order` |
| Prestige        | `show_testimonials` و`testimonials_title` و`testimonials`                                                                                                                                                                                                                                                                                                                                                                                                                                          |

لا يقرأ أي قالب آخر هذه المفاتيح: في قالب آخر تُحفظ الكتابة وتُرجع `200`، ولا يرى الزبائن أي تغيير. والمفتاح الذي لم يُحفظ أبداً يغيب عن الاستجابة، وعندها يُظهر Digital وAriana كتلته بينما يخفي Prestige آراء العملاء. يحدّد `section_order` ترتيب كتل Digital وAriana بالقيم `hero_slider` و`category_cards` و`top_sellers` و`popular_by_category` و`promo_banners` و`multi_column_lists`. والكتلة التي لا تَرِد في هذه القائمة لا تظهر.

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

**المصادقة:** مفتاح منصة بصلاحية `store:read`. وكما في `GET /v1/store/home-layout`، تُخدَم الاستجابة حديثًا في كل نداء.

```
curl 'https://api.dzbuild.app/v1/store/home-sections' \

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

```
{

  "data": {

    "theme": "digital",

    "settings": {"show_top_sellers": 1, "top_sellers_title": "Meilleures ventes", "column_1_category_id": 57}

  },

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

}
```

لا يحمل `settings` إلا الحقول التي حُفظت. والمتجر الذي لم يحفظ أي حقل يُرجع `"settings": []`.

### `PATCH /v1/store/home-sections`[​](#patch-v1storehome-sections "رابط مباشر إلى patch-v1storehome-sections")

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

أرسل الحقول التي تريد تغييرها فقط: تحتفظ البقية بقيمها، وتُتجاهل الحقول غير المعروفة. تُحفظ حقول `show_*` على شكل `1` أو `0`. ويأخذ `*_category_id` فئة من فئات هذا المتجر، و`0` يُفرغه. يُنزع الفراغ من طرفي النص ثم يُقصّ عند 500 حرف، و`testimonials_title` عند 200. ويقبل `banner_1_button_link` و`banner_2_button_link` رابط `https://` أو `http://` أو `mailto:` أو `tel:`، أو `/path`، أو `#anchor`. ويحتفظ `testimonials` بـ 24 عنصراً كحد أقصى، لكل منها `name` و`comment` و`stars` من 1 إلى 5.

```
curl -X PATCH 'https://api.dzbuild.app/v1/store/home-sections' \

  -H "Authorization: Bearer $DZ_KEY" \

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

  -H "Idempotency-Key: hs-top-sellers-off-1" \

  -d '{"show_top_sellers": false, "column_1_category_id": 61}'
```

```
{

  "data": {

    "updated": ["show_top_sellers", "column_1_category_id"],

    "settings": {"show_top_sellers": 0, "top_sellers_title": "Meilleures ventes", "column_1_category_id": 61}

  },

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

}
```

يسرد `updated` الحقول التي كُتبت، ويحمل `settings` كل الحقول المحفوظة بعد الكتابة. ولا تحمل الاستجابة `change_id`: يسرد `GET /v1/changes?entity=store.home_sections` هذه التغييرات، و`POST /v1/changes/{change_id}/undo` يتراجع عن أحدها. التراجع عن أول كتابة لمفتاح لا يُرجع قيمته الافتراضية: يعود مفتاح `show_*` بالقيمة `0` ويعود `section_order` بالقيمة `[]`، وهذا يخفي في Digital وAriana تلك الكتلة، أو كل الكتل. وللرجوع إلى القيم الافتراضية، أرسل `1` أو قائمة `section_order` كاملة عبر `PATCH`.

| HTTP | الرمز                   | السبب                                                                                                                                                           |
| ---- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400  | `bad_request`           | الجسم ليس JSON، أو `Idempotency-Key` غائب أو غير صالح.                                                                                                          |
| 403  | `forbidden`             | `Missing scope: store:read` أو `Missing scope: store:write`، أو `API access requires an active Enterprise plan` لمفتاح تاجر متجره ليس على خطة Enterprise سارية. |
| 422  | `no_writable_fields`    | لا يحمل الجسم أيّاً من الحقول التي تقبلها نقطة النهاية هذه.                                                                                                     |
| 422  | `invalid_category`      | `*_category_id` ليس فئة من فئات هذا المتجر.                                                                                                                     |
| 422  | `invalid_url`           | رابط زر يستعمل مخططاً آخر، مثل `javascript:`.                                                                                                                   |
| 422  | `idempotency_key_reuse` | استُعمل `Idempotency-Key` نفسه مع جسم آخر.                                                                                                                      |

معنى `401` و`402` و`413` و`500` هو نفسه في كتابات تخطيط الصفحة الرئيسية. أما `429 rate_limited` فيأتي فقط من الحدود العامة في الدقيقة المشروحة في [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md): حدود كتابات تخطيط الصفحة الرئيسية لا تنطبق هنا.
