تخطَّ إلى المحتوى

API الموزعين

نظرة عامة

أرسل طلبات شحن الألعاب من نظامك وتابع كل طلب حتى حالته النهائية. تُدفع الطلبات مسبقًا من رصيدك، فلا يوجد ائتمان ولا يصبح الرصيد سالبًا.

  • الرابط الأساسي: https://thenexus.store/api/reseller/v1
  • يوافق فريقنا على الوصول إلى API بعد الموافقة على حساب الموزع. ولا يتم ذلك تلقائيًا أبدًا.
  • لا توجد بيئة تجريبية (sandbox). كل دفعة طلب حقيقي يُدفع من رصيدك، فابدأ بطلب صغير واحد.

خطوات البدء

  1. أنشئ حساب موزع. لا تحتاج إلى كود شريك. يراجعه فريقنا.
  2. اشحن رصيدك بالدولار من قسم المحفظة في لوحتك. التحويلات البنكية مقبولة بالدولار أو اليورو إلى حساب بنكي أوروبي، أو إلى حساب بنكي مصري.
  3. اطلب الوصول إلى API من قسم API في لوحتك. بعد الموافقة أنشئ مفتاحًا من هناك. يظهر المفتاح مرة واحدة.
  4. تحقق من الاتصال بـ GET /account، واقرأ أسعارك بـ GET /products، ثم أرسل دفعة صغيرة بـ POST /batches.
  5. اختياري: حدّد رابط webhook لتصلك تحديثات الطلبات دون استعلام متكرر.
curl https://thenexus.store/api/reseller/v1/account \
  -H 'X-Nexus-API-Key: nxr_your_key_here'

المصادقة

أرسل مفتاحك في الترويسة X-Nexus-API-Key مع كل طلب. يبدأ المفتاح بـ nxr_ ثم 48 حرفًا ست عشريًا. نحفظ hash فقط، فلا يمكن عرض المفتاح المفقود مرة أخرى: ألغه وأنشئ مفتاحًا جديدًا.

  • صلاحيات كل مفتاح: products.read وbatches.create وbatches.read.
  • حتى 5 مفاتيح فعّالة لكل حساب. ينتهي المفتاح بعد 1 إلى 730 يومًا، و365 افتراضيًا.
  • يتحقق كل طلب من أن الحساب والوصول إلى API ما زالا معتمدين.

قواعد عامة

  • JSON في الطلب وفي الرد، UTF-8. الحد الأقصى لحجم الطلب 256 كيلوبايت.
  • المبالغ أرقام عشرية بالجنيه المصري، عملة المتجر. ويعيد GET /account وGET /balance وGET /products أيضًا القيمة بالدولار في حقول *_usd: الرصيد يُقرَّب للأسفل إلى السنت، والأسعار للأعلى.
  • يحمل كل رد X-Request-ID. اذكره عند التواصل مع الدعم.
  • لا تتضمن الردود أسماء الموردين ولا التكلفة.

الكتالوج

GET/api/reseller/v1/productsproducts.read

المنتجات النشطة بسعرك. المنتج الذي ليس له سعر آمن للموزعين لا يظهر. إذا كانت manual_fulfilment تساوي true فإن فريقنا يسلّمه يدويًا. تكون stock تساوي null إذا لم تكن محسوبة. الصفحات: per_page افتراضيًا 100.

{
  "products": [
    {"id": "3f2c0d4e-...", "title": "Example top-up pack", "category": "topup",
     "retail_price": 100.00, "reseller_price": 97.00,
     "retail_price_usd": 2.00, "reseller_price_usd": 1.94,
     "currency": "EGP", "stock": null, "manual_fulfilment": false}
  ],
  "page": 1, "per_page": 100, "has_more": false, "currency": "EGP"
}

الرصيد والحساب

GET/api/reseller/v1/balanceproducts.read

{"balance": 1250.50, "balance_usd": 25.01, "currency": "EGP", "discount_percent": 3}

GET/api/reseller/v1/accountproducts.read

{"account": {"tier": "starter", "discount_percent": 3, "balance": 1250.50, "balance_usd": 25.01,
  "currency": "EGP", "scopes": ["products.read", "batches.create", "batches.read"],
  "rate_limit_per_hour": 120, "key_expires_at": "2027-11-07 10:00:00"}}

