واجهة D2Bulk البرمجية للريسيلرزD2Bulk Reseller API

اربط متجرك مباشرة بكتالوج D2Bulk ورصيدك ونظام الطلبات. تصفّح المنتجات، تحقّق من رصيدك، نفّذ الطلبات، واستلم أكواد التفعيل فوراً — كل ذلك عبر واجهة HTTPS بسيطة وموقّعة. Connect your store directly to D2Bulk's catalog, balance and ordering system. Browse products, check your balance, place orders and receive redemption codes instantly — all over a simple, signed HTTPS API.

الرابط الأساسيBase URL https://api.d2bulk.com/api/v1

نظرة عامةOverview

تعكس واجهة الريسيلر البرمجية بالضبط ما يمكنك فعله بالفعل داخل بوت D2Bulk على تيليجرام — تصفّح المنتجات، والتحقق من رصيدك، والشراء — لكن في صورة واجهة HTTP صغيرة وموقّعة يمكنك استدعاؤها من متجرك أو نظامك الخاص. The Reseller API mirrors exactly what you can already do inside the D2Bulk Telegram bot — browsing products, checking your balance and buying — but as a small, signed HTTP API you can call from your own store or backend.

  • جميع الطلبات والردود بصيغة JSON.All requests and responses are JSON.
  • يجب أن تُرسَل جميع الطلبات عبر HTTPS؛ يُرفض أي طلب عبر HTTP العادي.All requests must use HTTPS. Plain HTTP requests are rejected.
  • تُوثَّق كل عملية طلب بمفتاح API وتوقيع HMAC-SHA256 — بلا جلسات وبلا ملفات تعريف ارتباط (cookies).Every request is authenticated with an API key + HMAC-SHA256 signature — no session, no cookies.
  • تُنفَّذ الطلبات خصماً من رصيد حسابك في D2Bulk، بسعر الريسيلر الخاص بك.Orders are placed against your own D2Bulk account balance, at your reseller pricing.

الحصول على مفتاح الـ APIGetting your API key

بلا نموذج تسجيل، وبلا انتظار موافقة — يُولَّد مفتاحك فوراً من داخل بوت D2Bulk. No sign-up form, no waiting for approval — your key is generated instantly from inside the D2Bulk bot.

  1. افتح بوت D2Bulk على تيليجرام وادخل على 💳 My Account ← ✏️ API. Open the D2Bulk bot on Telegram and go to 💳 My Account → ✏️ API.
  2. اضغط "🔑 Generate API Key". يتم إنشاء api_key وapi_secret فوراً ويظهران لك مباشرة. Tap "🔑 Generate API Key". Your api_key and api_secret are created and shown to you right there.
  3. احتفظ بالسر في مكان آمن. يمكنك رؤيته مرة أخرى في أي وقت تفتح فيه هذه الشاشة (إلى أن تُجدِّده)، لكن تعامل معه كأنه كلمة مرور — فأي شخص يملكه يستطيع تنفيذ طلبات باستخدام رصيدك. Store the secret safely. It's shown to you again any time you reopen that screen (until you regenerate), but treat it like a password — anyone who has it can place orders using your balance.
  4. اختياري: استخدم 🛡️ IP Filter من نفس الشاشة لتقييد المفتاح بعنوان (أو عناوين) IP الخاصة بسيرفرك. راجع تقييد عناوين IP. Optional: use 🛡️ IP Filter on the same screen to restrict the key to your server's IP address(es). See IP filtering.
فقدت السر أو تسرّب منك؟Lost or leaked your secret? اضغط "🔄 Regenerate API Key" في نفس شاشة البوت. هذا يُعطِّل المفتاح القديم فوراً ويُصدر زوجاً جديداً. Tap "🔄 Regenerate API Key" in the same bot screen. This disables the old key immediately and issues a new pair.

المصادقةAuthentication

