إنتقل إلى المحتوى الرئيسي

صفحات الهبوط

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

يمكن بناء الأقسام (السلايدرات، نماذج الطلب، الزوار الوهميون، العدّاد التنازلي…) عبر الواجهة البرمجية بنقاط الأقسام المشروحة أدناه، أو من لوحة التحكم.

حدود الخطة​

الخطةصفحات الهبوط (كل الحالات — المسودات محسوبة)
Free0 (شراء لمرة واحدة: 1000 دج/مدى الحياة لكل منها)
Pro3
Unlimited / Enterpriseغير محدود

يُطبَّق الحد على كل طرق الإنشاء، بما فيها الواجهة البرمجية، مع احتساب كل صفحة هبوط بما فيها المسودات. على متجر بلغ حدّه، يُرجع POST /v1/landing-pages (وPOST /v1/landing-pages/generate) الخطأ 403 limit_reached. ولا يستطيع متجر على الخطة المجانية إنشاء صفحة إلا ما دام لديه شراء صفحة هبوط لم يُستعمل بعد؛ ويُعلِّم POST /v1/landing-pages تلك الصفحة بـ is_purchased: true، وهذا ما يجعلها مرئية على واجهة المتجر.

GET /v1/landing-pages​

اسرد صفحات الهبوط. ترقيم بالمؤشّر. تُخدَم حديثًا في كل نداء، مثل GET /v1/landing-pages/{id}.

المصادقة: مفتاح منصة بصلاحية landing_pages:read، وتحتاجها GET /v1/landing-pages/{id} أيضًا. المفتاح الذي لا يحملها يتلقى 403 forbidden.

معاملات الاستعلام​

المعاملالنوعملاحظات
limitint 1–200الافتراضي 50
cursorstringغير شفاف
statusactive | draftتصفية

القيمة غير المعروفة في status تُتجاهَل فتُرجَع كل الصفحات بدل 400.

الاستجابة 200​

{
"data": {
"items": [
{
"id": 42,
"title": "Black T-Shirt — 30% off",
"slug": "black-tshirt-30-off",
"public_url": "https://your-store.example.com/landing/black-tshirt-30-off",
"status": "active",
"language": "ar",
"product_id": 26,
"views": 1543,
"is_purchased": false,
"created_at": "2026-03-01 10:00:00",
"updated_at": "2026-03-15 14:22:11"
}
],
"next_cursor": null,
"has_more": false
}
}

GET /v1/landing-pages/{id}​

تفاصيل مع section_count.

{
"data": {
"id": 42,
"title": "Black T-Shirt — 30% off",
"slug": "black-tshirt-30-off",
"public_url": "https://your-store.example.com/landing/black-tshirt-30-off",
"status": "active",
"language": "ar",
"product_id": 26,
"views": 1543,
"is_purchased": false,
"meta_title": "Black T-Shirt — Cotton 200gsm — 30% off | DZBuild",
"meta_description": "Limited-time offer on our cotton black t-shirt.",
"section_count": 7,
"created_at": "2026-03-01 10:00:00",
"updated_at": "2026-03-15 14:22:11"
}
}

مرجع الحقول​

الحقلملاحظات
statusactive أو draft فقط بصرامة — لا توجد حالة archived لصفحات الهبوط.
languagear أو fr أو en.
public_urlالعنوان الحي للصفحة: عنوان المتجر (نطاقه المخصّص متى صار فعّالًا، وإلا النطاق الفرعي)، ثم /landing/ ثم الـ slug. يكون null ما دام المتجر بلا عنوان. استعمله كما هو بدل بناء الرابط بنفسك.
product_idالمنتج المرتبط، أو null. القسم الذي يستقبل الطلبات (order_form وorder_button وproduct_offers) يحتاج إليه أو إلى settings.product_id الخاص به. بعد ضبطه، يمكن لـ PATCH تغييره إلى منتج آخر لكن لا يمكن إرجاعه إلى null.
viewsللقراءة فقط. تُحتسب في كل مرة تُشاهَد فيها الصفحة العامة؛ ولا تستطيع الواجهة البرمجية كتابتها ولا توجد طريقة لتصفيرها.
is_purchasedtrue بمجرد شراء الصفحة نهائيًا (1000 دج/مدى الحياة). على الخطة المجانية هذا ما يجعل الصفحة مرئية على واجهة المتجر.
section_countفي نقطة التفاصيل فقط — عدّ حيّ لأقسام الصفحة يُحسب مع كل طلب.
meta_title / meta_descriptionوسوم SEO. انظر الملاحظة تحت الإنشاء.