الأرقام أعلاه للتوضيح فقط.

إرسال الطلبات

POST/api/reseller/v1/batchesbatches.create

تحمل الدفعة من 1 إلى 50 عنصرًا وتُدفع من رصيدك فورًا. الترويسة Idempotency-Key إلزامية (من 8 إلى 100 حرف: حروف وأرقام و . _ : -). وللطلب حقل واحد هو items.

الحقلالقاعدة
client_refإلزامي. مرجعك الخاص، من 1 إلى 100 حرف (حروف وأرقام و . _ : -)، وفريد داخل الدفعة.
product_idإلزامي. معرّف المنتج من GET /products.
quantityمن 1 إلى 1000، والافتراضي 1.
deliveryكائن يحمل بيانات اللاعب التي يحتاجها المنتج (انظر بيانات اللاعب).
curl -X POST https://thenexus.store/api/reseller/v1/batches \
  -H 'X-Nexus-API-Key: nxr_your_key_here' \
  -H 'Idempotency-Key: order-1042-try-1' \
  -H 'Content-Type: application/json' \
  -d '{"items":[{"client_ref":"order-1042","product_id":"3f2c0d4e-...","quantity":1,"delivery":{"game_id":"123456789"}}]}'
HTTP 201
{
  "batch_code": "NXB-A1B2C3D4E5", "status": "completed", "item_count": 1,
  "total": 97.00, "currency": "EGP",
  "items": [{"client_ref": "order-1042", "order_code": "NX-...", "state": "processing",
             "unit_price": 97.00, "total": 97.00, "manual_fulfilment": false}]
}

تعني القيمة completed في status أن الدفعة قُبلت ودُفعت، وليس أن كل العناصر سُلّمت. تابع كل عنصر بحالته.

GET/api/reseller/v1/batchesbatches.read

دفعاتك من الأحدث: batch_code وstatus وitem_count وtotal وcurrency وcreated_at. الصفحات: per_page افتراضيًا 50.

GET/api/reseller/v1/batches/{batch_code}batches.read

دفعة واحدة مع عناصرها: client_ref وproduct_id وquantity وunit_price وtotal وorder_code وstate وmanual_fulfilment، ومعها error_code وerror_message إذا فشل عنصر.

بيانات اللاعب

ضع ما يحتاجه المنتج داخل delivery. هذه هي المفاتيح الشائعة، وبعض المنتجات تأخذ مفاتيح أخرى تُذكر مع المنتج. المفاتيح غير المعروفة تُرفض بـ HTTP 422.

المفتاحالاستخدام
game_idمعرّف اللاعب أو الحساب داخل اللعبة، حتى 120 حرفًا.
serverالسيرفر أو المنطقة إن وُجدت في اللعبة، حتى 50 حرفًا.
regionالمنطقة إذا طلبها المنتج، حتى 50 حرفًا.
provider_fieldsكائن بحقول نصية إضافية يحتاجها بعض الشحن، كل حقل حتى 200 حرف.

لا يستطيع API التحقق من معرّف اللاعب قبل الطلب، ولا يوجد endpoint للتحقق حاليًا. المنتجات التي تحتاج تسجيل دخول المشتري إلى حساب اللعبة تُرفض بالرمز interactive_login_required. وإذا تعذّر تسليم الطلب ينتقل إلى failed ويعود المبلغ كاملًا إلى رصيدك.

حالة الطلب

GET/api/reseller/v1/ordersbatches.read

طلباتك من الأحدث. اختياري: state (إحدى الحالات أدناه) وlimit (من 1 إلى 100، والافتراضي 50). هذه القائمة بلا صفحات.

GET/api/reseller/v1/orders/{order_code}batches.read

{"order": {"order_code": "NX-...", "client_ref": "order-1042", "product": "Example top-up pack",
  "quantity": 1, "total": 97.00, "currency": "EGP", "state": "delivered",
  "manual_fulfilment": false, "refunded_to_balance": false,
  "created_at": "2026-11-01 10:00:00", "updated_at": "2026-11-01 10:02:10"}}
