# للموزّعين

إن كنت تبني متاجر للعملاء — وكالات، فريلانسرز، شركات تنفيذ، مشغّلو منصات سوق — فإن DZBuild API مصمّم ليكون عمودك العملياتي.

هذا الدليل لك إن كان أيٌّ مما يلي ينطبق:

* تدير **5+ متاجر DZBuild** لعملاء مختلفين.
* تُفوتر العملاء لكل طلب أو شهريًا وتحتاج إشارة استخدام موثوقة.
* تبني **ثيمات مخصصة** أو **واجهات مخصصة** نيابة عن العملاء.
* تبيع DZBuild كطبقة **علامة بيضاء** ("MyAgency Commerce, مدعومة من DZBuild").
* تريد سكربتة عمليات بالجملة: استيراد منتجات، تحديث أسعار، تأكيد طلبات.

## كيف يستخدم الموزّعون الـ API فعلًا[​](#كيف-يستخدم-الموزّعون-الـ-api-فعلًا "رابط مباشر إلى كيف يستخدم الموزّعون الـ 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, os



KEY = 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 لعميل واحد[​](#تأكيد-كل-الطلبات-pending-لعميل-واحد "رابط مباشر إلى تأكيد كل الطلبات 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)[​](#العلامة-البيضاء-white-labeling "رابط مباشر إلى العلامة البيضاء (White-labeling)")

تريد أن تبدو متاجرك كأنها **علامتك**، لا DZBuild. الـ API يُمكّن ذلك:

* ابنِ الواجهة **بنفسك** بأي ستاك/علامة (انظر [الثيمات والواجهات المخصصة](https://dzbuild.com/ar/ar/api-docs/guides/custom-storefronts.md)).
* استخدم نطاقك الخاص (`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 للموزّعين[​](#webhooks-للموزّعين "رابط مباشر إلى 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` في الجسم هو المتجر الذي تنتظره. انظر [التحقق من التواقيع](https://dzbuild.com/ar/ar/api-docs/webhooks/verifying-signatures.md).

وخطّط أيضًا لفجوة التغطية: `order.created` في API v1 يُطلق فقط للطلبات المُنشأة عبر `POST /v1/orders`، وأحداث الحالة فقط لتغييرات الحالة التي تتم عبر الـ API. فإن كان عملاؤك يتلقّون الطلبات على واجهة DZBuild ويؤكدونها من اللوحة، فلن ترى **شيئًا** هنا — إما أن تستعلم `GET /v1/orders?since=...` لكل متجر، أو أن يُفعّل كل عميل إضافة Webhooks بدون كود على `/dashboard/webhooks` (خطة Unlimited فما فوق)، فهي تغطي كل مصادر الطلبات.

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

بعض العملاء يديرون **عدة متاجر في حساب DZBuild واحد** ([ميزة Multi-store](https://dzbuild.com/ar/ar/docs/operations/multi-store.md)). كل متجر له مفتاحه — مستقلة. سمّها بوضوح في مدير الأسرار:

```
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       | بلا سقف طلبات، إضافة إلى `hide_branding` على واجهة المتجر                                                 |
| 2000+ / multi-brand / أي أتمتة عبر الـ API | Enterprise      | دعم فني مباشر 24/7، ضمان SLA 99.9%، تطوير ميزات مخصصة، وهي الخطة **الوحيدة** التي تملك وصولًا إلى الـ API |

الخطة هي بوابة الوصول إلى الـ API

خطة اشتراك المتجر **هي بوابة** وصوله إلى الـ API: المتاجر ذات خطة **Enterprise** السارية وحدها تستطيع إنشاء المفاتيح وإجراء نداءات الـ API بمفاتيحها الخاصة‏ (600 طلب/دقيقة لكل متجر، مشتركة بين مفاتيحه؛ انظر [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md)). خفّض خطة عميل، أو دَع اشتراكه في 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}`.

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

* [المصادقة](https://dzbuild.com/ar/ar/api-docs/authentication.md) — Bearer + DZ-Public
* [Idempotency](https://dzbuild.com/ar/ar/api-docs/idempotency.md) — مطلوب على كل الكتابات
* [حدود المعدل](https://dzbuild.com/ar/ar/api-docs/rate-limits.md): حدود لكل متجر
* [Webhooks](https://dzbuild.com/ar/ar/api-docs/webhooks/overview.md) — دفع بدلًا من استعلام
* [الثيمات والواجهات المخصصة](https://dzbuild.com/ar/ar/api-docs/guides/custom-storefronts.md) — بناء headless كامل