POST /v1/landing-pages — إنشاء​

المصادقة: مفتاح منصة بصلاحيتَي landing_pages:write وlanding_pages:read. تقرأ الاستجابة الصفحة بعد حفظها، فمع landing_pages:write وحدها تُحفَظ الصفحة ويُرجع النداء 403 forbidden؛ والأمر نفسه مع PATCH و/publish. يتطلب Idempotency-Key.

الجسم​

الحقلالنوعإلزاميملاحظات
titlestring، من 1 إلى 255 بايت✅الحد يحسب البايتات لا الحروف: الحرف العربي يأخذ 2 بايت، فالعنوان العربي يتوقف عند نحو 127 حرفًا
slugstringيُشتق تلقائيًا من title إن أُغفل. أما الـ slug الذي ترسله هنا فيُخزَّن بدون تطبيع — أرسل قيمة نظيفة
statusactive | draftالافتراضي draft. أي قيمة أخرى تُحوَّل بصمت إلى draft
languagear | fr | enالافتراضي ar. أي قيمة أخرى تُحوَّل بصمت إلى ar
product_idintيجب أن ينتمي إلى متجرك؛ الصفحة تربط بهذا المنتج
meta_titlestring ≤ 255عنوان SEO. إن أغفلته عبر الواجهة البرمجية يُخزَّن ويُرجَع كـ null (بخلاف نموذج لوحة التحكم الذي ينسخ title إليه). ومع ذلك تعرض الصفحة العامة title كبديل، فعنوان الصفحة الظاهر صحيح في الحالتين
meta_descriptionstringوصف SEO

تُجعل الـ slugs فريدة داخل متجرك بإلحاق -2 و-3 وهكذا. وإن كان أساس الـ slug فارغًا فيُستعمل landing- متبوعًا بـ 6 أحرف hex.

الأخطاء​

الكودالسبب
bad_request "Body must be valid JSON"Content-Type خاطئ أو JSON تالف
bad_request "title is required (1-255 chars)"العنوان مفقود أو طويل جدًا
bad_request "product_id N does not belong to this store"معرّف من متجر آخر
limit_reached (403)بلغ المتجر حد صفحات الهبوط في خطته (المسودات محسوبة). على الخطة المجانية: لم يبقَ شراء صفحة هبوط غير مستعمل

الطلب​

curl -X POST 'https://api.dzbuild.app/v1/landing-pages' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"title": "Black T-Shirt — 30% off",
"language": "ar",
"product_id": 26,
"status": "draft"
}'

تُرجع 200 (وليس 201) وبنفس شكل GET /v1/landing-pages/{id}. صفحة الهبوط الجديدة بدون أقسام: أضفها بنقاط الأقسام المشروحة أدناه. فحص النشر لا يجري عند الإنشاء، لذا أنشئ الصفحة كـ draft وانشرها بعد إضافة أقسامها؛ فالصفحة المُنشأة بـ status: active تظهر للزبائن فارغة.

PATCH /v1/landing-pages/{id}​

تحديث جزئي.

يتحقّق PATCH بصرامة أكبر من الإنشاء: status غير صالح يُرجع 400 bad_request ("status must be active or draft")، وlanguage غير صالح يُرجع 400 ("language must be ar, fr, or en") بدل التحويل الصامت. ويجب أن يبقى title بين 1 و255 بايت. أما الـ slug المُرسَل في PATCH فيُطبَّع، بخلاف الإنشاء. ضبط status على active يُشغّل فحص النشر (انظر /publish أدناه). وبعد أن يصير للصفحة منتج، يُرجع product_id: null الخطأ 422 product_required؛ أرسل معرّف منتج آخر لتغيير المنتج.

curl -X PATCH 'https://api.dzbuild.app/v1/landing-pages/42' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "title": "Black T-Shirt — Spring promo" }'

تغيير العنوان يُعيد توليد slug تلقائيًا فقط إن لم تُرسل slug صراحةً. وعندما يتغيّر الـ slug، بتغيير العنوان أو صراحةً، يبقى الرابط القديم يعمل ويُحوِّل إلى الرابط الجديد.

الأقسام​

