# المصادقة

نوعان من المفاتيح.

## مفتاح المنصة (خادم إلى خادم، CRUD كامل)[​](#مفتاح-المنصة-خادم-إلى-خادم-crud-كامل "رابط مباشر إلى مفتاح المنصة (خادم إلى خادم، CRUD كامل)")

استخدم Bearer token من خادمك الخلفي:

```
Authorization: Bearer <key_id>.<key_secret>
```

الشكل هو `key_id.key_secret`، وكلا الجزأين مطلوب. و`key_id` هو المعرّف المكوّن من 24 حرفًا والذي يبدأ أصلًا بـ`dzpk_live_` (مثال: `dzpk_live_xxxxxxxxxxxxxx.<48-hex secret>`)، لذا لا تُضِف البادئة مرة أخرى. أما سر المفتاح فطوله 48 حرفًا ست عشريًا ويُعرض **مرة واحدة فقط** عند الإنشاء ولن يظهر مجددًا.

## المفتاح العام (المواقع والتطبيقات الخارجية؛ موقّع بـ HMAC)[​](#المفتاح-العام-المواقع-والتطبيقات-الخارجية-موقّع-بـ-hmac "رابط مباشر إلى المفتاح العام (المواقع والتطبيقات الخارجية؛ موقّع بـ HMAC)")

لعدّ **اشتراكات** المستخدمين النهائيين و**أحداثهم** المخصصة من موقع أو تطبيق تديره خارج DZBuild. يستدعي خادمك الخلفي `POST /v1/signups` أو `POST /v1/events` ويوقّع كل طلب — لا تكشف سر التوقيع للمتصفح أبدًا.

الرؤوس:

```
Authorization: DZ-Public <key_id>

X-DZ-Timestamp: <unix_seconds>

X-DZ-Nonce: <32-hex>

X-DZ-Signature: hex(hmac_sha256(signing_secret, key_id + "\n" + nonce + "\n" + ts + "\n" + sha256(body)))
```

هنا أيضًا يبدأ `key_id` أصلًا بـ`dzpub_live_` — مرّره كما أُرجع لك تمامًا. وسر التوقيع طوله 64 حرفًا ست عشريًا.

الـ nonce يُستخدم مرة واحدة فقط لكل مفتاح ولمدة ساعة، ويمنع إعادة التشغيل. الطابع الزمني يجب أن يكون ضمن ±5 دقائق.

المفتاح العام الجديد يبقى معطّلًا حتى يُفعَّل

المفتاح من نوع `type: public` الذي تُنشئه عبر `POST /v1/keys` سيُرجع `401` إلى أن يُفعَّل لاستقبال حركة الواجهة البرمجية. راسل الدعم مباشرة بعد إنشائه لتفعيله. أما مفاتيح المنصة (Bearer) فلا يشملها ذلك — تعمل فورًا.

## الصلاحيات (Scopes)[​](#الصلاحيات-scopes "رابط مباشر إلى الصلاحيات (Scopes)")

كل مفتاح له قائمة من الصلاحيات. صلاحيات منصة افتراضية: `store:read`, `store:write`, `products:read`, `products:write`, `orders:read`, `orders:write`, `customers:read`, `landing_pages:read`, `landing_pages:write`, `promos:read`, `promos:write`, `pixels:read`, `pixels:write`, `shipping:read`, `shipping:write`, `webhooks:read`, `webhooks:write`, `usage:read`, `analytics:read`, `whatsapp:read`, `whatsapp:send`. المفتاح الذي يُنشأ من لوحة التحكم يحصل على هذه القائمة بالضبط. وهي لا تضم `delivery:send` ولا `ai:generate`، لذا فالمفتاح المُنشأ من لوحة التحكم أو عبر `POST /v1/keys` يتلقى `403` على `POST /v1/orders/{id}/send-to-delivery` و`POST /v1/landing-pages/generate`.

صلاحيات عامة افتراضية: `signups:write`, `events:write`.

تُفحَص الصلاحيات في القراءة كما في الكتابة: المفتاح الذي لا يملك `orders:read` يتلقى `403` مع الرسالة `Missing scope: orders:read` على `GET /v1/orders`. والصلاحية `store:write` تشمل كتابات إعدادات المتجر وتصميمه وقالبه وأقسام صفحته الرئيسية. أما `signups:write` و`events:write` فتخصّان `POST /v1/signups` و`POST /v1/events`.