stateالمعنى
pendingتم القبول. يسلّم فريقنا هذا المنتج يدويًا، فلا يكون تلقائيًا.
processingتم الدفع من رصيدك، ويجري التسليم تلقائيًا.
deliveredتم التسليم. حالة نهائية.
failedتعذّر التسليم. أُعيد المبلغ كاملًا إلى رصيدك مرة واحدة.
refundedردّه الفريق. عاد المبلغ إلى رصيدك.

تعيد الطلبات الفاشلة والمردودة المبلغ إلى رصيدك مرة واحدة فقط، كسطر جديد في سجل الرصيد. ولا يُعدَّل السجل القديم أبدًا.

تقسيم الصفحات

يقبل GET /products وGET /batches المعاملين page (من 1) وper_page (من 1 إلى 100) ويعيدان page وper_page وhas_more. اطلب الصفحة التالية ما دامت has_more تساوي true.

curl 'https://thenexus.store/api/reseller/v1/batches?page=2&per_page=25' -H 'X-Nexus-API-Key: nxr_your_key_here'

Idempotency

أرسل Idempotency-Key فريدًا مع كل دفعة. إرسال المفتاح نفسه بالطلب نفسه يعيد الدفعة المحفوظة بـ HTTP 200 مع الترويسة Idempotent-Replayed: true، ولا يخصم مرتين. يحمل الرد المكرر إجماليات الدفعة دون العناصر: اقرأها بـ GET /batches/{batch_code}. والمفتاح نفسه مع طلب مختلف يُرفض بالرمز idempotency_key_mismatch.

بعد أي انقطاع كرّر الطلب نفسه بالمفتاح نفسه. واستخدم مفتاحًا جديدًا لدفعة جديدة فقط.

Webhooks والتوقيع

حدّد endpoint بـ HTTPS من قسم API في لوحتك، ويظهر الـ signing secret مرة واحدة. تُرسل الـ webhooks فقط ما دام الوصول إلى API معتمدًا. يجب أن يكون العنوان HTTPS عامًا على المنفذ 443، ولا تُتبع إعادات التوجيه.

الحدثمتى
order.pendingطلب ينتظر فريقنا.
order.processingطلب يجري تسليمه تلقائيًا.
order.deliveredتم تسليم طلب.
order.failedفشل طلب وعاد المبلغ إلى رصيدك.
order.refundedردّ الفريق طلبًا إلى رصيدك.
batch.completedقُبلت دفعة ودُفعت. يُرسل مرة واحدة دون إعادة.

كل طلب هو POST يحمل X-Nexus-Event وX-Nexus-Signature بالشكل t=<unix>,v1=<hex>. التوقيع هو HMAC-SHA256 للنص "<t>.<raw body>" باستخدام secret الخاص بك. قارن بوقت ثابت وارفض أي timestamp أقدم من 5 دقائق.

{"id": "...", "event": "order.failed", "created_at": "2026-11-01T10:05:00+00:00",
 "data": {"order_code": "NX-...", "client_ref": "order-1042", "state": "failed",
          "total": 97.0, "currency": "EGP", "manual_fulfilment": false, "credited_to_balance": true}}
// PHP
$parts = [];
foreach (explode(',', $_SERVER['HTTP_X_NEXUS_SIGNATURE'] ?? '') as $p) { [$k, $v] = array_pad(explode('=', $p, 2), 2, ''); $parts[$k] = $v; }
$raw = file_get_contents('php://input');
$ok = isset($parts['t'], $parts['v1'])
  && abs(time() - (int)$parts['t']) <= 300
  && hash_equals(hash_hmac('sha256', $parts['t'] . '.' . $raw, $secret), $parts['v1']);

أجب بأي status من 2xx خلال 4 ثوانٍ. يُرسل كل حدث طلب حتى 6 مرات بفواصل متزايدة إلى أن تجيب بـ 2xx. يتغير id مع كل محاولة، لذا أزل التكرار باستخدام order_code مع state. الـ webhooks وسيلة مساعدة، وتبقى endpoints الطلبات هي المرجع دائمًا.

الأخطاء

تأتي الأخطاء بصيغة JSON مع رسالة error وrequest_id. وكثير منها يحمل code يمكن للبرامج قراءته.

