الطلبات هي قلب المنصة. كل طلب:
ينتمي إلى متجر واحد فقط (مقيّد بمفتاحك — لا يمكنك أبدًا الوصول إلى بيانات تاجر آخر بالخطأ).
له دورة حياة من 7 حالات.
مرتبط بعميل (يُزال التكرار باستخدام الهاتف داخل المتجر).
يحتوي على عنصر واحد أو أكثر، كل منها يمكن أن يحمل متغيرات. إضافات المنتج (add-ons، أي الحقول المخصصة المدفوعة) غير مدعومة في واجهة v1 — انظر الإضافات.
له حالة دفع (
pending,paid,refunded) مستقلّة عن حالة التسليم.
دورة الحياة {#lifecycle}
المسار الرئيسي pending → confirmed → processing → shipped → delivered قفزات مسموحة pending → processing confirmed → shipped إلغاء pending | confirmed | processing → cancelled (نهائية) إرجاع shipped | delivered → returned (نهائية)
وهذه خريطة الانتقالات التي تفرضها الواجهة البرمجية بالضبط، لكل حالة:
من | الحالات التالية المسموح بها |
|
|
|
|
|
|
|
|
|
|
| — (نهائية) |
| — (نهائية) |
الإلغاء مشروع فقط من pending وconfirmed وprocessing — الطلب الذي بلغ shipped أو delivered لم يعد يمكن إلغاؤه.
وتعديل الطلب بـ PATCH إلى الحالة التي هو عليها أصلًا هو عملية 200 بلا أثر.
الحالة | المعنى | المخزون |
| أُنشئ من الواجهة أو الـ API. ينتظر تأكيد التاجر. | لم يُحجز، إلا إذا كان المتجر يخصم المخزون فور وصول الطلب |
| أكّده التاجر (اتصل بالعميل، راجع السلة). | مُلتزَم (تم خصمه) |
| يُجهَّز / يُحضَّر للتسليم لشركة التوصيل. | مُلتزَم |
| سُلِّم لشركة التوصيل. | مُلتزَم |
| استلمه العميل ووقّع. | مُلتزَم |
| أُلغي الطلب — يعود المخزون إن كان مُلتزَمًا. | مُسترَد |
| أرجع العميل المنتج — يعود المخزون. | مُسترَد |
cancelled و returned حالتان نهائيتان — لا يمكن الخروج منهما.
POST /v1/orders — إنشاء طلب
أنشئ طلبًا جديدًا للمتجر المنادي. يستعمله الثيمات المخصصة والتطبيقات المحمولة والموزّعون وأي واجهة headless ترسل الطلبات من خادمها الخاص بدل استعمال checkout واجهة المتجر المدمجة.
المصادقة: مفتاح منصة بصلاحيتَي orders:write وorders:read. يتطلب Idempotency-Key. الرد يعيد قراءة الطلب، لذلك المفتاح الذي يملك orders:write وحدها يُحفَظ طلبه لكنه يتلقى 403 forbidden، وإعادة المحاولة بنفس Idempotency-Key تُعيد نفس 403.
يُنشأ الطلب بحالة pending. في الإعداد الافتراضي لا يُلتزَم المخزون عند الإنشاء: أول انتقال إلى حالة مُلتزِمة (confirmed أو processing أو shipped أو delivered) هو من يخصم المخزون، تمامًا كتدفّق اللوحة. الهدف من ذلك: ترك مساحة لفريق العمليات لتصفية الطلبات الوهمية والمكررة وغير المُجاب عنها قبل لمس المخزون. أما المتجر الذي اختار في الطلبات ← إعدادات العرض ← خصم المخزون الخيار فور وصول الطلب فيُخصم مخزونه لحظة إنشاء الطلب عبر الـ API.
الجسم
{
"customer": {
"name": "Sarra Benali",
"phone": "0555000111",
"email": "[email protected]",
"wilaya_id": 16,
"commune": "Bab Ezzouar",
"address": "12 Rue X, Apt 3"
},
"delivery": {
"type": "home",
"desk_id": null,
"desk_name": null
},
"items": [
{
"product_id": 26,
"quantity": 2,
"variants": [
{ "group_name": "Color", "option_name": "Red", "color_code": "#ff0000", "price_adjustment": 0 },
{ "group_name": "Size", "option_name": "L", "color_code": null, "price_adjustment": 200 }
]
}
],
"discount": 0,
"payment_method": "cod",
"notes": "Please call before delivery"
}
مرجع الحقول
customer (كائن، إلزامي)
الحقل | النوع | إلزامي | ملاحظات |
| string (1–255) | ✅ | الاسم الكامل |
| string | ✅ |
|
| string | null | إن وُجد، يُحفظ في سجل العميل | |
| int | ✅ | كود الولاية الجزائرية: من 1 إلى 58، أو من 1 إلى 69 في متجر مضبوط على 69 ولاية (اقرأ |
| string (1–100) | ✅ | نص حر، مثل "Bab Ezzouar" |
| string | شارع + شقة؛ يمكن تركه فارغًا للاستلام بالمكتب |
العملاء يُزال تكرارهم بالمتجر + رقم الهاتف. إن وُجد عميل بهذا الهاتف في متجرك، يُحدَّث (الاسم، الولاية، البلدية، العنوان، البريد) ويُعاد استخدامه. وإلا يُنشَأ سجل جديد.
delivery (كائن، اختياري)
الحقل | النوع | الافتراضي | ملاحظات |
|
|
|
|
| int | null | null | إلزامي إن كان |
| string | null | null | تسمية بشرية اختيارية |
items (مصفوفة، إلزامية، 1–50 سطرًا)
الحقل | النوع | إلزامي | ملاحظات |
| int | ✅ | يجب أن ينتمي لمتجرك (الـ IDs من متاجر أخرى تُرفض بـ |
| int، من 1 إلى 9999 | القيمة 1 إن لم تُرسَل | |
| مصفوفة من كائنات المتغيرات | انظر أدناه |
هام — تسعير معتمد على الخادم. أنت لا تُحدّد سعر السطر. يُستعمل دائمًا سعر المنتج الحالي في الكتالوج. إن أرسلت حقل price فهو يُتجاهل.
وprice_adjustment لكل متغيّر معتمد على الخادم أيضًا: لكل زوج (group_name, option_name) يطابق خيارًا حقيقيًا على المنتج، تستبدل DZBuild قيمة price_adjustment الخاصة بالكتالوج. قيمتك تبقى فقط للأزواج غير الموجودة في الكتالوج — وهو تساهُل مقصود للتكاملات القديمة — لذا فأي "خصم" سالب تخترعه يُهمَل بصمت لأي خيار حقيقي. عامل price_adjustment عند الإدخال على أنه معلوماتي فقط: أعِد إرسال القيمة كما وردت من GET /v1/products/{id} كي يطابق إجماليك المحسوب عند العميل إجمالي الخادم.
items[].variants (مصفوفة، اختيارية)
كل كائن متغيّر يصف خيارًا مختارًا لمجموعة متغيرات على المنتج:
الحقل | النوع | ملاحظات |
| string | مثل "Color" أو "Size" أو "Material" |
| string | مثل "Red" أو "L" أو "Cotton" |
| string | null | لون hex (لمتغيرات اللون فقط) |
| number | يُضاف للسعر الأساسي. تُستبدل بقيمة الكتالوج كلما وُجد زوج المجموعة/الخيار على المنتج — انظر ملاحظة التسعير أعلاه |
أرسل كائن متغيّر واحد لكل مجموعة مختارة على هذا السطر. فـ "تيشيرت أحمر مقاس L" يصبح إدخالين (واحد لـ Color/Red وآخر لـ Size/L). تعرضها DZBuild على صفحة الطلب في اللوحة كما لو اختارها العميل من الواجهة تمامًا.
للمنتجات التي تستخدم متغيرات لكل قطعة (مثل عرض "اشترِ 3 تيشيرتات، اختر لونًا لكل قطعة")، استخدم quantity = 1 لكل سطر وأنشئ سطرًا لكل قطعة — هذا أنظف ربط.
حقول المال على المستوى الأعلى
الحقل | النوع | الافتراضي | ملاحظات |
| number | يُتجاهَل إن أُرسل. يحسب الخادم تكلفة التوصيل من سعر المتجر للولاية ونوع التسليم، ومن قواعد الشحن المجاني ورسوم الوزن، بنفس طريقة الطلب المُنشأ من لوحة التحكم. لا تُحتسب أي تكلفة توصيل على طلبات | |
| number ≥ 0 | 0 | قيمة كود خصم، خصم يدوي… لا يتجاوز المجموع الفرعي مضافًا إليه الشحن |
| number | يُتجاهَل إن أُرسل؛ قيمته دائمًا 0 | |
|
| تلقائي | الافتراضي |
| string ≤ 1000 | null | ملاحظات العميل، تظهر على صفحة الطلب في اللوحة |
الإجمالي يُحسب على الخادم: subtotal + shipping_cost - discount (لا يقل عن 0)، حيث shipping_cost هو ما يحسبه الخادم نفسه. و subtotal نفسه = sum(items[].quantity × (price + Σ variants.price_adjustment)).
الحقل الوحيد الذي يُؤخذ من جسم طلبك هو discount. يجب أن يكون ≥ 0، ولا يتجاوز المجموع الفرعي مضافًا إليه الشحن، ولا يُقارَن بأكواد الخصم المعرَّفة في متجرك، لذلك يجب استدعاء POST /v1/orders من خادم موثوق فقط، ولا يجوز إطلاقًا استدعاؤه من كود متصفح أو تطبيق يمكن للزبون العبث به.
الطلب
curl -X POST 'https://api.dzbuild.app/v1/orders' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"customer": {
"name": "Sarra Benali",
"phone": "0555000111",
"wilaya_id": 16,
"commune": "Bab Ezzouar",
"address": "12 Rue X"
},
"items": [
{ "product_id": 26, "quantity": 1,
"variants": [
{ "group_name": "Duration", "option_name": "30 days", "price_adjustment": 0 }
]
}
],
"payment_method": "cod"
}'
الاستجابة 200
إنشاء الطلب يُرجع HTTP 200 وليس 201 — لا تتفرّع على رمز الحالة؛ تحقّق من data.id / data.order_number بدلًا من ذلك. الجسم بنفس شكل GET /v1/orders/{id} — معبّأ بالكامل بالإجماليات المحسوبة، وكتلة العميل المعيارية، وسطور العناصر التي أنشأتها للتو (مع متغيراتها).
صيغة order_number هي ORD-{store_id}-{YYYYMMDD}-{8 أحرف hex كبيرة}. وطلبات صفحات الهبوط تستعمل LP-{8 أحرف hex كبيرة}. أما الطلبات المُنشأة قبل 2026-06-02 فتحمل لاحقة قديمة من 4 أحرف hex، لذا يجب أن يقبل المحلّل الطولين.
الأخطاء
الكود | السبب |
| JSON تالف، أو جسم عبارة عن قيمة JSON مفردة مثل نص أو رقم بدل كائن (رأس Content-Type لا يُفحَص) |
| كائن |
| الاسم مفقود أو طويل جدًا |
| الهاتف لم يطابق التعبير النمطي |
| ولاية خارج نطاق المتجر؛ والمتجر المضبوط على 69 ولاية يرد بـ "customer.wilaya_id must be 1-69" |
| البلدية مفقودة أو طويلة جدًا |
| سلة فارغة |
| أكثر من 50 سطرًا (قسّمها لطلبات متعددة) |
|
|
| منتج من متجر آخر |
| كمية غير صالحة |
| نوع تسليم غير صالح |
| طريقة دفع غير صالحة |
| خصم سالب |
| سقف الخطة Free — انظر أدناه |
سقف الطلبات الشهري. الخطة Free محدودة بـ 30 طلبًا في الشهر التقويمي؛ أما Pro و Unlimited و Enterprise فبلا سقف. واسم خطة غير معروف يعود أيضًا إلى سقف 30/شهر المجاني. العدّاد شهري تقويمي ويشمل كل مصادر الطلبات (واجهة المتجر + صفحة الهبوط + لوحة التحكم + الواجهة البرمجية).
Idempotency
كل POST يجب أن يحمل رأس Idempotency-Key. إن أعدت نفس الطلب (نفس Idempotency-Key ونفس مفتاح API ونفس بايتات الجسم) خلال 24 ساعة نُعيد لك نفس الاستجابة مع Idempotency-Replay: 1، فيُنشأ الطلب مرة واحدة فقط. ردود الخطأ تُعاد هي أيضًا، ما عدا 429 و5xx، ونفس Idempotency-Key مع جسم مختلف يرد بـ 422 idempotency_key_reuse: أرسل الطلب المصحَّح بمفتاح جديد. انظر Idempotency.
# آمن للإعادة بالمفتاح نفسه
KEY="$(uuidgen)"
for i in 1 2 3; do
curl -X POST 'https://api.dzbuild.app/v1/orders' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
-d @order.json
done
# يُنشأ طلب واحد فقط لا غير
Webhook الذي يُطلق
إنشاء طلب يُطلق order.created لكل اشتراكات /v1/webhooks على هذا الحدث. انظر أحداث Webhook.
⚠️ تنبيه — /v1/webhooks ترى نشاط الواجهة البرمجية فقط
اشتراكات /v1/webhooks تُطلق فقط للتغييرات التي تمت عبر واجهة v1. أما الطلبات الموضوعة على واجهة المتجر أو على صفحة هبوط، وتغييرات الحالة من لوحة التحكم، فلا تُطلق order.created / order.confirmed / order.shipped.
للحصول على أحداث تغطي كل نشاط الطلبات، استعمل إضافة Webhooks (/dashboard/addons ← "Webhooks — Connect n8n, Make & Zapier"، تتطلب خطة Unlimited) وهي تلتقط كل طلب مهما كان مصدره — أو واصل الاستطلاع عبر GET /v1/orders?since=….
ما الذي يتخطّاه مسار الطلب عبر الواجهة البرمجية
الطلب المُنشأ عبر الواجهة البرمجية هو إدراج مبسّط. مقارنةً بطلب من واجهة المتجر أو صفحة هبوط أو لوحة التحكم، فهو لا:
يُنتج أي حدث Pixel أو CAPI لـ Meta أو TikTok.
يزيد عدّادي
total_orders/total_spentللعميل.يفحص قائمة حظر العملاء — فطلب العميل المحظور عبر الواجهة البرمجية يمرّ. اقرأ
is_bannedمن العملاء وارفضه من جانب عميلك إن احتجت ذلك.يطبّق فحوص مكافحة الإساءة التلقائية في checkout واجهة المتجر، ولا قواعد إضافة الحد الأدنى/الأقصى للكمية.
ومع ذلك يتلقى التاجر إشعار الطلب الجديد المعتاد، وهو نفس الإشعار الذي يُرسَل مع طلب واجهة المتجر.
ولاحظ أيضًا أن العميل الذي تُنشئه الواجهة البرمجية تُخزَّن فيه سلسلة customer.name كاملةً في first_name ويُترك last_name فارغًا؛ أما العميل الموجود مسبقًا والمطابَق برقم الهاتف فيُستبدَل فيه first_name فقط، ويُترك أي last_name موجود دون تغيير.
GET /v1/orders
اسرد الطلبات. ترقيم بالمؤشّر.
المصادقة: مفتاح بصلاحية orders:read (ضمن الصلاحيات الافتراضية). المفتاح الذي لا يملكها يتلقى 403 forbidden "Missing scope: orders:read".
معاملات الاستعلام
المعامل | النوع | ملاحظات |
| int 1–200 | الافتراضي 50 |
| string | غير شفاف |
| إحدى الحالات السبع | تصفية |
| سلسلة ISO 8601 |
|
| string | تطابق تام |
قيمة status غير الصالحة أو since غير القابلة للتحليل تُتجاهَل بصمت — فتحصل على القائمة غير المصفّاة لا على 400. ولا يوجد فلتر payment_status في v1؛ صفِّ من جانب العميل.
الطلب
curl 'https://api.dzbuild.app/v1/orders?status=pending&limit=20' \ -H "Authorization: Bearer $DZ_KEY"
الاستجابة 200
{
"data": {
"items": [
{
"id": 6894,
"order_number": "ORD-13-20260317-AD3C91F7",
"status": "pending",
"payment_status": "pending",
"payment_method": "cod",
"total": 1000,
"customer_name": "John Doe",
"customer_phone": "0555000000",
"wilaya_id": 16,
"commune": "Bab Ezzouar",
"delivery_type": "home",
"created_at": "2026-03-17 15:18:13"
}
],
"next_cursor": null,
"has_more": false
}
}
عرض القائمة مضغوط عمدًا (بدون عناصر ولا متغيرات). اطلب GET /v1/orders/{id} للتفاصيل الكاملة.
GET /v1/orders/{id}
تفاصيل كاملة مع سطور العناصر والمتغيرات وكتلة العميل.
المصادقة: مفتاح بصلاحية orders:read. المفتاح الذي لا يملكها يتلقى 403 forbidden.
الاستجابة 200
{
"data": {
"id": 6894,
"order_number": "ORD-13-20260317-AD3C91F7",
"store_seq": 644,
"status": "pending",
"payment_status": "pending",
"payment_method": "cod",
"customer": {
"id": 5578,
"name": "John Doe",
"phone": "0555000000",
"email": null,
"wilaya_id": 16,
"commune": "Bab Ezzouar",
"address": "12 Rue X"
},
"delivery": { "type": "home", "desk_id": null, "desk_name": null },
"shipment": {
"sent_to_delivery": true,
"sent_to_delivery_at": "2026-09-06 16:04:30",
"delivery_company": "colivraison",
"delivery_tracking": "TRK-0000000000",
"last_send_failure": null
},
"amounts": {
"subtotal": 1000,
"shipping_cost": 0,
"discount": 0,
"payment_fee": 0,
"total": 1000
},
"items": [
{
"id": 8421,
"product_id": 26,
"price": 1000,
"quantity": 1,
"variants": [
{ "order_item_id": 8421, "group_name": "Duration", "option_name": "30 days",
"color_code": null, "price_adjustment": "0.00" }
]
}
],
"created_at": "2026-03-17 15:18:13",
"updated_at": "2026-03-17 15:18:13"
}
}
حقول الشحن
store_seq هو رقم الطلب الظاهر في لوحة التحكم (#644)؛ إنشاء الطلب عبر الـ API يرقّمه قبل الرد، وفي الحالة النادرة التي يفشل فيها الترقيم يبقى null إلى أن يُملأ بعد قليل. يصبح shipment.sent_to_delivery صحيحًا (true) عندما تقبل شركة التوصيل الطرد، وdelivery_company هي الشركة (معرّفها النصي) وdelivery_tracking رقم التتبع. shipment.last_send_failure هو آخر إرسال مرفوض لهذا الطلب (at وprovider وmessage كما أرسلتها الشركة) أو null إن لم يفشل أي إرسال. ويكون دائمًا null متى صار sent_to_delivery صحيحًا، فالفشل السابق لا يظهر بعد إرسال ناجح. تُرجع نداءات الإنشاء والتحديث والإلغاء الكائن نفسه.
المتغيرات في الاستجابة
مصفوفة variants على كل عنصر هي المرجع لما اختاره العميل. كل إدخال يحمل order_item_id وgroup_name وoption_name وcolor_code (لمتغيرات اللون) وprice_adjustment (الإضافة لكل قطعة، وتُرجَع كسلسلة string في JSON لا كعدد). لعروض القطع المتعددة قد ترى عدة إدخالات متغيرات على نفس العنصر بتجميعات مختلفة — انظر ملاحظات القطع المتعددة أدناه.
ما لا تُرجعه استجابة التفاصيل
notesحقل للكتابة فقط في v1 — يُخزَّن على الطلب ويظهر في لوحة التحكم، لكنGET /v1/orders/{id}لا يُرجعه أبدًا.كما أن
product_nameوskuللعنصر وtotalالسطر تُلتقط عند الإنشاء لكنها لا تُرجَع أيضًا. ارجع إلىGET /v1/products/{id}إن احتجت الأسماء.
الإضافات (add-ons) غير مكشوفة {#add-ons-are-not-exposed}
إضافات المنتج (الحقول المخصصة المدفوعة التي يضبطها التاجر على منتج) ليس لها أي سطح في v1: لا يمكنك إرسالها في POST /v1/orders، وGET /v1/orders/{id} لا يُرجع أي إدخالات إضافات. أما الطلب الموضوع على واجهة المتجر مع إضافات فيُقرأ عبر الواجهة البرمجية وقيمة الإضافات مدمجة أصلًا في items[].price (وبالتالي في amounts.subtotal) — لكن بدون أي سطر إضافة ولا عنوان ولا نسبة ملف.
PATCH /v1/orders/{id} — تغيير الحالة
المصادقة: مفتاح منصة بصلاحيتَي orders:write وorders:read. يتطلب Idempotency-Key. بدون orders:read تتغير الحالة فعلًا، لكن الرد يكون 403 forbidden.
الجسم يجب أن يكون {"status": "<one of the 7>"}. نتحقق من الانتقال مقابل الجدول في دورة الحياة؛ وإلا نُرجع 400 مع الحالات التالية المسموح بها. وتعديل الطلب إلى حالته الحالية هو عملية 200 بلا أثر.
الطلب
curl -X PATCH 'https://api.dzbuild.app/v1/orders/6894' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: confirm-6894-$(date +%s)" \
-d '{"status": "confirmed"}'
تُرجع 200 وتفاصيل الطلب المحدّث. الانتقالات المتزامنة على نفس الطلب تُنفَّذ بالتسلسل: إن غيّر طلبٌ آخر الحالة قبلك، يفشل طلبك بنظافة بـ bad_request ("order status changed concurrently; retry") بدل أن يُطبَّق مرتين.
آثار المخزون الجانبية
حالات الالتزام بالمخزون هي confirmed وprocessing وshipped وdelivered.
غير مُلتزَم → مُلتزَم — يُخصم المخزون أول مرة يدخل فيها الطلب أيًا من تلك الحالات، بما في ذلك القفزة
pending → processing. ويرتفع كذلك عدّاد مبيعات المنتج.في متجر اختار في خصم المخزون الخيار فور وصول الطلب، خُصم المخزون عند إنشاء الطلب، فلا يخصم هذا الانتقال شيئًا إضافيًا.
مُلتزَم → cancelled / returned — يُسترَد المخزون.
الانتقالات الأخرى لا تمسّ المخزون.
المخزون لا يُتحقَّق منه: الخصم يتوقف عند الصفر، فلا يُرفض البيع الزائد أبدًا، وأي مشكلة في المخزون لا تُفشل تغيير الحالة ولا تتراجع عنه. ويتصرّف المخزون تمامًا كما يتصرّف مع الطلبات المُدارة من لوحة التحكم.
الأخطاء
الكود | السبب |
| الجسم لا يحوي |
| سلسلة غير صالحة |
| غير مسموح بآلة الحالات (الواجهة تُصدر |
| طلب آخر غيّر الحالة أثناء انتقالك. أعد المحاولة بمفتاح |
| معرّف الطلب غير معروف أو لمتجر آخر |
POST /v1/orders/{id}/cancel
نقطة مريحة — تكافئ تمامًا PATCH /v1/orders/{id} مع {"status":"cancelled"}. نفس جدول الانتقالات، بلا أي صلاحية إضافية. الإلغاء مشروع فقط من pending وconfirmed وprocessing؛ ومن shipped أو delivered ستحصل على 400 bad_request (فتلك الحالتان لا تنتقلان إلا إلى delivered / returned).
المصادقة: مفتاح منصة بصلاحيتَي orders:write وorders:read. يتطلب Idempotency-Key. بدون orders:read يُلغى الطلب فعلًا، لكن الرد يكون 403 forbidden.
curl -X POST 'https://api.dzbuild.app/v1/orders/6894/cancel' \ -H "Authorization: Bearer $DZ_KEY" \ -H "Idempotency-Key: cancel-6894-$(date +%s)"
POST /v1/orders/{id}/send-to-delivery
يسلّم الطلب لشركة التوصيل الخاصة بالمتجر، وهو نفس الإرسال الذي يقوم به الزر في لوحة التحكم. لا يمكن استرجاع الطرد بعد أن تستلمه الشركة، لذلك يمر كل إرسال بنداءين ويوافق التاجر على الأول.
المصادقة: مفتاح بصلاحية delivery:send. يتطلب Idempotency-Key. المفاتيح المُنشأة من الإعدادات ← واجهة API لا تحمل هذه الصلاحية وتتلقى 403 forbidden؛ أما التطبيق فيحصل عليها عندما يوافق التاجر عليها أثناء التثبيت.
الحقل | النوع | ملاحظات |
| string، اختياري | المعرّف النصي لشركة توصيل مرتبطة بالمتجر. اتركه لاستعمال شركة التوصيل الافتراضية للمتجر. الشركة غير المرتبطة تُرفض. |
| string | الرمز الذي أعاده النداء الأول، يُرسَل بعد موافقة التاجر |
نادِ بدون
confirm_token. الرد يكون422 confirmation_requiredومعهconfirm_token(يُستعمل مرة واحدة، صالح600ثانية) وactionوwill_change: العميل والهاتف والوجهة ونوع التسليم والإجمالي وشركة التوصيل. اعرض هذا الملخص على التاجر.بعد موافقته، أعد النداء بنفس
providerومعهconfirm_tokenوبمفتاحIdempotency-Keyجديد (المفتاح الأول مرتبط بالجسم الذي لا يحوي الرمز). الرمز المنتهي أو المستعمل أو الذي لم يعد يطابق الطلب يرد بـ422 confirmation_staleمع رمز جديد. الحقلconfirm: trueغير مقبول هنا.
عادةً يجري الإرسال في الخلفية ويرد بـ 202 مع queued: true. اقرأ GET /v1/orders/{id} إلى أن يصبح shipment.sent_to_delivery صحيحًا ومعه delivery_tracking، أو إلى أن يُظهر shipment.last_send_failure رفض الشركة. وإن لم يكن التشغيل في الخلفية متاحًا يجري الإرسال داخل النداء نفسه: 200 مع sent وprovider وtracking، أو 422 courier_refused مع رسالة الشركة. بعد أن تقبل الشركة الطرد، ينتقل الطلب من pending أو confirmed إلى processing، وهذا يخصم المخزون إن لم يكن قد خُصم. الطلبات من نوع التسليم pickup لا تُسلَّم أبدًا لشركة توصيل. والإرسال في الخلفية الذي يتوقف قبل الاتصال بالشركة، مثل إرسال طلب pickup أو شركة غير مرتبطة، يرد مع ذلك بـ 202 ولا يغيّر أيًا من حقلَي shipment.
الكود | السبب |
| المفتاح لا يملك |
| طلب غير معروف، أو طلب متجر آخر |
| الطلب عند شركة توصيل أصلًا؛ و |
| انظر الخطوتين أعلاه |
| رفضت الشركة الطرد أثناء إرسال داخل النداء |
| لنداءات شركات التوصيل ميزانية خاصة بكل متجر فوق حدود المعدل |
curl -X POST 'https://api.dzbuild.app/v1/orders/6894/send-to-delivery' \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: send-6894-approved" \
-d '{"confirm_token": "cft_REPLACE_WITH_TOKEN"}'
المتغيرات — مرجع كامل
تجعل المتغيرات منتجًا واحدًا يغطي خيارات متعددة (لون، حجم، خامة، سعة…). على الواجهة يضغط العملاء بطاقات المتغيرات لاختيار ما يريدون؛ على الواجهة البرمجية ترسل أنت الخيارات المختارة كجزء من الطلب.
نموذج المتغيرات
للمنتج 0 أو أكثر من مجموعات المتغيرات. للمجموعة 0 أو أكثر من الخيارات. كل خيار يمكن أن يحمل:
value(الاسم المعروض)color_code(لون hex، فقط لمجموعات اللون)price_adjustment(يُضاف للسعر الأساسي)image_id(صورة منتج مرتبطة كـ swatch)
اقرأ GET /v1/products/{id} لرؤية كل المجموعات والخيارات لمنتج:
{
"variants": [
{
"id": 11,
"name": "Color",
"type": "color",
"options": [
{ "id": 14, "value": "Red", "color_code": "#ff0000", "image_id": 28, "stock": 12 },
{ "id": 15, "value": "Blue", "color_code": "#0000ff", "image_id": 29, "stock": 5 }
]
},
{
"id": 12,
"name": "Size",
"type": "text",
"options": [
{ "id": 16, "value": "S", "stock": 10 },
{ "id": 17, "value": "M", "stock": 10 },
{ "id": 18, "value": "L", "stock": 5 }
]
}
]
}
منتج بـ 2 ألوان × 3 مقاسات لديه 6 تركيبات.
كيفية إرسال المتغيرات في POST /v1/orders
حوّل اختيار العميل إلى إدخال متغيّر واحد لكل مجموعة مختارة. لـ "تيشيرت أحمر مقاس L":
"variants": [
{ "group_name": "Color", "option_name": "Red", "color_code": "#ff0000", "price_adjustment": 0 },
{ "group_name": "Size", "option_name": "L", "color_code": null, "price_adjustment": 0 }
]
الأسماء التي ترسلها تُحفظ كما هي على الطلب — يجب أن تطابق ما أعاده GET /v1/products/{id}. price_adjustment يُضاف لسعر السطر (فيكون final_price = product.price + Σ price_adjustment)، لكن لأي زوج موجود في الكتالوج يستبدل الخادم قيمته الخاصة، فأرسل رقم الكتالوج.
المخزون لكل متغيّر
إن فعّل التاجر variant_stock_enabled على منتج، يحمل كل خيار متغيّر عداد مخزونه. اقرأه من options[].stock. الواجهة لا تمنعك من إنشاء طلب بـ quantity > stock؛ هذا قرار التاجر. ويُخصم المخزون عند أول انتقال إلى حالة مُلتزِمة (confirmed، processing، shipped، delivered)، أو عند الإنشاء في متجر يخصم المخزون فور وصول الطلب، ولا يُتحقَّق منه أبدًا: الخصم يتوقف عند الصفر، فيُسجَّل البيع الزائد بدل أن يُرفض.
المخزون لكل تركيبة
إن فُعّل combination_stock_enabled يُتتبع المخزون لكل تركيبة (Red+L = 5، Red+M = 8…). يُرجعها GET /v1/products/{id} في combinations[] (لكل واحدة id وsku وstock وis_active وخياراتها options) مع combination_count؛ وتتوقف القائمة عند 300 عنصر، ويُخبرك combinations_truncated إن قُطعت. انظر المنتجات. ويتحرك مخزون التركيبات في نفس اللحظة التي يتحرك فيها باقي مخزون الطلب.
المتغيرات المتدرجة (Cascading)
تتيح إضافة Cascading Variants للتاجر جعل خيارات المجموعة B تعتمد على اختيار المجموعة A (مثل "علامة → موديل" — اختيار "Apple" للعلامة يُظهر فقط "iPhone 15" / "iPhone 14" للموديل). وهذه الإضافة تتطلب خطة Pro.
لا يكشف GET /v1/products/{id} أي معلومات عن التدرّج — فخريطة الأب/الابن لا تُطبَّق إلا في واجهة المتجر وفي لوحة التحكم. لا يستطيع عميلك اكتشاف قواعد التدرّج عبر الواجهة البرمجية في v1: ثبّتها في الكود أو اقرأها من لوحة التحكم. وإرسال تركيبة غير صالحة يُنشئ الطلب رغم ذلك (لا نمنعه) — لكن التاجر سيرفضه عند التأكيد.
متغيرات الصورة-نص
بعض التجار يستخدمون نوع image_text للمتغيرات (صورة مصغرة بجانب اسم الخيار). على الواجهة البرمجية ما زلت ترسل group_name + option_name — الصورة شأن واجهة فقط ولا تكون جزءًا من حمولة الطلب.
عروض القطع المتعددة
إن أطلق التاجر عرض "اشترِ 3، اختر ألوانًا"، يختار العميل متغيرًا مختلفًا لكل قطعة. على الواجهة البرمجية:
"items": [
{ "product_id": 26, "quantity": 1,
"variants": [{ "group_name": "Color", "option_name": "Red" }] },
{ "product_id": 26, "quantity": 1,
"variants": [{ "group_name": "Color", "option_name": "Blue" }] },
{ "product_id": 26, "quantity": 1,
"variants": [{ "group_name": "Color", "option_name": "Green" }] }
]
ثلاثة سطور منفصلة، كل واحد quantity = 1. هكذا تعرض صفحة الطلب لون كل قطعة بنظافة.
أنماط شائعة
"إرسال طلب من واجهة React مخصصة"
تبني واجهة React/Vue/Next.js تتحدث مع الواجهة البرمجية بدلًا من ثيمات DZBuild المضمّنة. التدفّق:
اقرأ
GET /v1/products+GET /v1/products/{id}لعرض الكتالوج.يضيف المستخدم العناصر إلى سلة من جانب العميل.
لعرض سعر التوصيل قبل إتمام الطلب، اقرأ أسعار المتجر عبر
GET /v1/shipping/rates(صلاحيةshipping:read). أما الطلب نفسه فيُحتسب عليه دائمًا ما يحسبه الخادم.POST
/v1/ordersبالسلة وكتلة العميل؛ وamounts.shipping_costفي الرد هو تكلفة التوصيل المحتسبة.أعرض على العميل
order_numberوصفحة "شكرًا".استطلع
GET /v1/orders?since=…لمتابعة تقدّم التنفيذ. فأحداثorder.confirmed/order.shippedفي/v1/webhooksلا تُطلق إلا عندما تتغيّر الحالة عبر الواجهة البرمجية — وتأكيد التاجر من لوحة التحكم لا يُنتج أي حدث.
انظر دليل الثيمات والواجهات المخصصة لخطوات كاملة.
"مزامنة الطلبات الجديدة مع CRM كل دقيقة"
استخدم فلتر since:
curl 'https://api.dzbuild.app/v1/orders?since=2026-04-30T20:00:00Z&limit=200' \ -H "Authorization: Bearer $DZ_KEY"
الاستطلاع هو الأداة الصحيحة هنا. فاشتراك /v1/webhooks على order.created لا يغطي إلا الطلبات التي أنشأها تكاملك أنت عبر الواجهة البرمجية — أما طلبات واجهة المتجر وصفحات الهبوط فلا تُطلقه أبدًا، ولذلك لا يمكنه أن يحلّ محل مسح since. انظر Webhooks.
"تأكيد كل الطلبات المعلّقة لعميل واحد"
PHONE="0555000000"
curl -sS "https://api.dzbuild.app/v1/orders?status=pending&customer_phone=$PHONE" \
-H "Authorization: Bearer $DZ_KEY" \
| jq -r '.data.items[].id' \
| while read OID; do
curl -sS -X PATCH "https://api.dzbuild.app/v1/orders/$OID" \
-H "Authorization: Bearer $DZ_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: confirm-$OID" \
-d '{"status":"confirmed"}'
done