يُوقَّع كل طلب بخوارزمية HMAC-SHA256 على نص ثابت، باستخدام api_secret الخاص بك. لا توجد رموز دخول (bearer tokens) ولا جلسات تحتاج لإدارتها. Every request is signed with HMAC-SHA256 over a fixed string, using your api_secret. There are no bearer tokens or sessions to manage.

الترويسات (Headers) المطلوبةRequired headers

الترويسةHeaderالوصفDescription
X-API-KEYمفتاحك العام (api_key).Your public api_key.
X-TIMESTAMPالوقت الحالي بصيغة Unix timestamp بالثواني. يجب ألا يتجاوز الفارق 60 ثانية عن وقت السيرفر.Current Unix time in seconds. Must be within 60 seconds of server time.
X-SIGNATUREتوقيع HMAC-SHA256 بصيغة hex — التفاصيل أدناه.Hex-encoded HMAC-SHA256 signature — see below.

معادلة التوقيعSigning formula

// The exact string you sign, in order, separated by "\n":
string_to_sign = METHOD + "\n" + PATH + "\n" + TIMESTAMP + "\n" + RAW_BODY
signature      = hex(HMAC_SHA256(api_secret, string_to_sign))
  • METHOD — طريقة HTTP بحروف كبيرة، مثل GET أو POST.METHOD — uppercase HTTP method, e.g. GET or POST.
  • PATH — مسار الطلب بعد /api/v1، مع الشرطة المائلة في البداية وبدون query string. مثال: من أجل https://api.d2bulk.com/api/v1/orders/D2B-1A2B3C يكون التوقيع على /orders/D2B-1A2B3C.PATH — the request path after /api/v1, including the leading slash and no query string. E.g. for https://api.d2bulk.com/api/v1/orders/D2B-1A2B3C, sign /orders/D2B-1A2B3C.
  • TIMESTAMP — نفس القيمة المُرسَلة في X-TIMESTAMP.TIMESTAMP — the same value sent in X-TIMESTAMP.
  • RAW_BODY — نص جسم الطلب (body) كما أُرسل بالضبط. نص فارغ في حالة طلبات GET.RAW_BODY — the exact raw request body as sent. Empty string for GET requests.
function signRequest(string $method, string $path, string $body, string $apiKey, string $apiSecret): array {
    $timestamp = (string) time();
    $stringToSign = $method . "\n" . $path . "\n" . $timestamp . "\n" . $body;
    $signature = hash_hmac('sha256', $stringToSign, $apiSecret);

    return [
        'X-API-KEY'   => $apiKey,
        'X-TIMESTAMP' => $timestamp,
        'X-SIGNATURE' => $signature,
    ];
}
import time, hmac, hashlib

def sign_request(method, path, body, api_key, api_secret):
    timestamp = str(int(time.time()))
    string_to_sign = f"{method}\n{path}\n{timestamp}\n{body}"
    signature = hmac.new(api_secret.encode(), string_to_sign.encode(), hashlib.sha256).hexdigest()
    return {
        "X-API-KEY": api_key,
        "X-TIMESTAMP": timestamp,
        "X-SIGNATURE": signature,
    }
