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

مسار التثبيت عبر OAuth

يصل التطبيق إلى المتجر عبر مسار OAuth 2.0 برمز التفويض مع PKCE. يوافق التاجر على تطبيقك في شاشة موافقة تابعة لـ DZBuild، ثم يبادل خادمك الرمز برمز وصول واحد لكل متجر، وكل رمز يستدعي واجهة REST لمتجره فقط.

نقاط الوصول​

الخطوةالطلبمن يرسله
التفويضGET https://dzbuild.com/oauth/apps/authorizeمتصفح التاجر، يوجّهه تطبيقك
الموافقة أو الرفضPOST https://dzbuild.com/oauth/apps/approve و /oauth/apps/denyنموذج الموافقة. تطبيقك لا يستدعيهما أبدا.
تبادل الرمزPOST https://dzbuild.com/oauth/apps/tokenخادمك
استدعاءات الواجهةhttps://api.dzbuild.app/v1/...خادمك، مع رمز الوصول

خطوات المسار​

  1. ينشئ خادمك متحقق PKCE وتحدّيه بطريقة S256، وقيمة state عشوائية.
  2. يوجّه التاجر إلى عنوان التفويض. التاجر غير المسجّل يدخل حسابه أولا ثم يعود إلى العنوان نفسه.
  3. تعرض DZBuild شاشة الموافقة. يختار التاجر المتاجر ويوافق.
  4. تعيد DZBuild توجيه المتصفح إلى redirect_uri الخاص بك مع code وقيمة state.
  5. يرسل خادمك الرمز والمتحقق وبيانات اعتماد العميل إلى نقطة التبادل.
  6. يحمل الرد رمز وصول لكل متجر ثُبّت عليه التطبيق.

الخطوة 1: توجيه التاجر إلى عنوان التفويض​

المعاملإلزاميالقاعدة
response_typeنعمدائما code.
client_idنعممعرّف العميل لتطبيقك من منصة المطورين: dzapp_ يليه 20 حرفا ست عشريا.
redirect_uriنعمأحد عناوين إعادة التوجيه المسجّلة على التطبيق، حرفا بحرف. لا مطابقة ببادئة أو بنمط.
scopeلاصلاحيات يفصل بينها فراغ. يجب أن تكون كل صلاحية مسجّلة على التطبيق ومسموحا بها للتطبيقات. غيابه أو كونه فارغا يعني كل الصلاحيات المسجّلة على التطبيق. 512 حرفا على الأكثر.
stateنعممن 1 إلى 1024 حرفا. تعيده DZBuild دون تغيير. اربطه بجلسة التاجر وتحقّق منه عند العودة.
code_challengeنعمبصمة SHA-256 للمتحقق بترميز base64url دون حشو: 43 حرفا بالضبط من A-Z a-z 0-9 - _.
code_challenge_methodنعمدائما S256. طريقة plain مرفوضة.

يتكوّن متحقق الرمز من 43 إلى 128 حرفا من A-Z a-z 0-9 - . _ ~. احتفظ به على خادمك حتى تبادل الرمز. لا يمرّ أبدا عبر المتصفح.

PKCE بلغة PHP:

<?php
function base64url(string $bytes): string
{
return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
}

$verifier = base64url(random_bytes(32)); // 43 characters
$challenge = base64url(hash('sha256', $verifier, true));

// Keep $verifier on your server (session or database) until the token call.
$authorizeUrl = 'https://dzbuild.com/oauth/apps/authorize?' . http_build_query([
'response_type' => 'code',
'client_id' => 'dzapp_0123456789abcdef0123',
'redirect_uri' => 'https://app.example.com/dzbuild/callback',
'scope' => 'orders:read products:read',
'state' => bin2hex(random_bytes(16)),
'code_challenge' => $challenge,
'code_challenge_method' => 'S256',
], '', '&', PHP_QUERY_RFC3986);

PKCE بلغة Node.js:

const crypto = require('node:crypto');

const verifier = crypto.randomBytes(32).toString('base64url'); // 43 characters
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');

// Keep the verifier on your server (session or database) until the token call.
const authorizeUrl = 'https://dzbuild.com/oauth/apps/authorize?' + new URLSearchParams({
response_type: 'code',
client_id: 'dzapp_0123456789abcdef0123',
redirect_uri: 'https://app.example.com/dzbuild/callback',
scope: 'orders:read products:read',
state: crypto.randomBytes(16).toString('hex'),
code_challenge: challenge,
code_challenge_method: 'S256',
});