تعرض الصفحة أقسامها من الأعلى إلى الأسفل. قراءة الأقسام تحتاج إلى landing_pages:read، وكتابتها تحتاج إلى landing_pages:write، وكل كتابة تحتاج إلى Idempotency-Key.

النقطةالجسمالاستجابة
GET /v1/landing-page-section-types200: section_types، كل عنصر فيها type مع default_settings الخاصة به
GET /v1/landing-pages/{id}/sections200: landing_page_id وsections بترتيب العرض (حتى 500، بدون ترقيم)
POST /v1/landing-pages/{id}/sectionssection_type (أو type)، وsettings اختياري201: الـ section الجديد، مُضافًا في آخر الصفحة
POST /v1/landing-pages/{id}/sections/batchsections: حتى 30 كائنًا فيها type (أو section_type) وsettings اختياري201: الـ sections الجديدة. الكل أو لا شيء: عنصر واحد خاطئ يمنع حفظ الجميع
POST /v1/landing-pages/{id}/sections/reordersections: كل معرّفات أقسام الصفحة، كل واحد مرة واحدة، بالترتيب الجديد200: الأقسام بترتيبها الجديد
PATCH /v1/landing-pages/{id}/sections/{section_id}settings، وreplace اختياري200: الـ section بعد التحديث
DELETE /v1/landing-pages/{id}/sections/{section_id}200: { "deleted": true, "id": 901, "landing_page_id": 42 }

يحمل القسم id وsection_type وsort_order وsettings. والاستجابات التي تعيد قراءة الصفحة (القائمة وإعادة الترتيب وPATCH) تحمل أيضًا created_at وupdated_at. الأنواع الـ 14 هي image وorder_form وorder_button وfree_text وcontact_button وcountdown وfake_visitors وspecial_offer وprice_display وproduct_offers وcustom_form وimage_carousel وannouncement_bar وtestimonials. اقرأ GET /v1/landing-page-section-types قبل الكتابة، حتى تطابق مفاتيح إعداداتك ما تعرضه الصفحة.

  • الإعدادات التي ترسلها تُدمج فوق القيم الافتراضية للنوع، فنداء واحد يكفي لإنشاء قسم مضبوط بالكامل. ومع PATCH تُدمج فوق الإعدادات المخزّنة؛ أرسل "replace": true لتبدأ من جديد من القيم الافتراضية للنوع. الكائنات المتداخلة تُدمج مفتاحًا بمفتاح، أما القوائم مثل slides وitems وoffers وfields فتُستبدل كاملة. ولا يمكن تغيير نوع القسم.
  • قسم order_form أو order_button أو product_offers يحتاج إلى منتج: product_id الخاص بالصفحة أو settings.product_id الخاص به. بدونه يُرجع النداء 422 landing_page_has_no_product. وsettings.product_id من متجر آخر يُرجع 422 validation_error.
  • حقول نموذج الطلب show_name وshow_phone وshow_wilaya تُحفَظ دائمًا بقيمة true في أي قسم يحملها.
  • قائمة slides تقبل 20 عنصرًا على الأكثر، وقائمة items تقبل 30 على الأكثر (422 too_many_items). ولا يجوز أن تتجاوز الإعدادات المُرمَّزة 262144 بايت (422 settings_too_large). والنوع غير المعروف يُرجع 422 invalid_section_type.
  • عند الكتابة، الصفحة التي ليست من متجرك تُرجع 404 landing_page_not_found (القائمة والفحص يُرجعان 404 not_found)، والقسم غير الموجود على الصفحة يُرجع 404 section_not_found. وقائمة إعادة الترتيب التي تكرّر قسمًا أو تُغفله تُرجع 422 validation_error.
  • تظهر تغييرات الأقسام في GET /v1/changes. يمكن التراجع عن التعديل والحذف وإعادة الترتيب بـ POST /v1/changes/{id}/undo، والقسم المحذوف الذي يعود بالتراجع يأخذ رقمًا جديدًا. أما إضافة قسم فلا يمكن التراجع عنها: احذفه بدل ذلك.
curl -X POST 'https://api.dzbuild.app/v1/landing-pages/42/sections/batch' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"sections": [
{ "type": "announcement_bar" },
{ "type": "order_form" }
]
}'

GET /v1/landing-pages/{id}/check​

يُبلغ عمّا سيجده الزبون معطّلًا في الصفحة. المصادقة: landing_pages:read.