إدارة المفاتيح (`/v1/keys`) محكومة بـ**نوع** المفتاح لا بصلاحياته: المفتاح العام الذي يستدعيها يتلقى `403` — "Key management requires a platform key".

مفتاح المنصة الذي يُنشأ عبر `POST /v1/keys` لا يحصل إلا على الصلاحيات التي يملكها المفتاح المستدعي أصلًا (`403` إن لم تجمعهما أي صلاحية مشتركة). أما المفتاح من نوع `type: public` فيحصل دائمًا على `signups:write` و`events:write`.

## إنشاء مفتاح[​](#إنشاء-مفتاح "رابط مباشر إلى إنشاء مفتاح")

ينشئ مالك متجر على خطة Enterprise سارية مفاتيحه الشخصية من لوحة التحكم عبر **الإعدادات ← واجهة API** (`/dashboard/api`). يُسجَّل المفتاح الجديد في البرنامج التجريبي تلقائيًا ويعمل فورًا، فلا شيء تطلبه من الدعم. تعرض الصفحة قيمتين، مرة واحدة فقط، عند إنشاء المفتاح:

* **مفتاح الوصول (Bearer token)**: هو بيانات الاعتماد كاملة، وهو أصلًا بالشكل `key_id.key_secret`. أرسله كما هو، `Authorization: Bearer <bearer token>`، دون أن تضيف إليه شيئًا.
* **سر التوقيع (Signing secret)**: لا يوضع أبدًا في رأس `Authorization`، ونداءات `Bearer` لا تستعمله. احفظه سرًّا مثل مفتاح الوصول.

يحتفظ المتجر بـ 3 مفاتيح شخصية نشطة كحد أقصى. والمفاتيح التي تحملها التطبيقات المثبّتة أو Copilot أو أحد الموصلات لا تشغل أيًّا من هذه الأماكن.

## اتصالات المساعدين[​](#اتصالات-المساعدين "رابط مباشر إلى اتصالات المساعدين")

الاتصال الذي يُنشأ لـ Copilot أو لمساعد ذكاء اصطناعي متصل (Claude أو ChatGPT) يمكن أن يغطي عدة متاجر للتاجر، بمفتاح لكل متجر. وتسمح نقطتا نهاية للمفتاح الذي يحمله اتصال كهذا بقراءة المتاجر التي يغطيها وبتغيير المتجر النشط منها. أما أي مفتاح آخر، بما في ذلك المفتاح المُنشأ من لوحة التحكم، فيتلقى `404 not_found` مع `This key does not belong to an assistant connection.`

### `GET /v1/connection`[​](#get-v1connection "رابط مباشر إلى get-v1connection")

يحتاج إلى `store:read`.

```
curl https://api.dzbuild.app/v1/connection \

  -H "Authorization: Bearer $DZ_KEY"
```

```
{ "data": { "connection_id": 100, "client_name": "Claude", "active_store_id": 10,

            "stores": [ { "id": 10, "name": "My store", "slug": "my-store" },

                        { "id": 20, "name": "My second store", "slug": "my-second-store" } ] },

  "meta": { "request_id": "...", "api_version": "v1" } }
```

`client_name` هو اسم تطبيق المساعد. والاتصال الذي تمّت الموافقة عليه قبل أن تصبح الاتصالات قادرة على تغطية عدة متاجر يسرد متجره الوحيد.

### `POST /v1/connection/active-store`[​](#post-v1connectionactive-store "رابط مباشر إلى post-v1connectionactive-store")

يحتاج إلى `store:write` وإلى `Idempotency-Key`. ويحدّد `store_id` في الجسم المتجر الذي يصبح نشطًا.

```
curl -X POST https://api.dzbuild.app/v1/connection/active-store \

  -H "Authorization: Bearer $DZ_KEY" \

  -H "Content-Type: application/json" \

  -H "Idempotency-Key: active-store-20" \

  -d '{"store_id": 20}'
```

الاستجابة هي الاتصال بعد النقل، بالشكل نفسه الذي يُرجعه `GET /v1/connection`. المتجر النشط مؤشّر وليس صلاحية: كل طلب يبقى يعمل على المتجر الوحيد الذي ينتمي إليه مفتاحه. والمتجر الذي لا يدخل في الاتصال يُرجع `403 store_not_in_connection`، والجسم الذي لا يحمل `store_id` يُرجع `400 bad_request`.