لاختبار شيفرتك: متحقق المثال في RFC 7636، أي dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk، يجب أن يعطي التحدّي E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM.

الخطوة 2: شاشة الموافقة​

تعرض شاشة الموافقة اسم تطبيقك وشعاره واسم المطوّر. يحمل التطبيق المقبول شارة "راجعته DZBuild". أما التطبيق غير المقبول بعد فتظهر عليه ملاحظة وضع التجربة، ولا يفتحه إلا مطوّره.

يرى التاجر المتاجر التي يملكها. أعضاء الفريق لا يرون أي متجر، لأن التثبيت يمنح رمزا للمتجر كله. المتجر الذي لا يمكنه استقبال التطبيق يظهر مع السبب: التاجر ليس المالك، أو التطبيق في وضع التجربة، أو خطة المتجر أدنى من الخطة الدنيا للتطبيق، أو التطبيق موقوف. يستطيع التاجر الموافقة على 10 متاجر كحد أقصى في المرة الواحدة.

تظهر الصلاحيات المطلوبة مجمّعة حسب المورد. يبقى طلب الموافقة صالحا 10 دقائق.

الخطوة 3: استقبال إعادة التوجيه​

بعد الموافقة، تجيب DZBuild بـ 302 نحو عنوان إعادة التوجيه الخاص بك:

HTTP/1.1 302 Found
Location: https://app.example.com/dzbuild/callback?code=3f9a...64-hex...&state=c2a8a879c9434b775191caf5b17d846f

الرمز من 64 حرفا ست عشريا، صالح 10 دقائق ويُستعمل مرة واحدة. تحقّق من مطابقة state للقيمة المحفوظة قبل استعمال الرمز. إذا كان عنوان إعادة التوجيه المسجّل يحمل سلسلة استعلام، تضيف DZBuild معاملاتها بعد &.

أخطاء التفويض والموافقة​

تصلك الأخطاء بطريقتين. قبل أن تتعرّف DZBuild على client_id و redirect_uri، تعرض صفحة خطأ للتاجر ولا تعيد التوجيه أبدا، حتى لا يرسل رابط خاطئ رموزا إلى عنوان مجهول. بعد ذلك تعيد التوجيه إلى redirect_uri مع المعامل error. تجري الفحوص بترتيب هذا الجدول.

الحالةالنتيجةطريقة الإرجاع
client_id مجهول أو غير صالح الصيغة، أو redirect_uri غير مسجّل حرفياصفحة خطأ، HTTP 400صفحة للتاجر
التطبيق غير مقبول والتاجر ليس مطوّره، أو التطبيق مرفوض أو موقوفصفحة خطأ، HTTP 404صفحة للتاجر
response_type ليس codeerror=unsupported_response_typeإعادة توجيه، مع state إذا كانت صالحة
state غائبة أو أطول من 1024 حرفاerror=invalid_requestإعادة توجيه، دون state
code_challenge ليس 43 حرفا بترميز base64url، أو code_challenge_method ليس S256error=invalid_requestإعادة توجيه، مع state
صلاحية غير مسجّلة على التطبيق أو غير مسموح بها للتطبيقات، أو scope أطول من 512 حرفاerror=invalid_scopeإعادة توجيه، مع state
التاجر ينقر على الرفضerror=access_deniedإعادة توجيه، مع state
لم يُختر أي متجرصفحة خطأ، HTTP 400صفحة للتاجر
اختيار أكثر من 10 متاجرصفحة خطأ، HTTP 400صفحة للتاجر
متجر مختار لا يملكه التاجر أو لا يمكنه استقبال التطبيقصفحة خطأ، HTTP 403صفحة للتاجر
طلب الموافقة منتهي الصلاحية أو سبقت معالجتهصفحة خطأ، HTTP 400صفحة للتاجر

الخطوة 4: تبادل الرمز​

يرسل خادمك نموذجا (application/x-www-form-urlencoded) إلى نقطة التبادل.

الحقلالقيمة
grant_typeauthorization_code
codeالرمز الوارد في إعادة التوجيه.
redirect_uriالسلسلة نفسها التي أرسلتها إلى عنوان التفويض.
code_verifierالمتحقق الذي بُني عليه code_challenge.
client_idمعرّف العميل الخاص بك.
client_secretسرّ العميل (dzas_ يليه 48 حرفا ست عشريا).

يمكنك إرسال client_id و client_secret كبيانات اعتماد HTTP Basic بدل حقول النموذج. تقرأ DZBuild حقول النموذج أولا، ولا تستعمل الترويسة Authorization: Basic إلا إذا غاب الحقلان معا. داخل Basic، رمّز القيمتين بصيغة form-urlencoded كما يشترط القسم 2.3.1 من RFC 6749.