# Example for GET /balance (empty body) — replace TS/SIG with real values
TS=$(date +%s)
BODY=""
SIG=$(printf "GET\n/balance\n%s\n%s" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$API_SECRET" | sed 's/^.* //')

curl https://api.d2bulk.com/api/v1/balance \
  -H "X-API-KEY: $API_KEY" \
  -H "X-TIMESTAMP: $TS" \
  -H "X-SIGNATURE: $SIG"

نقاط الوصولEndpoints

جميع نقاط الوصول أدناه نسبية إلى الرابط الأساسي https://api.d2bulk.com/api/v1، وتتطلب ترويسات المصادقة الموضحة أعلاه. All endpoints below are relative to the base URL https://api.d2bulk.com/api/v1 and require the authentication headers described above.

GET/catalog

يُرجع كل المنتجات المتاحة لك، مُسعَّرة بسعر الريسيلر الخاص بك.Returns every product available to you, priced at your reseller rate.

{
  "ok": true,
  "data": {
    "products": [
      {
        "id": 1024,
        "name": "Google Play Gift Card 10 USD",
        "price": 9.20,
        "stock": 137,
        "currency": "USD"
      }
    ]
  }
}

تعكس الأسعار سعر الريسيلر الخاص بك إن كان مُفعَّلاً لحسابك، وإلا فالسعر العادي.Prices reflect your reseller rate where one is configured for you, otherwise the standard price.

GET/balance

يُرجع رصيدك الحالي في محفظة D2Bulk.Returns your current D2Bulk wallet balance.

{ "ok": true, "data": { "balance": 482.50, "currency": "USD" } }
POST/orders

يُنفِّذ طلباً، وعند نجاحه يُعيد كود (أو أكواد) التفعيل فوراً — بنفس آلية التسليم الفوري المتاحة في البوت.Places an order and, on success, returns the redemption code(s) immediately — the same instant delivery you get in the bot.

محتوى الطلبRequest body

الحقلFieldالنوعTypeالوصفDescription
product_idintegerإلزاميrequiredمن GET /catalog.From GET /catalog.
quantityintegerإلزاميrequiredيجب ألا تتجاوز الكمية المتوفرة.Must not exceed available stock.
idempotency_keystringإلزاميrequiredمفتاح فريد لكل محاولة طلب (مثل UUID) — التفاصيل أدناه.A unique key per order attempt (e.g. a UUID) — see below.
reseller_refstringاختياريoptionalمعرّف داخلي خاص بك للطلب، يُعاد إليك كما هو لسجلاتك.Your own internal order/reference id, echoed back for your records.
أرسل دائماً idempotency_key فريداً لكل محاولة طلب.Always send a unique idempotency_key per order attempt. إذا أُعيد إرسال الطلب بنفس المفتاح (مثلاً بعد انقطاع الاتصال)، يُعيد D2Bulk نفس النتيجة الأصلية بدلاً من خصم المبلغ أو تسليم المنتج مرتين. If a request is retried with the same key (e.g. after a network timeout), D2Bulk returns the original result instead of charging you or delivering the product twice.
{
  "idempotency_key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
  "product_id": 1024,
  "quantity": 2,
  "reseller_ref": "order-88213"
}

الرد (200)Response (200)

{
  "ok": true,
  "data": {
    "order_ref": "D2B-9F3A21",
    "status": "delivered",
    "total": 18.40,
    "codes": ["XXXX-XXXX-XXXX", "YYYY-YYYY-YYYY"]
  }
}

إذا كان المنتج من مورّد خارجي، قد يعود الطلب بحالة status: "pending" بدون حقل codes بعد — تابع الحالة عبر GET /orders/{id} أو من خلال إشعار order.delivered. If the product is sourced from an upstream supplier, an order can come back as status: "pending" with no codes field yet — poll GET /orders/{id} or listen for the order.delivered webhook.

GET/orders/{id}

يبحث عن طلب واحد باستخدام order_ref الخاص به.Looks up a single order by its order_ref.

{ "ok": true, "data": { "order_ref": "D2B-9F3A21", "status": "delivered", "codes": ["XXXX-XXXX-XXXX"] } }

القيم الممكنة لحالة status: pending (قيد الانتظار) · processing (قيد المعالجة) · delivered (تم التسليم) · failed (فشل) · refunded (مُسترجَع). Possible status values: pending · processing · delivered · failed · refunded.

GET/orders

يعرض طلباتك السابقة، الأحدث أولاً.Lists your past orders, newest first.

معامل الاستعلامQuery paramالافتراضيDefaultالوصفDescription
page1رقم الصفحة.Page number.
limit50عدد النتائج في كل صفحة.Results per page.
from—تصفية بحسب التاريخ، بصيغة YYYY-MM-DD.Filter, YYYY-MM-DD.
to—تصفية بحسب التاريخ، بصيغة YYYY-MM-DD.Filter, YYYY-MM-DD.
GET /orders?page=1&limit=20&from=2026-09-01

شحن الألعاب (Game Top-Ups)Game Top-Ups

نقاط وصول منفصلة تماماً لشحن حسابات الألعاب (UC، شدة، جواهر، إلخ) بدلاً من بطاقات الكود. لا يوجد product_id/quantity هنا — تُحدَّد الباقة عبر service_id، وكل طلب يعني شحنة واحدة لـ Player ID واحد (شحن باقتين يعني طلبين منفصلين، كل واحد بـ idempotency_key مستقل). الأسعار واحدة للجميع — نفس سعر عملاء البوت، بدون سعر ريسيلر مخفّض لهذا النوع من المنتجات. A completely separate set of endpoints for topping up game accounts (UC, Diamonds, etc.) rather than redeeming code cards. There's no product_id/quantity here — a package is addressed by its service_id, and every order means exactly one top-up for one Player ID (topping up two packages means two separate orders, each with its own idempotency_key). Pricing is the same for everyone — resellers pay the exact same price a bot customer pays; there's no discounted reseller rate for this product type.

GET/topup/catalog

يُرجع كل باقات الشحن المتاحة والمُفعَّلة حالياً.Returns every currently active, priced top-up package.

معامل الاستعلامQuery paramالوصفDescription
gameاختياري — تصفية بحسب لعبة واحدة (مثل pubg). بدون هذا المعامل تُعاد كل الألعاب.Optional — filter to a single game (e.g. pubg). Omit to get every game.
{
  "ok": true,
  "data": {
    "packages": [
      {
        "service_id": "10",
        "game": "pubg",
        "game_label": "PUBGM UC & Items",
        "category": "UC Packages",
        "name": "60 UC",
        "price": 1.03,
        "currency": "USD"
      }
    ]
  }
}
POST/topup/orders

يُنفِّذ طلب شحن لباقة ولاعب مُحدَّدين. على عكس POST /orders، لا يعود الرد بحالة نهائية فوراً — الموردّ لا يؤكد النجاح أو الفشل لحظة الطلب، فتبدأ كل الطلبات بحالة processing ثم تُحدَّث تلقائياً (عبر Webhook أو بالاستعلام) عند استقرار النتيجة.Places a top-up order for a specific package and player. Unlike POST /orders, the response is never final right away — the upstream supplier doesn't confirm success or failure at request time, so every order starts as processing and is updated automatically (via webhook or by polling) once it resolves.

محتوى الطلبRequest body

الحقلFieldالنوعTypeالوصفDescription
service_idstringإلزاميrequiredمن GET /topup/catalog.From GET /topup/catalog.
player_idstringإلزاميrequiredمعرّف اللاعب الذي يُشحَن إليه — قد يكون Player ID فقط، أو Player ID|Server ID|Character Name حسب ما تتطلبه هذه الباقة بالتحديد.The player being topped up — may be just a Player ID, or Player ID|Server ID|Character Name, whatever this specific package needs.
idempotency_keystringإلزاميrequiredمفتاح فريد لكل محاولة طلب — نفس المبدأ المُستخدم في POST /orders.A unique key per order attempt — same principle as POST /orders.
reseller_refstringاختياريoptionalمعرّف داخلي خاص بك، يُعاد إليك كما هو.Your own internal reference id, echoed back as-is.
{
  "service_id": "10",
  "player_id": "123456789",
  "idempotency_key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}

الرد (200)Response (200)

{
  "ok": true,
  "data": {
    "order_id": "TOPUP-28174029C9-1791065940",
    "status": "processing",
    "total_price": 1.03,
    "player_id": "123456789",
    "created_at": "2026-10-03T22:19:00Z"
  }
}
لا تنتظر رداً نهائياً في نفس اللحظة.Don't expect a final result in the same call. كل طلب شحن يبدأ بحالة processing — راجع GET /topup/orders/{id} أو اشترك في Webhooks (الإشعارات الفورية) لمعرفة النتيجة النهائية. Every top-up order starts as processing — poll GET /topup/orders/{id} or subscribe to webhooks to learn the final outcome.
GET/topup/orders/{id}

يبحث عن طلب شحن واحد باستخدام order_id الخاص به.Looks up a single top-up order by its order_id.

{ "ok": true, "data": { "order_id": "TOPUP-28174029C9-1791065940", "status": "delivered", "total_price": 1.03, "player_id": "123456789", "created_at": "2026-10-03 22:19:00" } }

القيم الممكنة لحالة status: processing (قيد المعالجة — لم تُحسَم النتيجة بعد) · delivered (تم الشحن بنجاح) · failed (فشل الطلب — ويُرَد المبلغ إلى رصيدك تلقائياً، ويظهر السبب في error_message). Possible status values: processing (not resolved yet) · delivered (topped up successfully) · failed (order failed — your balance is refunded automatically, and the reason is in error_message).

GET/topup/orders

يعرض طلبات الشحن السابقة الخاصة بك، الأحدث أولاً. نفس معاملات GET /orders بالضبط (page, limit, from, to).Lists your past top-up orders, newest first. Exactly the same query params as GET /orders (page, limit, from, to).

GET /topup/orders?page=1&limit=20

رموز الأخطاءError codes

يتّبع كل رد خطأ نفس الشكل:Every error response follows the same shape:

{ "ok": false, "error": { "code": "insufficient_balance", "message": "..." } }
HTTPCodeالمعنىMeaning
400invalid_requestحقل مفقود أو بصيغة خاطئة.Missing or malformed field.
401invalid_signatureالتوقيع غير مطابق، أو مفتاح API غير معروف.Signature doesn't match, or unknown API key.
401timestamp_expiredفارق X-TIMESTAMP عن وقت السيرفر أكثر من 60 ثانية.X-TIMESTAMP more than 60s off server time.
403account_suspendedحساب الريسيلر الخاص بك موقوف.Your reseller account is suspended.
403ip_not_allowedالطلب وصل من عنوان IP غير مسموح به لهذا المفتاح.Request came from an IP not on your key's allow-list.
404product_not_foundproduct_id غير معروف.Unknown product_id.
404order_not_foundorder_ref غير معروف.Unknown order_ref.
409duplicate_idempotency_keyنفس المفتاح استُخدم لبيانات طلب مختلفة.Same key reused for a different order payload.
422insufficient_balanceالرصيد غير كافٍ لتغطية الطلب.Not enough balance to cover the order.
422out_of_stockالكمية المطلوبة تتجاوز المتوفر في المخزون.Requested quantity exceeds available stock.
429rate_limit_exceededعدد طلبات كبير جداً — راجع حدود معدل الطلبات أدناه.Too many requests — see rate limits below.
500internal_errorحدث خطأ من جهتنا — يمكنك إعادة المحاولة بأمان بنفس idempotency_key.Something went wrong on our side — safe to retry with the same idempotency_key.

حدود معدل الطلباتRate limits

تُطبَّق الحدود لكل مفتاح API، لكل دقيقة:Limits are applied per API key, per minute:

  • POST /orders — 10 طلبات في الدقيقةPOST /orders — 10 requests / minute
  • باقي نقاط الوصول — 60 طلباً في الدقيقةAll other endpoints — 60 requests / minute

يحتوي كل رد على ترويستَي X-RateLimit-Limit وX-RateLimit-Remaining حتى تستطيع تخفيف معدل طلباتك قبل الوصول إلى الخطأ 429.Every response includes X-RateLimit-Limit and X-RateLimit-Remaining headers so you can back off before hitting 429.

تقييد عناوين IP (اختياري)IP filtering (optional)

إذا كان تكاملك يعمل من سيرفر ثابت، يمكنك تقييد مفتاحك بعناوين IP محددة من شاشة ✏️ API ← 🛡️ IP Filter في البوت.If your integration runs from a fixed server, you can lock your key to specific IP addresses from the bot's ✏️ API → 🛡️ IP Filter screen.

  • أرسل عنوان IP واحداً أو أكثر (IPv4 أو IPv6)، مفصولة بفواصل، لتقييد المفتاح بها.Send one or more IPv4/IPv6 addresses, comma-separated, to restrict the key to them.
  • أرسل off في أي وقت لإزالة القيد.Send off at any time to remove the restriction.
  • لا يوجد أي قيد افتراضياً — يعمل المفتاح من أي عنوان IP.By default, no restriction is applied — the key works from any IP.
  • يُرفض أي طلب من عنوان IP غير مسموح به برمز الخطأ ip_not_allowed (403).A request from a non-allowed IP is rejected with ip_not_allowed (403).

الإشعارات الفورية (Webhooks)Webhooks

يدعم D2Bulk إرسال أحداث الطلبات والمخزون إلى رابط تتحكم فيه أنت، موقَّعة بترويسة X-D2Bulk-Signature (توقيع HMAC-SHA256 لمحتوى الرسالة، باستخدام سر الـ webhook الخاص بك) — من الأحداث المخطط دعمها: order.delivered وorder.failed وproduct.price_changed وproduct.stock_changed. D2Bulk supports pushing order and stock events to a URL you control, signed with X-D2Bulk-Signature (HMAC-SHA256 of the raw payload, using your webhook secret) — planned events include order.delivered, order.failed, product.price_changed and product.stock_changed.

نفس الحدَثين order.delivered وorder.failed يُطلَقان أيضاً لطلبات شحن الألعاب (POST /topup/orders) لحظة استقرار نتيجتها — وهو البديل عن انتظار استعلامك المتكرر على GET /topup/orders/{id}. The same two events, order.delivered and order.failed, also fire for Game Top-Up orders (POST /topup/orders) the moment they resolve — this is the alternative to repeatedly polling GET /topup/orders/{id}.

إعداد الـ Webhook الذاتي غير متاح حالياً.Self-service webhook setup isn't live yet. إلى أن يتوفر، تواصل مع فريق D2Bulk لتسجيل رابط الـ webhook الخاص بحسابك يدوياً. في هذه الأثناء، تابع حالة الطلب عبر GET /orders/{id} — ولا تعتمد على الـ webhook وحده أبداً. Until then, contact the D2Bulk team to have a webhook URL registered for your account manually. In the meantime, poll GET /orders/{id} to confirm order status — never rely on a webhook alone.

أفضل الممارساتBest practices

  • أرسل دائماً idempotency_key فريداً لكل محاولة طلب حتى لا تتسبب إعادة المحاولة في خصم مضاعف.Always send a unique idempotency_key per order attempt so a retried request never double-charges you.
  • جدِّد السر الخاص بك دورياً (كل 90 يوماً على الأقل، وفوراً إذا اشتبهت في تسرّبه) باستخدام "🔄 Regenerate API Key" في البوت.Rotate your secret periodically (at least every 90 days, and immediately if you suspect it leaked) using "🔄 Regenerate API Key" in the bot.
  • قيِّد الوصول بعنوان IP إذا كان تكاملك يعمل من سيرفر ثابت — راجع تقييد عناوين IP.Restrict by IP if you integrate from a fixed server — see IP filtering.
  • تعامل مع الطلبات ذات الحالة pending — بعض المنتجات تُورَّد من مزوّد خارجي ولا تُسلَّم فوراً. تابع GET /orders/{id} حتى تستقر الحالة.Handle pending orders — some products are sourced from an upstream supplier and aren't delivered instantly. Poll GET /orders/{id} until status settles.
  • راقب ترويسات حدود المعدل وخفِّف من طلباتك قبل الوصول إلى الخطأ 429.Watch the rate-limit headers and back off before you hit 429.
  • استخدم HTTPS فقط — تُرفض طلبات HTTP العادية مباشرة.Use HTTPS only — plain HTTP requests are rejected outright.