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

صفحات الهبوط

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

بقلم: Support

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

تُدار الأقسام (السلايدرات، الزوار الوهميون، العدّاد التنازلي…) من لوحة التحكم في v1؛ الواجهة البرمجية تُجري CRUD على السجل الأم فقط. تحديث v1.1 سيكشف CRUD الأقسام أيضًا.

حدود الخطة

الخطة

صفحات الهبوط (كل الحالات — المسودات محسوبة)

Free

0 (شراء لمرة واحدة: 1000 دج/مدى الحياة لكل منها)

Pro

3

Unlimited / Enterprise

غير محدود

الحد يُفرض من تدفّقي الإنشاء والنسخ في لوحة التحكم فقط، مع احتساب كل صفحة هبوط بما فيها المسودات. أما الواجهة البرمجية فلا تفرض شيئًا: POST /v1/landing-pages متبوعًا بـ /publish يتجاوز الحد بالكامل، وعلى خطة مدفوعة تُعرض الصفحات الزائدة حيّة على واجهة المتجر. أما صفحات الخطة المجانية فتبقى غير مرئية ما لم تكن الصفحة مشتراة (is_purchased).

GET /v1/landing-pages

اسرد صفحات الهبوط. ترقيم بالمؤشّر. مخزَّنة مؤقتًا لمدة 30 ثانية — تحقّق من ترويسة الاستجابة X-Cache: HIT|MISS. أما GET /v1/landing-pages/{id} فغير مُخزَّنة.

المصادقة: أي مفتاح منصة نشِط للمتجر (landing_pages:read غير مطبَّقة في v1؛ المفحوصة هي landing_pages:write فقط على نقاط الكتابة).

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

المعامل

النوع

ملاحظات

limit

int 1–200

الافتراضي 50

cursor

string

غير شفاف

status

active | draft

تصفية

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

الاستجابة 200

{
  "data": {
    "items": [
      {
        "id":            42,
        "title":         "Black T-Shirt — 30% off",
        "slug":          "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",
    "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"
  }
}

مرجع الحقول

الحقل

ملاحظات

status

active أو draft فقط بصرامة — لا توجد حالة archived لصفحات الهبوط.

language

ar أو fr أو en.

product_id

المنتج المرتبط، أو null. الصفحة بلا معرّف منتج لا تستطيع تسعير نموذج طلبها بشكل صحيح.

views

للقراءة فقط. تُحتسب في كل مرة تُشاهَد فيها الصفحة العامة؛ ولا تستطيع الواجهة البرمجية كتابتها ولا توجد طريقة لتصفيرها.

is_purchased

true بمجرد شراء الصفحة نهائيًا (1000 دج/مدى الحياة). على الخطة المجانية هذا ما يجعل الصفحة مرئية على واجهة المتجر.

section_count

في نقطة التفاصيل فقط — عدّ حيّ لأقسام الصفحة يُحسب مع كل طلب.

meta_title / meta_description

وسوم SEO. انظر الملاحظة تحت الإنشاء.

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

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

الجسم

الحقل

النوع

إلزامي

ملاحظات

title

string 1–255

slug

string

يُشتق تلقائيًا من title إن أُغفل. أما الـ slug الذي ترسله هنا فيُخزَّن بدون تطبيع — أرسل قيمة نظيفة

status

active | draft

الافتراضي draft. أي قيمة أخرى تُحوَّل بصمت إلى draft

language

ar | fr | en

الافتراضي ar. أي قيمة أخرى تُحوَّل بصمت إلى ar

product_id

int

يجب أن ينتمي إلى متجرك؛ الصفحة تربط بهذا المنتج

meta_title

string ≤ 255

عنوان SEO. إن أغفلته عبر الواجهة البرمجية يُخزَّن ويُرجَع كـ null (بخلاف نموذج لوحة التحكم الذي ينسخ title إليه). ومع ذلك تعرض الصفحة العامة title كبديل، فعنوان الصفحة الظاهر صحيح في الحالتين

meta_description

string

وصف 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"

معرّف من متجر آخر

الطلب

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}. صفحة الهبوط الجديدة بدون أقسام — أضفها من لوحة التحكم.

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 فيُطبَّع، بخلاف الإنشاء.

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 صراحةً.

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

اختصار: تحويل الحالة إلى active. يكافئ PATCH ... { status: "active" }.

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

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 } }.

هل أجاب هذا عن سؤالك؟