إن كنت تبني متاجر للعملاء — وكالات، فريلانسرز، شركات تنفيذ، مشغّلو منصات سوق — فإن DZBuild API مصمّم ليكون عمودك العملياتي.
هذا الدليل لك إن كان أيٌّ مما يلي ينطبق:
تدير 5+ متاجر DZBuild لعملاء مختلفين.
تُفوتر العملاء لكل طلب أو شهريًا وتحتاج إشارة استخدام موثوقة.
تبني ثيمات مخصصة أو واجهات مخصصة نيابة عن العملاء.
تبيع DZBuild كطبقة علامة بيضاء ("MyAgency Commerce, مدعومة من DZBuild").
تريد سكربتة عمليات بالجملة: استيراد منتجات، تحديث أسعار، تأكيد طلبات.
كيف يستخدم الموزّعون الـ API فعلًا
إعداد موزّع نموذجي:
┌─────────────────────────┐
│ back-office / │
│ لوحة وكالتك │
│ (كودك، واجهتك) │
└──────────┬──────────────┘
│ Bearer dzpk_live_…
▼
┌─────────────────────────────┐
│ api.dzbuild.app/v1/* │
└──────────┬──────────────────┘
▼
┌──────────┬─────────┬──────────┐
│ متجر A │ متجر B │ متجر C │ ← العملاء الذين تديرهم
└──────────┴─────────┴──────────┘
كل عميل له متجر DZBuild خاص (حساب التاجر، خطته، طلباته). تحمل مفتاح API لكل متجر وتنسّق كل شيء — إعداد، تخصيص، تقارير — من لوحة وكالتك.
نموذج المفاتيح للموزّعين
لا يوجد نوع مفتاح "موزّع" خاص، ولا مفتاح عابر للمتاجر. كل موزّع يعمل بـ مفتاح منصة واحد لكل متجر عميل، وPOST /v1/keys مقيّد بصرامة بالمتجر الذي ينتمي إليه المفتاح المنادي أصلًا.
أ) يُنشئ العميل أول مفتاح للمتجر ثم يُسلّمه إليك
تُنشأ المفاتيح من لوحة تحكم التاجر عبر الإعدادات ← واجهة API (/dashboard/api) بواسطة مالك المتجر (خطة Enterprise، وبحد أقصى 3 مفاتيح نشطة لكل متجر) — فإدماج عميل جديد يعني أن يُنشئ العميل مفتاحًا ويسلّمه لك، أو تُنشئانه معًا. وما دامت المرحلة التجريبية قائمة، يستطيع دعم DZBuild أيضًا إصدار المفاتيح وتسجيلها. تُخزّن أسرار العملاء في back-office لديك مشفّرة، وكل عملية ضد العميل X تستخدم مفتاح العميل X.
الإيجابيات: موافقة واضحة، العميل يملك المفتاح ويستطيع إلغاءه. السلبيات: احتكاك في التأهيل — خطوة بشرية لكل متجر.
ب) تُنشئ بنفسك مفاتيح إضافية لمتجر لديك مفتاح له أصلًا
ما إن يكون لديك مفتاح واحد لمتجر، يمكنك إنشاء المزيد لذلك المتجر نفسه دون مراسلة أحد:
curl -X POST 'https://api.dzbuild.app/v1/keys' \
-H "Authorization: Bearer $CLIENT_X_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"type":"platform","name":"agency-reporting"}'
# HTTP 200 → { "data": { "key_id", "bearer_token", "signing_secret", "note" } }
يرث المفتاح الجديد فئة تحديد المعدل وعَلَم البرنامج التجريبي من المنادي. مفيد لفصل مهام التقارير عن مهام الكتابة على المتجر نفسه.
ما هو غير موجود: لا توجد أي تهيئة "مظلة وكالة"، على أي خطة، تُتيح لك إنشاء مفاتيح لمتاجر لا تملك مفتاحًا لها أصلًا. وتأهيل متجر عميل جديد يبدأ دائمًا بمالك المتجر: إما أن يُنشئ أول مفتاح من الإعدادات ← واجهة API ويُسلّمه إليك، وإما أن يثبّت تطبيقًا تسجّله أنت من الإعدادات ← المطورون ويوافق على صلاحياته، فيحصل تطبيقك على رمز خاص به لذلك المتجر (ويحتاج التطبيق موافقة DZBuild قبل أن يستطيع تجار آخرون تثبيته).
استيراد منتجات بالجملة
تبني كتالوجًا لعميل؟ استخدم حلقة CSV → API:
import requests, csv, uuid, osKEY = os.environ['DZ_KEY_CLIENT_X']
HEADERS = {
'Authorization': f'Bearer {KEY}',
'Content-Type': 'application/json',
}with open('products.csv') as f:
for row in csv.DictReader(f):
body = {
'name': row['name'],
'price': float(row['price']),
'compare_price': float(row['compare_price']) if row['compare_price'] else None,
'sku': row['sku'],
'description': row['description'],
'stock_quantity': int(row['stock']),
'track_stock': True,
'status': 'active',
}
r = requests.post(
'https://api.dzbuild.app/v1/products',
headers={**HEADERS, 'Idempotency-Key': str(uuid.uuid4())},
json=body,
)
if r.ok: # 200، وليس 201: فـ POST /v1/products يُرجع 200
print(f"OK {row['sku']} → id {r.json()['data']['id']}")
else:
print(f"FAIL {row['sku']}: {r.text}")
خطآن يجب تفاديهما في تلك الحلقة، وكلاهما موجود في النسخة الساذجة:
لا تفحص
201. فـPOST /v1/productsيُرجع 200؛ وفحص== 201يطبع FAIL لكل منتج أنشأه بنجاح.لا تستعمل
uuid4()لمفتاح Idempotency. فمفتاح جديد في كل تشغيل يعني أن إعادة التشغيل تُنشئ نسخًا مكررة بدل إعادة تشغيل الاستجابة. استعمل مفتاحًا حتميًا مثلimport-{client}-{sku}-{run}— وهو ما تقوله النصيحة أدناه أيضًا، فأبقِ الشيفرة والنصيحة متسقتين.
نصائح:
استخدم مفتاح Idempotency حتمي (مثل
import-{client}-{sku}-{run}) فتقفز الإعادات على الصفوف المستوردة. وتُخزَّن استجابة كل مفتاح 24 ساعة، بما فيها أخطاء 4xx (أما 5xx و 429 فلا تُخزَّنان، فأعد المحاولة بالمفتاح نفسه)؛ غيّر المفتاح بعد إصلاح طلب سيّئ.كل متجر عميل تديره عبر الـ API يجب أن يكون على خطة Enterprise سارية (فالواجهة البرمجية حصرية لخطة Enterprise)، وهي تسمح بـ 600 طلب/دقيقة لكل متجر (مشتركة بين جميع مفاتيحه) — لذا يظل إنشاء ~1000 منتج يستغرق دقيقتين تقريبًا من الزمن الفعلي. سِر بنحو نصف السقف لتترك هامشًا؛ وتجاوزه يُرجع
429 rate_limitedمع ترويسةRetry-After. ولاحظ أن صور المنتجات لها ميزانيتها الخاصة الأضيق — 10 في الدقيقة لكل متجر — فعمليات الاستيراد بالجملة المصحوبة بالصور تنضبط وتيرتها بها لا بالحد العام.يمكن إضافة صور المنتجات عبر الـ API من رابط https عام بـ
POST /v1/products/{id}/images(حتى 20 صورة لكل منتج، و20 ميغابايت لكل ملف)؛ ولا يوجد رفع مباشر للملفات.
عمليات طلبات بالجملة
⚠️ تنبيه — limit=200 هو السقف، لا "كل الطلبات"
limit مقيّد بـ 200. والسكربتان أدناه يتوقفان عند ذلك ولا يخبرانك بشيء عمّا فاتهما. وكل استجابة قائمة تحمل has_more و next_cursor — كرّر عليهما:
CURSOR=""
while :; do
PAGE=$(curl -sS "https://api.dzbuild.app/v1/orders?status=pending&limit=200${CURSOR:+&cursor=$CURSOR}" \
-H "Authorization: Bearer $KEY")
echo "$PAGE" | jq -r '.data.items[].id'
[ "$(echo "$PAGE" | jq -r '.data.has_more')" = "true" ] || break
CURSOR=$(echo "$PAGE" | jq -r '.data.next_cursor')
done
كما أن قراءات الطلبات لا تُخزَّن مؤقتًا أبدًا (المخزَّن هو المنتجات وصفحات الهبوط والمتجر فقط)، فمسح 50 متجر عميل يعني 50 رحلة غير مخزَّنة، كل منها تُحسب من ميزانية ذلك المتجر في الدقيقة. استعمل نوافذ ?since= بدل إعادة قراءة كامل المتراكم.
تأكيد كل الطلبات pending لعميل واحد
KEY="$(cat /etc/secrets/client-x.key)"
# 1. اسرد pending
curl -sS 'https://api.dzbuild.app/v1/orders?status=pending&limit=200' \
-H "Authorization: Bearer $KEY" \
| jq -r '.data.items[].id' \
| while read OID; do
# 2. أكّد كل واحد
curl -sS -X PATCH "https://api.dzbuild.app/v1/orders/$OID" \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: confirm-$OID" \
-d '{"status":"confirmed"}'
done
تقرير إيرادات يومي عبر كل العملاء
clients = json.load(open('clients.json')) # [{name, key}, ...]
today = date.today().isoformat() + 'T00:00:00Z'for c in clients:
orders = requests.get(
f'https://api.dzbuild.app/v1/orders?since={today}&limit=200',
headers={'Authorization': f'Bearer {c["key"]}'},
).json()['data']['items']
revenue = sum(o['total'] for o in orders if o['status'] == 'delivered')
print(f"{c['name']}: {len(orders)} طلبات، {revenue} دج")
العلامة البيضاء (White-labeling)
تريد أن تبدو متاجرك كأنها علامتك، لا DZBuild. الـ API يُمكّن ذلك:
ابنِ الواجهة بنفسك بأي ستاك/علامة (انظر الثيمات والواجهات المخصصة).
استخدم نطاقك الخاص (
shop.yourbrand.com) — وجّهه إلى واجهتك المخصصة، وواجهتك تتحدث مع DZBuild عبر API.لوحة التاجر في
dzbuild.com/dashboardتبقى بعلامة DZBuild — هناك تؤكد الطلبات. عملاؤك النهائيون لا يرون علامة DZBuild أبدًا.
لا توجد لوحة تاجر بعلامة بيضاء، على أي خطة. وأداة العلامة الوحيدة الموجودة هي hide_branding (خطة Unlimited فما فوق)، وهي تزيل علامة DZBuild من واجهة متجر التاجر، لا من لوحة التحكم. وقيمتها الحالية مكشوفة على GET /v1/store، ويمكنك تبديلها بـ PATCH /v1/store/design ({"hide_branding": true}). وإن احتجت ما هو أبعد من ذلك، تحدّث مع المبيعات بدل التخطيط اعتمادًا على منتج غير موجود بعد.
Webhooks للموزّعين
سجّل webhook واحد لكل متجر عميل يشير إلى back-office وكالتك:
curl -X POST 'https://api.dzbuild.app/v1/webhooks' \
-H "Authorization: Bearer $CLIENT_X_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"url": "https://api.youragency.com/dz-hooks?store=client-x",
"events": ["order.created","order.confirmed","order.shipped","order.delivered","order.cancelled"]
}'
استعمل المعامل ?store=client-x فيمكن لنقطة واحدة معالجة كل العملاء، واجعله يختار سر secret الخاص بذلك العميل: كل webhook يوقّع تسليماته بسره الخاص، فتحقّق من X-DZ-Signature بسر webhook ذلك المتجر، وتأكد أن store_id في الجسم هو المتجر الذي تنتظره. انظر التحقق من التواقيع.
وخطّط أيضًا لفجوة التغطية: order.created في API v1 يُطلق فقط للطلبات المُنشأة عبر POST /v1/orders، وأحداث الحالة فقط لتغييرات الحالة التي تتم عبر الـ API. فإن كان عملاؤك يتلقّون الطلبات على واجهة DZBuild ويؤكدونها من اللوحة، فلن ترى شيئًا هنا — إما أن تستعلم GET /v1/orders?since=... لكل متجر، أو أن يُفعّل كل عميل إضافة Webhooks بدون كود على /dashboard/webhooks (خطة Unlimited فما فوق)، فهي تغطي كل مصادر الطلبات.
الحسابات متعددة المتاجر
بعض العملاء يديرون عدة متاجر في حساب DZBuild واحد (ميزة Multi-store). كل متجر له مفتاحه — مستقلة. سمّها بوضوح في مدير الأسرار:
DZ_KEY_CLIENT_X_BRAND_A=dzpk_live_... DZ_KEY_CLIENT_X_BRAND_B=dzpk_live_...
الخطط — ما توصي به
كل متجر تديره بمفاتيح API الخاصة به يجب أن يكون على خطة Enterprise سارية. فالواجهة البرمجية حصرية لخطة Enterprise: على أي خطة أخرى، أو باشتراك Enterprise منتهي الصلاحية، يُرجع كل نداء يتم بمفاتيح API الخاصة بالمتجر 403 forbidden، ولا يمكن أصلًا إنشاء مفاتيح جديدة للمتجر.
أما متاجر العملاء التي لا تؤتمتها (تستعمل لوحة التحكم وواجهة المتجر فقط)، فتبقى الخطط الأخرى سارية كالمعتاد:
حجم العميل | الخطة المستحسنة | السبب |
0-30 طلب/شهر | Free | تحقق من الفكرة قبل الالتزام، لكن الخطة Free تحدّ المتجر بـ 30 طلبًا في الشهر الميلادي |
30–500 طلب/شهر | Pro | يُزيل سقف الطلبات الشهري |
500–2000 طلب/شهر | Unlimited | بلا سقف طلبات، إضافة إلى |
2000+ / multi-brand / أي أتمتة عبر الـ API | Enterprise | دعم فني مباشر 24/7، ضمان SLA 99.9%، تطوير ميزات مخصصة، وهي الخطة الوحيدة التي تملك وصولًا إلى الـ API |
ℹ️ معلومة — الخطة هي بوابة الوصول إلى الـ API
خطة اشتراك المتجر هي بوابة وصوله إلى الـ API: المتاجر ذات خطة Enterprise السارية وحدها تستطيع إنشاء المفاتيح وإجراء نداءات الـ API بمفاتيحها الخاصة (600 طلب/دقيقة لكل متجر، مشتركة بين مفاتيحه؛ انظر حدود المعدل). خفّض خطة عميل، أو دَع اشتراكه في Enterprise ينتهي، فتتوقف مفاتيحه فورًا (403 forbidden)؛ وأعِده إلى Enterprise فتعود المفاتيح نفسها إلى العمل، دون أي إعادة إصدار. ويظل التسجيل في البرنامج التجريبي مطلوبًا ما دام البرنامج قائمًا: وبدونه يُرجع كل نداء 403 forbidden "API is in pilot mode; key not enrolled".
فوترة عملائك
الـ API يُعطيك إشارات استخدام دقيقة لتفوتر بثقة:
GET /v1/usage— نداءات الشهر الحالي مقسمة حسب مجموعة النقاطGET /v1/usage/history— صفوف ساعية (period_hourوendpoint_groupوcountوbillable_count) تحتdata.rows. تفترض آخر 7 أيام افتراضيًا وتقبل نافذة 90 يومًا كحد أقصى عبر?from=&to=؛ وأي نافذة أوسع تُرجع400 bad_request "range too large (max 90 days)". أي أن سنة كاملة تعني المرور عبر خمس نوافذ من 90 يومًا.GET /v1/orders?status=delivered&since=...— لنماذج عمولة لكل طلب (وتذكّر سقف 200 صف لكل صفحة وnext_cursor)
معظم الموزّعين يفوترون:
رسوم شهرية ثابتة لاستضافة الواجهة + إعادة بيع رخصة DZBuild
% عمولة على الطلبات المُسلَّمة (اقرأ من
?status=delivered)أو اشتراك مدمج (مثل "10000 دج/شهر للكل")
اختر النموذج الذي يتوقعه سوقك.
نصائح تشغيلية
بيئة لكل عميل. أسرار dev في dev. أسرار prod في prod. لا تشارك أبدًا.
استخدم Idempotency-Keys حتمية لأي حلقة إعادة (خصوصًا الاستيراد بالجملة / التأكيد بالجملة).
خزّن قراءات المنتجات من جهتك. تُخدَم
GET /v1/productsوGET /v1/landing-pagesوGET /v1/storeحديثًا في كل نداء، فطبقة 5 دقائق من عندك توفّر رحلات؛ المنتجات نادرًا ما تتغير لحظيًا. أما قراءات الطلبات فلا تُخزَّن مؤقتًا أبدًا، فاحسب حساب رحلة كاملة في كل واحدة.حدّ نفسك. لا تقفز إلى سقف فئتك لحظة توفّره — اترك هامشًا لحركة التاجر.
اضبط تنبيهات Telegram عندك على
429 rate_limitedو5xxوفشل تسليم webhook.تدقيق ربع سنوي: دوّر مفاتيح المتاجر التي لا تديرها بعد. استعمل
DELETE /v1/keys/{key_id}.
مرجع
المصادقة — Bearer + DZ-Public
Idempotency — مطلوب على كل الكتابات
حدود المعدل: حدود لكل متجر
Webhooks — دفع بدلًا من استعلام
الثيمات والواجهات المخصصة — بناء headless كامل