{"error": "Insufficient reseller wallet balance", "request_id": "..."}
HTTPالمعنى
400رصيد المحفظة غير كافٍ. اشحن رصيدك ثم أرسل الدفعة من جديد بـ Idempotency-Key جديد.
401invalid_api_key: المفتاح ناقص أو خاطئ أو ملغى أو منتهي، أو لم يعد الحساب أو الوصول إلى API معتمدًا.
403suspended أو scope_denied: الحساب موقوف، أو المفتاح لا يملك الصلاحية التي يحتاجها هذا الـ endpoint.
404الطلب أو الدفعة غير موجودين في حسابك. المنتج غير المعروف أو غير النشط داخل دفعة يعيد 409، والمعرّف غير الصحيح يعيد 422.
409لا يمكن بيع المنتج للموزعين حاليًا. قيمة code إحدى: delivery_method_not_allowed أو delivery_region_unavailable أو interactive_login_required أو reseller_price_unavailable، أو غير موجودة (غير متاح أو نفد). لا يُخصم أي مبلغ.
413body_too_large: حجم الطلب أكبر من 256 كيلوبايت.
422خطأ في البيانات. من الرموز: idempotency_key_required وidempotency_key_invalid وidempotency_key_mismatch.
429rate_limited: طلبات كثيرة لهذا المفتاح، أو مفاتيح خاطئة كثيرة من عنوان واحد. انتظر عدد الثواني في Retry-After.

حدود الاستخدام

يسمح كل مفتاح بـ 120 طلبًا في الساعة افتراضيًا، ويمكن للفريق تحديد قيمة أخرى لكل مفتاح. وهناك حد قصير في الدقيقة يساوي سدس الحد بالساعة (10 على الأقل و120 على الأكثر). تحمل الردود الناجحة X-RateLimit-Limit. وبعد الحد يُرجَع HTTP 429 مع Retry-After.

أمثلة الكود

curl

curl https://thenexus.store/api/reseller/v1/products?per_page=100 \
  -H 'X-Nexus-API-Key: nxr_your_key_here'

Node.js

const res = await fetch('https://thenexus.store/api/reseller/v1/batches', {
  method: 'POST',
  headers: {
    'X-Nexus-API-Key': process.env.NEXUS_KEY,
    'Idempotency-Key': 'order-1042-try-1',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ items: [{ client_ref: 'order-1042', product_id: PRODUCT_ID, quantity: 1, delivery: { game_id: '123456789' } }] }),
});
if (res.status === 429) await new Promise(r => setTimeout(r, Number(res.headers.get('retry-after') || 1) * 1000));
console.log(res.status, await res.json());

Python

import os, time, requests
r = requests.post('https://thenexus.store/api/reseller/v1/batches',
    headers={'X-Nexus-API-Key': os.environ['NEXUS_KEY'], 'Idempotency-Key': 'order-1042-try-1'},
    json={'items': [{'client_ref': 'order-1042', 'product_id': PRODUCT_ID, 'quantity': 1, 'delivery': {'game_id': '123456789'}}]},
    timeout=30)
if r.status_code == 429:
    time.sleep(int(r.headers.get('Retry-After', 1)))
print(r.status_code, r.json())

التحقق من توقيع webhook (Node.js)

const crypto = require('crypto');
function verify(secret, header, rawBody, now = Date.now() / 1000) {
  const m = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(header || '');
  if (!m || Math.abs(now - Number(m[1])) > 300) return false;
  const want = crypto.createHmac('sha256', secret).update(m[1] + '.' + rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(want), Buffer.from(m[2]));
}

OpenAPI

وصف قابل للقراءة آليًا لهذه الـ endpoints، يقدّمه API نفسه: /api/reseller/v1/openapi.json

سجل التغييرات

  • انتقل هذا التوثيق إلى /resellers/docs. وأصبح ملف OpenAPI مطابقًا للكود: GET /orders يقبل state وlimit، ونقص الرصيد يعيد HTTP 400.

  • حالات الطلب مع GET /orders وGET /orders/{order_code}، وGET /balance وGET /account وقائمة GET /batches، وترويسة Idempotent-Replayed وملف OpenAPI. وتعود الطلبات الفاشلة والمردودة إلى الرصيد مرة واحدة.

  • Webhooks موقّعة. وأصبح الوصول إلى API موافقة مستقلة عن الحساب.

  • الإصدار الأول: GET /products وPOST /batches.

أسئلة عن API؟ افتح تذكرة من قسم الدعم في لوحتك.