تحمل الاستجابة landing_page_id وstatus وproduct_id وsections (عدد الأقسام المفحوصة) وpublishable وblocked_by (أول رسالة مانعة، أو null) وproblems. لكل مشكلة code وseverity (blocking أو warning) وmessage؛ والمشاكل المرتبطة بقسم واحد تحمل أيضًا section_id.

الكودالخطورةالمعنى
empty_pageblockingالصفحة بلا أقسام، فتظهر فارغة
order_form_without_productblockingقسم يستقبل الطلبات، لكن لا الصفحة ولا القسم يحدّدان منتجًا، فتُسجَّل الطلبات بـ 0 دج
section_product_not_foundblockingقسم يشير إلى منتج ليس في متجرك
no_order_formwarningلا شيء في الصفحة يستقبل الطلبات
multiple_order_formswarningيظهر أكثر من order_form أو order_button واحد
variants_need_page_productwarningقسم يحدّد منتجًا بمتغيرات والصفحة بلا منتج. أدوات اختيار المتغيرات لا تظهر إلا من منتج الصفحة نفسه، فاضبط product_id على الصفحة

يُرفض النشر ما دامت هناك مشكلة مانعة (انظر أدناه).

POST /v1/landing-pages/{id}/publish​

اختصار: تحويل الحالة إلى active. يكافئ PATCH ... { status: "active" }، ويُرفض بالطريقة نفسها: ما دام GET /v1/landing-pages/{id}/check يُبلغ عن مشكلة مانعة، يُرجع النداء 422 page_not_publishable ويحمل الخطأ قائمة problems. أما التعديلات التي لا ترسل status فلا تمرّ بهذا الفحص، حتى على صفحة منشورة.

curl -X POST 'https://api.dzbuild.app/v1/landing-pages/42/publish' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: publish-42-$(date +%s)"

POST /v1/landing-pages/generate​

يبني صفحة هبوط من أحد منتجاتك بالذكاء الاصطناعي. يُرجع 202 فورًا مع مهمة تتابعها؛ وتستغرق العملية نحو دقيقتين. المصادقة: صلاحية ai:generate. المفاتيح المُنشأة من لوحة التحكم أو عبر POST /v1/keys والتطبيقات الخارجية لا تحملها وتتلقى 403 forbidden؛ أما اتصالات Claude وChatGPT وDZBuild Copilot فتحملها. يتطلب Idempotency-Key.

الحقلالنوعإلزاميملاحظات
titlestring✅3 أحرف على الأقل، ويُقطع عند 255
product_idint✅منتج نشِط من متجرك فيه صورة واحدة على الأقل
descriptionstringوصف موجز للصفحة، يُقطع عند 2000 حرف
languagear | fr | enالافتراضي ar
sizemedium | tallالافتراضي medium. تكلفة medium هي 20 نقطة ذكاء اصطناعي، وتكلفة tall هي 45

تحمل الاستجابة task_id وsize وcredits_charged وeta_seconds وpoll. تُخصم النقاط عند بدء العملية وتُعاد إذا فشلت أو تجاوزت المهلة. الأخطاء: 400 bad_request (العنوان مفقود أو أقصر من 3 أحرف)، 402 quota_exceeded (نقاط الذكاء الاصطناعي غير كافية)، 403 limit_reached (حد صفحات الهبوط في الخطة، مع limit وcurrent)، 409 already_processing (توليد واحد لكل متجر في الوقت نفسه)، 422 product_required أو product_not_found أو product_has_no_image، 429 rate_limited أو too_many_concurrent، 503 provider_unavailable (بدون خصم أي نقاط).

تابِع GET /v1/landing-pages/generate/{task_id} بصلاحية landing_pages:read. تُرجع task_id وstatus (processing أثناء بناء الصفحة، ثم completed أو failed) وlanding_page_id بمجرد وجود الصفحة وcurrent_step وerror. العملية التي تبقى قيد المعالجة بعد 10 دقائق تُعلَّم failed بالخطأ timeout عند المتابعة التالية، وتُعاد نقاطها.

DELETE /v1/landing-pages/{id}​

حذف نهائي. وتُحذف أقسام الصفحة معها.

curl -X DELETE 'https://api.dzbuild.app/v1/landing-pages/42' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Idempotency-Key: del-42"

الاستجابة: { "data": { "deleted": true, "id": 42 } }.

هذه الصفحة لأدوات الذكاء الاصطناعيعرض بصيغة Markdownفتح في ChatGPTفتح في Claude