أرسل الترويسة User-Agent مع هذا الطلب ومع كل استدعاء للواجهة، مثلا my-app/1.0 (+https://example.com). يجيب dzbuild.com على أي طلب POST لا يحملها، بما فيه طلب الرمز هذا، بـ 403 وصفحة تحقق بصيغة HTML بدل JSON. الدالة fetch في Cloudflare Workers وعدد من مكتبات HTTP لا ترسل User-Agent ما لم تضبطه بنفسك، أما curl فيرسل ترويسته الخاصة.

curl -sS https://dzbuild.com/oauth/apps/token \
-H "Accept: application/json" \
--data-urlencode "grant_type=authorization_code" \
--data-urlencode "code=$CODE" \
--data-urlencode "redirect_uri=https://app.example.com/dzbuild/callback" \
--data-urlencode "code_verifier=$CODE_VERIFIER" \
--data-urlencode "client_id=$DZBUILD_CLIENT_ID" \
--data-urlencode "client_secret=$DZBUILD_CLIENT_SECRET"

التبادل الناجح يجيب بـ 200 مع Cache-Control: no-store:

{
"access_token": "dzpk_live_...",
"token_type": "Bearer",
"scope": "orders:read products:read",
"store_id": 141,
"install_id": 57,
"stores": [
{
"store_id": 141,
"store_name": "Boutique Amel",
"install_id": 57,
"access_token": "dzpk_live_..."
},
{
"store_id": 152,
"store_name": "Amel Kids",
"install_id": 58,
"access_token": "dzpk_live_..."
}
]
}
الحقلالمعنى
access_tokenرمز العنصر الأول في stores.
token_typeدائما Bearer.
scopeالصلاحيات الممنوحة، يفصل بينها فراغ. كل متجر في الرد يحصل على الصلاحيات نفسها.
store_id، install_idالعنصر الأول في stores.
storesعنصر لكل متجر ثُبّت عليه التطبيق: store_id، store_name، install_id، access_token.

لا يحمل الرد expires_in ولا refresh_token. احفظ كل رمز على الخادم، مفهرسا بـ store_id. يُسمّى رمز الوصول هذا الخاص بكل متجر رمز التثبيت في الصفحات الأخرى.

أخطاء التبادل​

كل خطأ رد JSON يحمل error و error_description، مع Cache-Control: no-store.

HTTPerrorerror_descriptionالسبب
401invalid_clientClient authentication failedclient_id أو client_secret غائب أو خاطئ. مع بيانات Basic يحمل الرد أيضا WWW-Authenticate: Basic realm="dzbuild".
400unsupported_grant_typeOnly authorization_code is supportedgrant_type ليس authorization_code.
400invalid_grantThe code is invalid, expired, already used, or does not match this requestرمز مجهول أو منتهي أو مستعمل، أو رمز صادر لتطبيق آخر، أو redirect_uri مختلف، أو متحقق لا يطابق التحدّي.
400invalid_grantNo approved store could be installedتعذّر تثبيت أي متجر مختار: كل متجر فشل في الفحص الأخير (مثلا خطة أدنى من الخطة الدنيا للتطبيق) أو فشل تثبيته.
500server_errorThe code could not be checked أو The install could not be completedعطل في المنصّة. أعد التاجر إلى خطوة التفويض.

تتحقق DZBuild من العميل أولا، ثم من grant_type، ثم تستهلك الرمز. الرمز المستهلك يضيع حتى لو كان redirect_uri أو المتحقق خاطئا، فلا يمكن إعادة محاولة تبادل فاشل بالرمز نفسه. ابدأ طلب تفويض جديدا.

التثبيت على عدة متاجر​

التاجر الذي يملك عدة متاجر يستطيع الموافقة على 10 منها كحد أقصى في موافقة واحدة. يذكر رد التبادل كل متجر ثُبّت عليه التطبيق في stores، مع install_id و access_token خاصين به. الرمز لا يصل إلا إلى متجره.

تفحص DZBuild كل متجر مرة أخرى أثناء التبادل. المتجر الذي لم يعد يستوفي الشروط يُستبعد، لذا قد تحمل stores متاجر أقل مما اختاره التاجر. اعتمد على stores لا على الموافقة التي توقّعتها.

إعادة المسار لمتجر ثُبّت عليه تطبيقك من قبل تحدّث التثبيت نفسه: يبقى install_id، وتصبح الصلاحيات هي صلاحيات الموافقة الجديدة، ويحلّ رمز جديد محلّ القديم. يتوقف الرمز القديم فورا.

استدعاء الواجهة​

أرسل الرمز في ترويسة Bearer إلى https://api.dzbuild.app/v1. الطلب GET /v1/whoami لا يحتاج أي صلاحية ويبيّن ما يستطيعه الرمز:

curl -sS https://api.dzbuild.app/v1/whoami \
-H "Authorization: Bearer $DZBUILD_ACCESS_TOKEN"
{
"data": {
"key_id": "...",
"store_id": 141,
"type": "platform",
"rate_limit_tier": "enterprise",
"pilot": true,
"scopes": ["orders:read", "products:read"],
"app": {
"app_id": 12,
"client_id": "dzapp_0123456789abcdef0123",
"install_id": 57
}
},
"meta": {
"request_id": "...",
"api_version": "v1"
}
}

رموز التطبيقات تعمل مع كل خطط المتاجر. المستوى enterprise الظاهر في whoami هو التسمية التي تعطيها الواجهة لرموز التطبيقات، أما حدود تطبيقك فهي في صفحة حدود معدّل الطلبات.

مدة صلاحية الرمز وإلغاؤه​

ليس لرمز الوصول تاريخ انتهاء. يبقى صالحا حتى يقع أحد الأمرين:

  • يزيل التاجر التطبيق. يُلغى الرمز وتجيب الاستدعاءات بـ 401 مع رمز الخطأ unauthorized والرسالة Invalid or revoked API key. تستقبل نقطة webhook التي تم التحقق منها حدثا واحدا app.uninstalled.
  • تعيد مسار التثبيت للمتجر نفسه. يحلّ الرمز الجديد محلّ القديم.

ما دام التثبيت قائما، ترفض الواجهة الرمز بـ 403 في هذه الحالات:

error.codeالرسالةمتى
app_uninstalledThis app is no longer installed on this storeالتثبيت لم يعد نشطا.
app_suspendedThis app has been suspended by DZBuildأوقفت DZBuild التطبيق أو رفضته. تعود الاستدعاءات للعمل بعد رفع الإيقاف.
app_not_approvedThis app is in test mode and only runs on its developer's storesلم يُقبل التطبيق بعد (مسودة أو في مراجعته الأولى) والمتجر ليس ملكا لمطوّره.
app_plan_requiredThis app requires the ... planخطة المتجر، أو خطة مدفوعة منتهية، أدنى من الخطة الدنيا للتطبيق. تذكر الرسالة اسم الخطة.

عبر api.dzbuild.app، تمرّر البوابة رد DZBuild كما هو دون أي تعديل، فتصلك رموز 403 أعلاه وكذلك 401 و429 بالحالة والمحتوى الموصوفين هنا. وإذا تعذّر على البوابة التحقق من الرمز لدى DZBuild، لأنها لا تستطيع الوصول إليها أو لأنها ردّت بخطأ في الخادم، فإنها تجيب بـ 502 مع رمز الخطأ server_error والرسالة Key lookup failed, retry shortly. أعد المحاولة بعد لحظات.

لا توجد في الإصدار الأول نقطة وصول تلغي بها التطبيقات رموزها. إزالة التطبيق يقوم بها التاجر من صفحة التطبيق في لوحة التحكم.

تجديد سرّ العميل في منصة المطورين يستبدله فورا. الرموز الصادرة من قبل تبقى صالحة.

حدود معدّل الطلبات​

نقطة الوصولالحد
GET /oauth/apps/authorize30 طلبا كل 300 ثانية
POST /oauth/apps/approve10 طلبات كل 600 ثانية
POST /oauth/apps/token60 طلبا كل 300 ثانية
واجهة REST برمز تطبيق120 طلبا في الدقيقة لكل تثبيت، قبل الحد المشترك للمتجر

تُحسب حدود OAuth لكل عميل، ويُعرَّف العميل بعنوان IP وترويسات المتصفح والجلسة. التزم بها: العميل الذي يتجاوز حدًا قد يتلقى 429 مع ترويسة Retry-After لا تتجاوز 120 ثانية. أرسل Accept: application/json في طلبات التبادل حتى يعود الرفض بصيغة JSON لا كإعادة توجيه. حدود الواجهة في صفحة حدود معدّل الطلبات.

هذه الصفحة لأدوات الذكاء الاصطناعيعرض بصيغة Markdownفتح في ChatGPTفتح في Claude