OpenAPI 3.1الإصدار v1 17 نقطة نهاية · 11 حدث ويب هوك

واجهة التاجر في Delivery Syria

تسعير الطرود وإنشاؤها وعرضها وتتبّعها وإلغاؤها، وقراءة كشف المحفظة، وإدارة روابط الويب هوك.

استورد هذا الملف في Postman أو Insomnia أو أي أداة تدعم OpenAPI 3.1، أو أعطِ الأداة العنوان الظاهر أدناه. الخادم في الملف نسبي (بلا نطاق): بعد الاستيراد اضبط عنوان منصتك على أنه العنوان الأساسي.

URL
https://deliverysyria.com/docs/api/merchant-v1.json

نظرة عامة

تتيح واجهة التاجر (/api/v1) لنظام تاجر المنصة العمل مع الطرود والمحفظة. كل استدعاء يُوثَّق بمفتاح API في ترويسة Bearer، وكل ردّ بصيغة JSON وبالغلاف نفسه: {"success": true, "data": ...} (مع meta في القوائم المرقّمة) أو {"success": false, "error": {"code", "message"}}. أرسل دائماً Accept: application/json.

كُتب هذا المستند من كود التطبيق، وتفحصه اختبارات آلية مقابل المسارات وقواعد التحقق وأشكال الردود الفعلية. وهو يصف ما يفعله الكود فقط. ولا توجد ترويسة للإصدار ولا دعم لـ Idempotency-Key ولا لوحة «جرّب الآن». وحدود الطلبات موصوفة في كل عملية: طلبات في الدقيقة لكل عنوان IP، إضافة إلى حدود باقتك.

للأدلة والشروحات اقرأ مقالات المطورين في مركز التوثيق.

العنوان الأساسي
https://YOUR_DOMAIN/api/v1 استبدل YOUR_DOMAIN بعنوان منصتك.
المصادقة

مفتاح الـ API الخاص بالمطوّر لديك في ترويسة Authorization: Authorization: Bearer YOUR_API_KEY. تُقرأ هذه الترويسة فقط؛ والمفتاح في الاستعلام أو في الجسم يُتجاهل. أنشئ المفتاح من لوحة التاجر (الويب هوك والـ API ثم مفتاح API للمطورين). وهو يعمل على /api/v1 فقط: المفاتيح الأخرى (ربط المتاجر ومفتاح الشركة) تعطي invalid_key.

HTTP
Authorization: Bearer YOUR_API_KEY
Accept-Language

لغة رسائل الأخطاء والتسميات (تسمية الحالة وملاحظات الأحداث والأسماء). إذا بدأت القيمة بـ en جاء الرد بالإنجليزية، وأي قيمة أخرى أو غياب الترويسة يعطي العربية. الحقول المقروءة آلياً لا تتغير أبداً.

حدود الطلبات

تُطبَّق ثلاث طبقات. (1) حدّ عام قدره 60 طلباً في الدقيقة لكل عنوان IP على كل طلب /api. (2) حدود المسارات، وتُحتسب لكل عنوان IP على عدّاد واحد مشترك: حدّ المجموعة 120 في الدقيقة، و60 و30 و20 و10 لكل من POST /parcels وGET /statement وPOST /webhooks وPOST /webhooks/{id}/test؛ ولأن الطلب إلى مسار له حدّ خاص يُحسب على المجموعة وعلى المسار معاً، فإن المسار ذا الحدّ الخاص لا يتيح من عنوان IP واحد إلا نحو نصفه. (3) حدود الباقة لكل حساب في الدقيقة وفي اليوم (429 rate_limited مع Retry-After). وتُذكر الحدود المطبّقة على كل عملية في العملية نفسها.

لا توجد لوحة «جرّب الآن»

لا يتضمن هذا المرجع لوحة «جرّب الآن» ولا يرسل أي طلب من متصفحك. فذلك يعني إدخال مفتاح API حقيقي في صفحة ويب واستدعاء الواجهة الفعلية ببيانات حقيقية. اختبر بالأمثلة البرمجية ومفتاحك الخاص من خادمك أو من الطرفية.

الحساب

ملف التاجر وباقته وأرصدة محافظه.

الطريقة GET /me #

جلب حسابك

تُرجع معرّف التاجر والاسم التجاري والباقة وأرصدة المحافظ. وهي أول استدعاء مناسب للتأكد من المفتاح.

الردود

200 حسابك.

حسابك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

حسابك.

merchant_id integer مطلوب

معرّف حسابك كتاجر.

business_name string | null مطلوب

الاسم التجاري للتاجر.

plan object | null مطلوب

آخر اشتراك، أو null عند عدم وجود سجل اشتراك.

name string | null مطلوب

اسم الباقة.

expires_on string (date) مطلوب

تاريخ انتهاء الاشتراك (YYYY-MM-DD).

active boolean مطلوب

هل الباقة فعّالة حالياً.

balances object مطلوب

أرصدة المحافظ بالدولار.

recharge number مطلوب

رصيد الشحن (محفظة الشحن) بالدولار.

cod_due number مطلوب

مستحقات التحصيل عند الاستلام (محفظة المستحقات) بالدولار.

held number مطلوب

المبالغ المحجوزة بالدولار.

company_due number مطلوب

مستحقات الشركة بالدولار.

currency string مطلوب

رمز عملة المنصة المضبوط ($ افتراضياً). وهو ليس وحدة الأرصدة التي تكون بالدولار دائماً؛ أما GET /statement فيُرجع الرمز USD.

مثال

JSON · 200
{
  "success": true,
  "data": {
    "merchant_id": 12,
    "business_name": "Example Shop",
    "plan": {
      "name": "Example Plan",
      "expires_on": "2026-12-01",
      "active": true
    },
    "balances": {
      "recharge": 150.5,
      "cod_due": 320,
      "held": 0,
      "company_due": 0
    },
    "currency": "$"
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/me" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/me");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/me", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/me",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

قوائم الاختيار

قوائم مرجعية تحتاجها قبل إنشاء الطرد: شركات التوصيل والشحن والمحافظات وأماكن الاستلام ومخزون المستودعات.

الطريقة GET /companies #

قائمة شركات التوصيل والشحن

تعرض شركات التوصيل وشركات الشحن التي يمكنك استخدامها. أرسل قيمة id على أنها company_id عند التسعير أو إنشاء الطرد. القائمة غير مرقّمة.

  • الطلب GET /api/v1/companies
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

الردود

200 الشركات التي يمكنك استخدامها.

الشركات التي يمكنك استخدامها.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<object> مطلوب
id integer مطلوب

أرسله على أنه company_id.

name string مطلوب

اسم الشركة.

type string مطلوب

delivery_company أو carrier (شركة شحن خارجية).

إحدى القيم: delivery_company carrier

pricing_mode string مطلوب

طريقة احتساب السعر: governorate (مبلغ ثابت حسب المحافظة) أو per_kg أو per_km أو km_kg أو carrier_quote (سعر شركة الشحن نفسها). تظهر per_km لشركة توصيل لا تحمل آلية محفوظة.

إحدى القيم: governorate per_kg per_km km_kg carrier_quote

supports_own_account boolean مطلوب

تكون true عندما تسمح شركة الشحن بحسابات التجّار وتكون قد ربطتَ حسابك بها.

coverage object | null مطلوب

null عندما لا تقيّد الشركة التغطية؛ وإلا فرمز الدولة ثم قائمة أسماء المحافظات التي تغطيها ([] تعني كل محافظات الدولة).

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "id": 3,
      "name": "Example Delivery",
      "type": "delivery_company",
      "pricing_mode": "governorate",
      "supports_own_account": false,
      "coverage": null
    },
    {
      "id": 5,
      "name": "Example Carrier",
      "type": "carrier",
      "pricing_mode": "carrier_quote",
      "supports_own_account": true,
      "coverage": {
        "SY": []
      }
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/companies" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/companies");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/companies", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/companies",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة GET /governorates #

قائمة المحافظات

تُرجع id وname وname_ar لكل محافظة فعّالة. أرسل name أو name_ar في recipient.governorate. القائمة غير مرقّمة.

  • الطلب GET /api/v1/governorates
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

الردود

200 المحافظات الفعّالة.

المحافظات الفعّالة.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<object> مطلوب
id integer مطلوب

معرّف المحافظة. عند إرساله في recipient.governorate أرسله نصاً.

name string مطلوب

الاسم بالإنجليزية.

name_ar string مطلوب

الاسم بالعربية.

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Damascus",
      "name_ar": "دمشق"
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/governorates" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/governorates");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/governorates", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/governorates",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة GET /pickup-locations #

قائمة أماكن الاستلام لديك

تُرجع أماكن الاستلام لديك والافتراضي أولاً. عند عدم إرسال pickup_location_id مع الطرد يُستخدم المكان الافتراضي. أضف الأماكن من لوحة التاجر. القائمة غير مرقّمة.

  • الطلب GET /api/v1/pickup-locations
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

الردود

200 أماكن الاستلام لديك.

أماكن الاستلام لديك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<object> مطلوب
id integer مطلوب

أرسله على أنه pickup_location_id.

name string | null مطلوب

اسم المكان.

phone string | null مطلوب

هاتف التواصل.

address string | null مطلوب

العنوان.

lat number | null مطلوب

خط العرض.

lng number | null مطلوب

خط الطول.

default boolean مطلوب

تكون true للمكان الافتراضي (يُستخدم عند عدم إرسال pickup_location_id).

warehouse_id integer | null مطلوب

معرّف المستودع عندما يكون المكان مستودعاً، وإلا null.

active boolean مطلوب

هل يمكن استخدام المكان.

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "id": 7,
      "name": "Main branch",
      "phone": "0900000000",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null,
      "default": true,
      "warehouse_id": null,
      "active": true
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/pickup-locations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/pickup-locations");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/pickup-locations", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/pickup-locations",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة GET /warehouse/stock #

جلب بضاعتك في المستودعات

لكل حجز مستودع فعّال: المستودع ومعرّف مكان الاستلام الخاص به (استخدمه على أنه pickup_location_id للشحن من هذا المخزون) والمنصّات والأصناف بكمياتها. تُرجع قائمة فارغة عند عدم وجود حجز فعّال.

  • الطلب GET /api/v1/warehouse/stock
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

الردود

200 المخزون لكل حجز مستودع.

المخزون لكل حجز مستودع.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<object> مطلوب
warehouse_id integer مطلوب

معرّف المستودع.

warehouse string | null مطلوب

اسم المستودع.

pickup_location_id integer مطلوب

مكان الاستلام لهذا الحجز: استخدمه على أنه pickup_location_id للشحن من هذا المخزون.

pallets integer مطلوب

عدد المنصّات المحجوزة.

items array<object> مطلوب

أصناف المخزون.

item_id integer مطلوب

معرّف صنف المخزون.

sku string | null مطلوب

رمز المنتج.

name string | null مطلوب

اسم المنتج.

qty integer مطلوب

الكمية في المخزون.

reserved integer مطلوب

الكمية المحجوزة لطرود أخرى.

available integer مطلوب

الكمية التي ما زال بإمكانك شحنها.

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "warehouse_id": 1,
      "warehouse": "Example Warehouse",
      "pickup_location_id": 9,
      "pallets": 2,
      "items": [
        {
          "item_id": 5,
          "sku": "A1",
          "name": "Example item",
          "qty": 20,
          "reserved": 2,
          "available": 18
        }
      ]
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/warehouse/stock" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/warehouse/stock");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/warehouse/stock", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/warehouse/stock",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

التسعير

احتساب سعر الطرد دون إنشائه.

الطريقة POST /quote #

تسعير طرد دون إنشائه

تحسب سعر الطرد على الخادم دون إنشائه ودون خصم أي مبلغ. تأخذ الحقول نفسها المستخدمة في POST /parcels والمطلوب فقط company_id، لكن الحقول التي يحتاجها السعر تعتمد على pricing_mode للشركة (انظر GET /companies): governorate يحتاج recipient.governorate (أو عنواناً تستطيع المنصة ربطه بمحافظة، أو إحداثيات)؛ وper_kg يحتاج weight؛ وper_km يحتاج recipient.lat وrecipient.lng ومكان استلام له موقع على الخريطة؛ وkm_kg يحتاج الاثنين؛ وcarrier_quote يطلب السعر من شركة الشحن. وفي التسعير الداخلي يُقرَّب الوزن إلى كيلوغرام كامل ويُطبَّق الحد الأدنى للأجرة عند الشركة. ويختلف الرد بين شركة التوصيل وشركة الشحن (انظر Quote).

  • الطلب POST /api/v1/quote
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

جسم الطلب

application/json · مطلوب

الحقلالنوع مطلوبالوصف
company_id integer مطلوب

شركة التوصيل أو الشحن، قيمة id من GET /companies. يجب أن تكون متاحة لحسابك.

recipient object اختياري

المستلم. يمكن بدلاً من ذلك إرسال كل حقل مسطحاً في المستوى الأعلى (customer_name وcustomer_phone وcustomer_address وcustomer_city وlat وlong)؛ والشكل المتداخل هو الموثَّق.

name string اختياري

اسم المستلم.

الحد الأقصى للطول 191

phone string اختياري

رقم هاتف المستلم: أرقام ومسافات و+ و- وأقواس، من 6 إلى 30 محرفاً.

الحد الأقصى للطول 30النمط ^[+0-9\s\-()]{6,30}$

address string اختياري

عنوان المستلم.

الحد الأقصى للطول 1000

governorate string اختياري

اسم المحافظة (name بالإنجليزية أو name_ar بالعربية من GET /governorates). وإن أرسلت المعرّف فأرسله نصاً مثل "3" لأن الرقم في JSON يُرفض. مطلوب للتسعير حسب المحافظة، وإلا تحاول المنصة استنتاجها من العنوان ثم من الإحداثيات.

الحد الأقصى للطول 120يُقبل أيضاً باسم customer_city, city

lat number اختياري

خط عرض موقع المستلم. مطلوب للتسعير حسب المسافة (per_km وkm_kg).

الحد الأدنى -90الحد الأقصى 90

lng number اختياري

خط طول موقع المستلم. مطلوب للتسعير حسب المسافة (per_km وkm_kg).

الحد الأدنى -180الحد الأقصى 180يُقبل أيضاً باسم long

reference string اختياري

مرجعك الخاص (رقم الطلب). لا يؤثر في السعر.

الحد الأقصى للطول 191يُقبل أيضاً باسم invoice_no

cod_amount number اختياري

مبلغ التحصيل عند الاستلام الذي يدفعه المستلم، من 0 إلى 100,000,000 دولار أمريكي (يُحوَّل المبلغ بغير الدولار إلى الدولار بسعر المنصة قبل فحص الحد). القيمة 0 تعني مدفوع مسبقاً.

الحد الأدنى 0الحد الأقصى 100000000الافتراضي 0

currency string اختياري

رمز عملة cod_amount (لا فرق بين الأحرف الكبيرة والصغيرة). يُخزَّن المبلغ بالدولار، لذا يكون cod_amount في كائنات الطرد بالدولار دائماً. وقد لا تقبل الشركة إلا بعض العملات. وغياب سعر الصرف يعطي 422.

إحدى القيم: USD SYP SAR AED QAR KWD JOD IQD EGP LBP TRY EUR

الافتراضي USDيُقبل أيضاً باسم cod_currency

weight number اختياري

الوزن بالكيلوغرام من 0.01 إلى 1000. الافتراضي 1. في التسعير الداخلي يُقرَّب الوزن إلى كيلوغرام كامل (الحد الأدنى 1).

الحد الأدنى 0.01الحد الأقصى 1000الافتراضي 1يُقبل أيضاً باسم weight_kg

pickup_location_id integer اختياري

أحد أماكن الاستلام لديك (GET /pickup-locations). يُستخدم مكانك الافتراضي عند عدم الإرسال. وتُبلَّغ الأخطاء على الحقل shop_id.

يُقبل أيضاً باسم shop_id

note string اختياري

ملاحظة لشركة التوصيل بحد أقصى 2000 محرف.

الحد الأقصى للطول 2000

use_own_account boolean اختياري

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

shipping_paid_by string اختياري

من يدفع أجرة الشحن، لشركات الشحن التي تدعم الاختيار: sender (المرسل) أو customer (المستلم) أو included_in_cod (ضمن مبلغ التحصيل).

إحدى القيم: sender customer included_in_cod

مثال

JSON
{
  "company_id": 3,
  "recipient": {
    "governorate": "Damascus"
  },
  "weight": 2
}

الردود

200 التسعيرة.

التسعيرة.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data oneOf مطلوب

يعتمد الشكل على الشركة: شركة التوصيل تعطي QuoteDeliveryCompany وشركة الشحن تعطي QuoteCarrier (ميّز بينهما بـ pricing_mode).

بديل QuoteDeliveryCompany تسعيرة لشركة توصيل.
pricing_mode string مطلوب

آلية التسعير المستخدمة.

إحدى القيم: governorate per_kg per_km km_kg

pricing_label string | null مطلوب

تسمية آلية التسعير بلغة الطلب.

governorate string | null مطلوب

المحافظة المستخدمة في التسعير حسب المحافظة، وإلا null.

distance_km number مطلوب

المسافة المستخدمة (0 ما لم تعتمد الآلية على المسافة).

weight_kg number مطلوب

الوزن المستخدم مقرَّباً إلى كيلوغرام كامل (الحد الأدنى 1).

delivery_fee number مطلوب

أجرة التوصيل بالدولار.

platform_fee number مطلوب

رسم المنصة بالدولار.

charged_now number مطلوب

المبلغ الذي يُخصم من محفظتك عند الإنشاء: أجرة التوصيل مع رسم المنصة، أو رسم المنصة فقط لشركة التوصيل الداخلية الخاصة بك.

بديل QuoteCarrier تسعيرة لشركة شحن خارجية: كائن مختلف وأصغر. لا يتضمن pricing_label ولا governorate ولا distance_km ولا weight_kg ولا delivery_fee.
pricing_mode string مطلوب

قيمة ثابتة "carrier_quote"

carrier string مطلوب

اسم شركة الشحن.

account string مطلوب

الحساب الذي سيُستخدم: حساب المنصة أو حسابك الخاص لدى الشركة.

إحدى القيم: platform_account merchant_account

carrier_fee number مطلوب

سعر شركة الشحن بعملتها.

carrier_currency string مطلوب

عملة carrier_fee.

carrier_fee_usd number مطلوب

سعر شركة الشحن بالدولار.

platform_fee number مطلوب

رسم المنصة بالدولار.

charged_now number مطلوب

المبلغ المخصوم من محفظتك عند الإنشاء بالدولار.

held_now number مطلوب

المبلغ المحجوز حتى التسليم (حسابك الخاص لدى الشركة) بالدولار.

required_balance number مطلوب

الرصيد الذي يجب أن يتوفر في محفظتك بالدولار.

shipping_paid_by string مطلوب

من يدفع أجرة الشحن (sender أو customer أو included_in_cod).

receiver_pays number مطلوب

المبلغ الذي يدفعه المستلم عند التسليم بالدولار.

net_after_delivery number مطلوب

صافي مبلغك بعد التسليم بالدولار.

destination string | null مطلوب

ملاحظة الوجهة من شركة الشحن.

currency string مطلوب

قيمة ثابتة "USD"

مثال

JSON · 200
{
  "success": true,
  "data": {
    "pricing_mode": "governorate",
    "pricing_label": "Fixed amount per governorate",
    "governorate": "Damascus",
    "distance_km": 0,
    "weight_kg": 2,
    "delivery_fee": 6,
    "platform_fee": 1,
    "charged_now": 7
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

422 validation_failed:

validation_failed: company_id مفقود أو غير متاح لك، أو ينقص حقل يحتاجه التسعير. quote_failed: تعذّر حساب السعر. carrier_error: رفضت شركة الشحن التسعير أو تعذّر عليها.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Missing company

JSON · 422
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "company_id is required — get the list from GET /companies",
    "fields": {
      "company_id": [
        "company_id is required — get the list from GET /companies"
      ]
    }
  }
}

مثال — Price not calculated

JSON · 422
{
  "success": false,
  "error": {
    "code": "quote_failed",
    "message": "Could not calculate the price."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X POST "https://YOUR_DOMAIN/api/v1/quote" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "company_id": 3,
  "recipient": {
    "governorate": "Damascus"
  },
  "weight": 2
}'
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/quote");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'company_id' => 3,
        'recipient' => [
            'governorate' => 'Damascus',
        ],
        'weight' => 2,
    ]),
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/quote", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "company_id": 3,
    "recipient": {
      "governorate": "Damascus"
    },
    "weight": 2
  }),
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.post(
    "https://YOUR_DOMAIN/api/v1/quote",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    json={
        "company_id": 3,
        "recipient": {
            "governorate": "Damascus",
        },
        "weight": 2,
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطرود

إنشاء الطرود وعرضها وتتبّعها وإلغاؤها.

الطريقة GET /parcels #

عرض طرودك

تعرض طرودك الأحدث أولاً (حسب المعرّف) دون events. الطرود في المرحلة awaiting_funds لا تُعرض (اجلب الواحد منها برقم التتبع أو المرجع). الرد مرقّم ويتضمن meta.

معاملات الاستعلام

الاسمالنوعمطلوبالوصف
reference string اختياري

تطابق تام مع reference الذي أرسلته عند الإنشاء.

مثال ORDER-1043

from string (date) اختياري

أول يوم إنشاء YYYY-MM-DD شاملاً (بتوقيت UTC). لا يُتحقق من الصيغة: استخدم هذه الصيغة فقط.

مثال 2026-01-01

to string (date) اختياري

آخر يوم إنشاء YYYY-MM-DD شاملاً (بتوقيت UTC). لا يُتحقق من الصيغة: استخدم هذه الصيغة فقط.

مثال 2026-01-31

stage string اختياري

تصفية حسب stage للطرد. هذه القيم الست فقط تُصفّي؛ وأي قيمة أخرى (ومنها processing وawaiting_funds والأخطاء الإملائية) تُتجاهل بصمت ويعود كل شيء دون تصفية.

إحدى القيم: pending out_for_delivery delivered partially_delivered returning returned

مثال out_for_delivery

per_page integer اختياري

حجم الصفحة من 1 إلى 100 (الافتراضي 20). القيمة خارج المجال لا تُرفض بل تُقرَّب إلى أقرب حدّ، وتعود القيمة الفعلية في meta.per_page.

الحد الأدنى 1الحد الأقصى 100الافتراضي 20

page integer اختياري

رقم الصفحة ويبدأ من 1. القيمة غير الصالحة أو الأصغر من 1 تُعامل على أنها 1. والصفحة بعد الأخيرة تعيد قائمة فارغة.

الحد الأدنى 1الافتراضي 1

الردود

200 صفحة من الطرود.

صفحة من الطرود.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<Parcel> مطلوب
meta Meta مطلوب

كتلة الترقيم. لا توجد روابط ولا مؤشر (cursor).

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "id": 1043,
      "tracking_number": "DS-000000",
      "reference": "ORDER-1043",
      "stage": "out_for_delivery",
      "status_code": 7,
      "status_label": "Delivery Man Assign",
      "company_id": 3,
      "company_name": "Example Delivery",
      "external_tracking_number": null,
      "recipient": {
        "name": "Example Name",
        "phone": "0900000000",
        "governorate": "Damascus",
        "address": "Example street, building 1",
        "lat": null,
        "lng": null
      },
      "cod_amount": 25,
      "cod_collected": 0,
      "weight_kg": 1.5,
      "charges": {
        "delivery_fee": 6,
        "platform_fee": 1
      },
      "delivery_attempts": 0,
      "note": null,
      "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
      "created_at": "2026-01-01T10:00:00+00:00",
      "updated_at": "2026-01-01T12:10:00+00:00"
    }
  ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "last_page": 1
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/parcels?reference=ORDER-1043&from=2026-01-01&to=2026-01-31&stage=out_for_delivery" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/parcels?reference=ORDER-1043&from=2026-01-01&to=2026-01-31&stage=out_for_delivery");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/parcels?reference=ORDER-1043&from=2026-01-01&to=2026-01-31&stage=out_for_delivery", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/parcels",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    params={
        "reference": "ORDER-1043",
        "from": "2026-01-01",
        "to": "2026-01-31",
        "stage": "out_for_delivery",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة POST /parcels #

إنشاء طرد

تنشئ طرداً. تُحسب أجرة التوصيل على الخادم وتُخصم من محفظتك. أرسل reference نفسه مجدداً لإعادة المحاولة بأمان: تحصل على الطرد الموجود مع "duplicate": true (HTTP 200) ولا يُخصم أي مبلغ (الطرود المستردّة أو المنتهية لا تُحتسب). لا توجد ترويسة Idempotency-Key. التاجر بلا باقة فعّالة يُرفض بالرمز plan_feature قبل معالجة الطرد، وبلوغ حصة الطرود يعطي 422 على الحقل plan. وإذا رفضت شركة شحن خارجية الطرد فلا يُنشأ شيء ولا يُخصم شيء (carrier_error).

جسم الطلب

application/json · مطلوب

الحقلالنوع مطلوبالوصف
company_id integer مطلوب

شركة التوصيل أو الشحن، قيمة id من GET /companies. يجب أن تكون متاحة لحسابك.

recipient object مطلوب

المستلم. يمكن بدلاً من ذلك إرسال كل حقل مسطحاً في المستوى الأعلى (customer_name وcustomer_phone وcustomer_address وcustomer_city وlat وlong)؛ والشكل المتداخل هو الموثَّق.

name string مطلوب

اسم المستلم.

الحد الأقصى للطول 191

phone string مطلوب

رقم هاتف المستلم: أرقام ومسافات و+ و- وأقواس، من 6 إلى 30 محرفاً.

الحد الأقصى للطول 30النمط ^[+0-9\s\-()]{6,30}$

address string مطلوب

عنوان المستلم.

الحد الأقصى للطول 1000

governorate string اختياري

اسم المحافظة (name بالإنجليزية أو name_ar بالعربية من GET /governorates). وإن أرسلت المعرّف فأرسله نصاً مثل "3" لأن الرقم في JSON يُرفض. مطلوب للتسعير حسب المحافظة، وإلا تحاول المنصة استنتاجها من العنوان ثم من الإحداثيات.

الحد الأقصى للطول 120يُقبل أيضاً باسم customer_city, city

lat number اختياري

خط عرض موقع المستلم. مطلوب للتسعير حسب المسافة (per_km وkm_kg).

الحد الأدنى -90الحد الأقصى 90

lng number اختياري

خط طول موقع المستلم. مطلوب للتسعير حسب المسافة (per_km وkm_kg).

الحد الأدنى -180الحد الأقصى 180يُقبل أيضاً باسم long

reference string اختياري

مرجعك الخاص الفريد (رقم الطلب) بحد أقصى 191 محرفاً. يجعل إعادة المحاولة آمنة: إرسال المرجع نفسه مجدداً يُرجع الطرد الموجود مع "duplicate": true بدل إنشاء طرد جديد.

الحد الأقصى للطول 191يُقبل أيضاً باسم invoice_no

cod_amount number اختياري

مبلغ التحصيل عند الاستلام الذي يدفعه المستلم، من 0 إلى 100,000,000 دولار أمريكي (يُحوَّل المبلغ بغير الدولار إلى الدولار بسعر المنصة قبل فحص الحد). القيمة 0 تعني مدفوع مسبقاً.

الحد الأدنى 0الحد الأقصى 100000000الافتراضي 0

currency string اختياري

رمز عملة cod_amount (لا فرق بين الأحرف الكبيرة والصغيرة). يُخزَّن المبلغ بالدولار، لذا يكون cod_amount في كائنات الطرد بالدولار دائماً. وقد لا تقبل الشركة إلا بعض العملات. وغياب سعر الصرف يعطي 422.

إحدى القيم: USD SYP SAR AED QAR KWD JOD IQD EGP LBP TRY EUR

الافتراضي USDيُقبل أيضاً باسم cod_currency

weight number اختياري

الوزن بالكيلوغرام من 0.01 إلى 1000. الافتراضي 1. في التسعير الداخلي يُقرَّب الوزن إلى كيلوغرام كامل (الحد الأدنى 1).

الحد الأدنى 0.01الحد الأقصى 1000الافتراضي 1يُقبل أيضاً باسم weight_kg

pickup_location_id integer اختياري

أحد أماكن الاستلام لديك (GET /pickup-locations). يُستخدم مكانك الافتراضي عند عدم الإرسال. وتُبلَّغ الأخطاء على الحقل shop_id.

يُقبل أيضاً باسم shop_id

warehouse_items array<object> اختياري

المنتجات التي تُشحن من مخزونك. مطلوبة عندما يكون مكان الاستلام مستودعاً، وتُهمل في غير ذلك. وتُقبل أيضاً باسم items.

يُقبل أيضاً باسم items

sku string اختياري

رمز المنتج (SKU) في المخزون.

item_id integer اختياري

معرّف صنف المخزون (بديل لـ sku).

qty integer مطلوب

الكمية التي تخرج مع الطرد؛ يجب ألا تتجاوز الكمية المتاحة.

الحد الأدنى 1

note string اختياري

ملاحظة لشركة التوصيل بحد أقصى 2000 محرف.

الحد الأقصى للطول 2000

use_own_account boolean اختياري

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

shipping_paid_by string اختياري

من يدفع أجرة الشحن، لشركات الشحن التي تدعم الاختيار: sender (المرسل) أو customer (المستلم) أو included_in_cod (ضمن مبلغ التحصيل).

إحدى القيم: sender customer included_in_cod

wait_for_balance boolean اختياري

عند عدم كفاية رصيد المحفظة يُحفظ الطرد بالمرحلة awaiting_funds (الرد 201 ويُخفى عن GET /parcels) بدل الفشل بالرمز 402. تُكمله مهمة كل ساعة عند توفر الرصيد وتلغيه بعد 24 ساعة.

مثال

JSON
{
  "company_id": 3,
  "reference": "ORDER-1043",
  "recipient": {
    "name": "Example Name",
    "phone": "0900000000",
    "governorate": "Damascus",
    "address": "Example street, building 1"
  },
  "cod_amount": 25,
  "weight": 1.5,
  "note": "Call before arriving"
}

الردود

200 يوجد طرد بالمرجع reference نفسه:

يوجد طرد بالمرجع reference نفسه: يُرجع كما هو مع duplicate: true.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

duplicate boolean مطلوب

قيمة ثابتة true

مثال

JSON · 200
{
  "success": true,
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  },
  "duplicate": true
}
201 تم إنشاء الطرد.

تم إنشاء الطرد.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON · 201
{
  "success": true,
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "processing",
    "status_code": 5,
    "status_label": "Received Warehouse",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

402 insufficient_balance:

insufficient_balance: رصيد المحفظة لا يكفي (تذكر الرسالة المبلغ المطلوب والمتاح). أرسل wait_for_balance: true لحفظ الطرد بالمرحلة awaiting_funds بدلاً من ذلك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Balance too low

JSON · 402
{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Insufficient wallet balance. Required: 7.00, available: 2.00"
  }
}

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

422 validation_failed:

validation_failed: حقل مفقود أو خاطئ (يسردها fields بأسماء المنصة الداخلية)، أو company_id غير متاح لك، أو استُنفدت الحصة (plan). carrier_error: رفضت شركة الشحن الخارجية الطرد أو أن حساب الشركة غير صالح للاستخدام.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Missing recipient phone

JSON · 422
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "The customer phone field is required.",
    "fields": {
      "customer_phone": [
        "The customer phone field is required."
      ]
    }
  }
}

مثال — Carrier refused

JSON · 422
{
  "success": false,
  "error": {
    "code": "carrier_error",
    "message": "Localized message from the carrier."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X POST "https://YOUR_DOMAIN/api/v1/parcels" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "company_id": 3,
  "reference": "ORDER-1043",
  "recipient": {
    "name": "Example Name",
    "phone": "0900000000",
    "governorate": "Damascus",
    "address": "Example street, building 1"
  },
  "cod_amount": 25,
  "weight": 1.5,
  "note": "Call before arriving"
}'
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/parcels");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'company_id' => 3,
        'reference' => 'ORDER-1043',
        'recipient' => [
            'name' => 'Example Name',
            'phone' => '0900000000',
            'governorate' => 'Damascus',
            'address' => 'Example street, building 1',
        ],
        'cod_amount' => 25,
        'weight' => 1.5,
        'note' => 'Call before arriving',
    ]),
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/parcels", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "company_id": 3,
    "reference": "ORDER-1043",
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1"
    },
    "cod_amount": 25,
    "weight": 1.5,
    "note": "Call before arriving"
  }),
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.post(
    "https://YOUR_DOMAIN/api/v1/parcels",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    json={
        "company_id": 3,
        "reference": "ORDER-1043",
        "recipient": {
            "name": "Example Name",
            "phone": "0900000000",
            "governorate": "Damascus",
            "address": "Example street, building 1",
        },
        "cod_amount": 25,
        "weight": 1.5,
        "note": "Call before arriving",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة GET /parcels/{tracking} #

جلب طرد واحد مع أحداثه

تأخذ رقم تتبع أو reference (يُعتمد أحدث تطابق) وتُرجع الطرد مع events بترتيب زمني. وتجد أيضاً الطرود في المرحلة awaiting_funds.

  • الطلب GET /api/v1/parcels/{tracking}
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

معاملات المسار

الاسمالنوعمطلوبالوصف
tracking string مطلوب

رقم التتبع، أو reference الذي أرسلته عند إنشاء الطرد (يُعتمد أحدث تطابق؛ وقد يشير المرجع إلى طرد غير الذي تقصده، لذا ألغِ برقم التتبع).

مثال DS-000000

الردود

200 الطرد مع أحداثه.

الطرد مع أحداثه.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

كائن الطرد مع تاريخه (events). يُرجَع عند جلب طرد واحد.

يتضمن كل حقول Parcel
events array<object> مطلوب

تاريخ الطرد بترتيب زمني. يظهر فقط عند جلب طرد واحد.

status_code integer مطلوب

رمز الحالة الداخلي الدقيق لتلك الخطوة.

stage string مطلوب

المرحلة المبسطة لتلك الخطوة.

إحدى القيم: pending processing out_for_delivery delivered partially_delivered returning returned

status_label string مطلوب

تسمية الحالة بلغة الطلب.

note string | null مطلوب

ملاحظة نصية مسجّلة مع الحدث.

at string (date-time) | null مطلوب

وقت الحدث (ISO 8601 مع فرق التوقيت عن UTC).

مثال

JSON · 200
{
  "success": true,
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00",
    "events": [
      {
        "status_code": 1,
        "stage": "pending",
        "status_label": "Pending",
        "note": "Parcel created (api)",
        "at": "2026-01-01T10:00:00+00:00"
      },
      {
        "status_code": 5,
        "stage": "processing",
        "status_label": "Received Warehouse",
        "note": null,
        "at": "2026-01-01T10:00:01+00:00"
      }
    ]
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

404 not_found:

not_found: لا يوجد طرد بهذا الرقم أو المرجع في حسابك (والطرد الملغى لم يعد موجوداً).

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Unknown parcel

JSON · 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "No parcel with this number for your account."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/parcels/DS-000000" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/parcels/DS-000000");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/parcels/DS-000000", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/parcels/DS-000000",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة POST /parcels/{tracking}/cancel #

إلغاء طرد واسترجاع الأجرة

تلغي الطرد وتسترجع ما خُصم عند الإنشاء. لا تعمل إلا ما دامت الحالة «معلّق» أو «مستلم في المستودع» وليس للطرد external_tracking_number. يُحذف الطرد (والاستدعاء الثاني يعطي 404). والإلغاء عبر الـ API لا يرسل ويب هوك parcel.cancelled.

معاملات المسار

الاسمالنوعمطلوبالوصف
tracking string مطلوب

رقم التتبع، أو reference الذي أرسلته عند إنشاء الطرد (يُعتمد أحدث تطابق؛ وقد يشير المرجع إلى طرد غير الذي تقصده، لذا ألغِ برقم التتبع).

مثال DS-000000

الردود

200 أُلغي الطرد واستُرجعت الأجرة.

أُلغي الطرد واستُرجعت الأجرة.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

نتيجة الإلغاء.

tracking_number string مطلوب

رقم تتبع الطرد الملغى.

cancelled boolean مطلوب

قيمة ثابتة true

refunded boolean مطلوب

قيمة ثابتة true

مثال

JSON · 200
{
  "success": true,
  "data": {
    "tracking_number": "DS-000000",
    "cancelled": true,
    "refunded": true
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

404 not_found:

not_found: لا يوجد طرد بهذا الرقم في حسابك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Unknown parcel

JSON · 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "No parcel with this number for your account."
  }
}
409 not_cancellable:

not_cancellable: خرج الطرد من الحالة «معلّق» أو «مستلم في المستودع»، أو أُرسل إلى شركة شحن خارجية.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Already on its way

JSON · 409
{
  "success": false,
  "error": {
    "code": "not_cancellable",
    "message": "The parcel is out for delivery or sent to the shipping company — it cannot be cancelled from here."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X POST "https://YOUR_DOMAIN/api/v1/parcels/DS-000000/cancel" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/parcels/DS-000000/cancel");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/parcels/DS-000000/cancel", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.post(
    "https://YOUR_DOMAIN/api/v1/parcels/DS-000000/cancel",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

كشف الحساب

كشف حساب المحفظة لفترة.

الطريقة GET /statement #

جلب كشف حساب المحفظة

كشف حساب محفظتك لفترة: الرصيد الافتتاحي والختامي لكل محفظة، وملخص لكل نوع حركة، وكل الحركات (الأقدم أولاً). المبالغ بالدولار. الرد مرقّم: meta يعدّ lines، أما wallets وby_category فتغطيان الفترة كلها.

  • الطلب GET /api/v1/statement
  • حدّ الطلبات في الدقيقة لكل عنوان IP 60 عاماً، و120 للواجهة كلها، و30 لهذا المسار
  • يتطلب ميزة الباقة: الـ API (تُفحص عندما تُطبَّق الباقات على حسابك)
  • أدلة مرجع واجهة التاجر API v1

معاملات الاستعلام

الاسمالنوعمطلوبالوصف
from string (date) اختياري

أول يوم YYYY-MM-DD. الافتراضي: أول يوم في الشهر الحالي. يُقبل بصيغة YYYY-MM-DD حرفياً فقط وإلا يُتجاهل. وإذا جاء from بعد to تُبدَّل القيمتان، والمدى الأطول من 366 يوماً يُقصَّر بتحريك from.

مثال 2026-01-01

to string (date) اختياري

آخر يوم YYYY-MM-DD. الافتراضي: اليوم. بالقواعد نفسها المطبّقة على from.

مثال 2026-01-31

wallet string اختياري

هذه المحفظة فقط: recharge (رصيد الشحن) أو held (المبالغ المحجوزة) أو return (مستحقات التحصيل) أو payout_pending. أي قيمة أخرى تُتجاهل.

إحدى القيم: recharge held return payout_pending

category string اختياري

هذا النوع من الحركات فقط، مثل parcel_created. أحرف لاتينية صغيرة وشرطات سفلية (من 2 إلى 60 محرفاً)؛ ولا يُتحقق منه من قائمة الأنواع المعروفة، فالقيمة المجهولة لا تعيد أي سطر.

النمط ^[a-z_]{2,60}$

مثال parcel_created

per_page integer اختياري

حجم الصفحة من 1 إلى 500 (الافتراضي 100). القيمة خارج المجال لا تُرفض بل تُقرَّب إلى أقرب حدّ، وتعود القيمة الفعلية في meta.per_page.

الحد الأدنى 1الحد الأقصى 500الافتراضي 100

page integer اختياري

رقم الصفحة ويبدأ من 1. القيمة غير الصالحة أو الأصغر من 1 تُعامل على أنها 1. والصفحة بعد الأخيرة تعيد قائمة فارغة.

الحد الأدنى 1الافتراضي 1

الردود

200 كشف الحساب.

كشف الحساب.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

كشف المحفظة لفترة. كل المبالغ بالدولار.

period object مطلوب

الفترة المطبّقة فعلياً.

from string (date) مطلوب

أول يوم (YYYY-MM-DD).

to string (date) مطلوب

آخر يوم (YYYY-MM-DD).

currency string مطلوب

قيمة ثابتة "USD"

wallets array<object> مطلوب

الرصيد الافتتاحي والختامي لكل محفظة. تغطي الفترة كلها بصرف النظر عن الصفحة.

wallet string مطلوب

رمز المحفظة.

إحدى القيم: recharge held return payout_pending

name string مطلوب

تسمية المحفظة بلغة الطلب.

opening number مطلوب

الرصيد قبل الفترة.

credits number مطلوب

مجموع الإيداعات في الفترة.

debits number مطلوب

مجموع السحوبات في الفترة.

closing number مطلوب

الرصيد في نهاية الفترة.

count integer مطلوب

عدد الحركات.

by_category array<object> مطلوب

ملخص لكل نوع حركة. يغطي الفترة كلها بصرف النظر عن الصفحة.

category string مطلوب

رمز نوع الحركة، مثل parcel_created.

name string مطلوب

تسمية النوع بلغة الطلب.

credits number مطلوب

إيداعات هذا النوع.

debits number مطلوب

سحوبات هذا النوع.

count integer مطلوب

عدد الحركات.

lines array<object> مطلوب

حركات الصفحة المطلوبة، الأقدم أولاً (التاريخ ثم المعرّف). يسري الترقيم على هذه القائمة فقط.

id integer مطلوب

معرّف الحركة.

date string (date-time) مطلوب

وقت الحركة (ISO 8601).

wallet string مطلوب

رمز المحفظة.

wallet_name string مطلوب

تسمية المحفظة.

type string مطلوب

رمز نوع الحركة.

type_name string مطلوب

تسمية النوع.

credit number مطلوب

مبلغ الإيداع (0 للسحب).

debit number مطلوب

مبلغ السحب (0 للإيداع).

balance number مطلوب

رصيد المحفظة بعد الحركة.

description string | null مطلوب

وصف الحركة.

parcel string | null مطلوب

رقم التتبع عندما تتعلق الحركة بطرد.

meta Meta مطلوب

كتلة الترقيم. لا توجد روابط ولا مؤشر (cursor).

مثال

JSON · 200
{
  "success": true,
  "data": {
    "period": {
      "from": "2026-01-01",
      "to": "2026-01-31"
    },
    "currency": "USD",
    "wallets": [
      {
        "wallet": "recharge",
        "name": "Shipping balance",
        "opening": 50,
        "credits": 200,
        "debits": 132.5,
        "closing": 117.5,
        "count": 41
      }
    ],
    "by_category": [
      {
        "category": "parcel_created",
        "name": "Parcel creation fee",
        "credits": 0,
        "debits": 132.5,
        "count": 38
      }
    ],
    "lines": [
      {
        "id": 9811,
        "date": "2026-01-02T10:14:00+00:00",
        "wallet": "recharge",
        "wallet_name": "Shipping balance",
        "type": "parcel_created",
        "type_name": "Parcel creation fee",
        "credit": 0,
        "debit": 3.5,
        "balance": 46.5,
        "description": "Example description",
        "parcel": "DS-000000"
      }
    ]
  },
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 1,
    "last_page": 1
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/statement?from=2026-01-01&to=2026-01-31&category=parcel_created" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/statement?from=2026-01-01&to=2026-01-31&category=parcel_created");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/statement?from=2026-01-01&to=2026-01-31&category=parcel_created", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/statement",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    params={
        "from": "2026-01-01",
        "to": "2026-01-31",
        "category": "parcel_created",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

روابط الويب هوك

إدارة العناوين التي تستقبل إشعاراتك. أما الرسائل نفسها فمشروحة ضمن أحداث الويب هوك.

الطريقة GET /webhooks/events #

قائمة الأحداث التي يمكنك الاشتراك بها

تعرض أسماء الأحداث مع اسمها المختصر ووصفها بلغة الطلب. أرسل * أو أسماءً بعينها في events عند إنشاء الرابط. لا تُعرض ping لأنها لا تُختار.

الردود

200 الأحداث.

الأحداث.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<object> مطلوب
event string مطلوب

اسم الحدث.

إحدى القيم: parcel.created parcel.status_changed parcel.out_for_delivery parcel.delivered parcel.returning parcel.returned parcel.cancelled parcel.awaiting_funds wallet.topup wallet.withdrawal

name string مطلوب

اسم مختصر بلغة الطلب.

description string مطلوب

متى يُرسل، بلغة الطلب.

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "event": "parcel.delivered",
      "name": "Delivered",
      "description": "The parcel was delivered (fully or partially) — includes the collected amount."
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/webhooks/events" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks/events");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks/events", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/webhooks/events",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة GET /webhooks #

قائمة روابط الويب هوك لديك

تعرض روابط الويب هوك لديك. لا يُرجَع مفتاح التوقيع أبداً. القائمة غير مرقّمة.

الردود

200 روابطك.

روابطك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data array<Webhook> مطلوب

مثال

JSON · 200
{
  "success": true,
  "data": [
    {
      "id": 7,
      "name": "ERP",
      "url": "https://example.com/hooks/delivery",
      "events": [
        "parcel.delivered",
        "parcel.returned"
      ],
      "active": true,
      "disabled_reason": null,
      "last_status": null,
      "last_error": null,
      "last_sent_at": null
    }
  ]
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X GET "https://YOUR_DOMAIN/api/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "GET",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.get(
    "https://YOUR_DOMAIN/api/v1/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة POST /webhooks #

إضافة رابط ويب هوك

تنشئ رابطاً وتُرجع مفتاح توقيعه (secret) مرة واحدة. تحتاج باقة فيها ميزة الويب هوك (403 plan_feature) وتتيح 10 روابط كحد أقصى، أو حدّ باقتك إن كان أقل (422 limit_reached). يجب أن يكون العنوان https وعاماً وبلا اسم مستخدم أو كلمة مرور وعلى المنفذ 443 أو 8443. وطريقة توقيع الرسائل وإعادة إرسالها في مقالات الويب هوك.

جسم الطلب

application/json · مطلوب

الحقلالنوع مطلوبالوصف
name string | null اختياري

تسمية اختيارية بحد أقصى 100 محرف.

الحد الأقصى للطول 100

url string (uri) مطلوب

عنوان HTTPS بحد أقصى 500 محرف. يجب أن يُحلّ النطاق إلى عناوين عامة فقط، دون اسم مستخدم أو كلمة مرور، وعلى المنفذ 443 أو 8443. ولا تُتبع التحويلات.

الحد الأقصى للطول 500النمط ^[Hh][Tt][Tt][Pp][Ss]://

events array<string> مطلوب

الأحداث المطلوب استقبالها: عنصر واحد على الأقل، كل منها * أو اسم حدث بعينه.

إحدى القيم: * parcel.created parcel.status_changed parcel.out_for_delivery parcel.delivered parcel.returning parcel.returned parcel.cancelled parcel.awaiting_funds wallet.topup wallet.withdrawal

الحد الأدنى للعناصر 1

active boolean اختياري

هل الرابط مفعّل (الافتراضي true).

مثال

JSON
{
  "name": "ERP",
  "url": "https://example.com/hooks/delivery",
  "events": [
    "parcel.delivered",
    "parcel.returned"
  ]
}

الردود

201 تم إنشاء الرابط.

تم إنشاء الرابط.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

رابط ويب هوك مع مفتاح التوقيع (يظهر مرة واحدة).

id integer مطلوب

معرّف الرابط.

name string | null مطلوب

التسمية التي أعطيتها للرابط.

url string مطلوب

عنوان HTTPS الذي يستقبل الرسائل.

events array<string> مطلوب

الأحداث المشترك بها؛ ["*"] تعني كل الأحداث.

active boolean مطلوب

تكون false عند التعطيل، ومنه الإيقاف التلقائي بعد 40 محاولة فاشلة متتالية.

disabled_reason string | null مطلوب

سبب إيقاف الرابط تلقائياً.

last_status integer | null مطلوب

حالة HTTP لآخر محاولة إرسال.

last_error string | null مطلوب

خطأ آخر محاولة فاشلة.

last_sent_at string (date-time) | null مطلوب

وقت آخر محاولة (ISO 8601).

secret string مطلوب

مفتاح التوقيع (whsec_ يليه 40 محرفاً). يُرجع في هذا الرد فقط: احفظه الآن.

مثال

JSON · 201
{
  "success": true,
  "data": {
    "id": 7,
    "name": "ERP",
    "url": "https://example.com/hooks/delivery",
    "events": [
      "parcel.delivered",
      "parcel.returned"
    ],
    "active": true,
    "disabled_reason": null,
    "last_status": null,
    "last_error": null,
    "last_sent_at": null,
    "secret": "whsec_EXAMPLE_ONLY_NOT_A_REAL_SECRET"
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

422 validation_failed:

validation_failed: حقل مفقود أو خاطئ (يجب أن يكون العنوان https وعاماً وعلى المنفذ 443 أو 8443، وكل حدث * أو اسماً بعينه). limit_reached: لديك أصلاً العدد الأقصى من الروابط.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Not https

JSON · 422
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "The URL must start with https://",
    "fields": {
      "url": [
        "The URL must start with https://"
      ]
    }
  }
}

مثال — Too many endpoints

JSON · 422
{
  "success": false,
  "error": {
    "code": "limit_reached",
    "message": "You have reached your plan limit: 10 webhook links."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X POST "https://YOUR_DOMAIN/api/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "ERP",
  "url": "https://example.com/hooks/delivery",
  "events": [
    "parcel.delivered",
    "parcel.returned"
  ]
}'
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'name' => 'ERP',
        'url' => 'https://example.com/hooks/delivery',
        'events' => [
            'parcel.delivered',
            'parcel.returned',
        ],
    ]),
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "ERP",
    "url": "https://example.com/hooks/delivery",
    "events": [
      "parcel.delivered",
      "parcel.returned"
    ]
  }),
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.post(
    "https://YOUR_DOMAIN/api/v1/webhooks",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    json={
        "name": "ERP",
        "url": "https://example.com/hooks/delivery",
        "events": [
            "parcel.delivered",
            "parcel.returned",
        ],
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة DELETE /webhooks/{id} #

حذف رابط ويب هوك

تحذف الرابط. الرسائل التي ما زالت بانتظار إعادة الإرسال تُعلَّم فاشلة عند حلول موعدها.

معاملات المسار

الاسمالنوعمطلوبالوصف
id integer مطلوب

معرّف رابط الويب هوك (من GET /webhooks).

مثال 7

الردود

200 تم حذف الرابط.

تم حذف الرابط.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

نتيجة الحذف.

deleted boolean مطلوب

قيمة ثابتة true

مثال

JSON · 200
{
  "success": true,
  "data": {
    "deleted": true
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

404 not_found:

not_found: لا يوجد هذا الرابط في حسابك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Unknown webhook endpoint

JSON · 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "Link not found."
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X DELETE "https://YOUR_DOMAIN/api/v1/webhooks/7" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks/7");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "DELETE",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks/7", {
  method: "DELETE",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.delete(
    "https://YOUR_DOMAIN/api/v1/webhooks/7",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة PATCH /webhooks/{id} #

تعديل رابط ويب هوك

تعدّل name أو url أو events أو active؛ أرسل ما تريد تغييره فقط. تفعيل active من جديد يصفّر عدّاد الإخفاق ويمسح سبب الإيقاف.

معاملات المسار

الاسمالنوعمطلوبالوصف
id integer مطلوب

معرّف رابط الويب هوك (من GET /webhooks).

مثال 7

جسم الطلب

application/json · مطلوب

الحقلالنوع مطلوبالوصف
name string | null اختياري

التسمية بحد أقصى 100 محرف.

الحد الأقصى للطول 100

url string (uri) اختياري

عنوان HTTPS الجديد (بالقواعد نفسها عند الإنشاء).

الحد الأقصى للطول 500النمط ^[Hh][Tt][Tt][Pp][Ss]://

events array<string> اختياري

القائمة الجديدة للأحداث (واحد على الأقل).

إحدى القيم: * parcel.created parcel.status_changed parcel.out_for_delivery parcel.delivered parcel.returning parcel.returned parcel.cancelled parcel.awaiting_funds wallet.topup wallet.withdrawal

الحد الأدنى للعناصر 1

active boolean اختياري

تفعيله من جديد يصفّر عدّاد الإخفاق ويمسح سبب الإيقاف.

مثال

JSON
{
  "active": true
}

الردود

200 الرابط بعد التعديل.

الرابط بعد التعديل.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data Webhook مطلوب

رابط ويب هوك (لا يُرجَع مفتاح التوقيع أبداً).

مثال

JSON · 200
{
  "success": true,
  "data": {
    "id": 7,
    "name": "ERP",
    "url": "https://example.com/hooks/delivery",
    "events": [
      "parcel.delivered",
      "parcel.returned"
    ],
    "active": true,
    "disabled_reason": null,
    "last_status": null,
    "last_error": null,
    "last_sent_at": null
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

404 not_found:

not_found: لا يوجد هذا الرابط في حسابك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Unknown webhook endpoint

JSON · 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "Link not found."
  }
}
422 validation_failed:

validation_failed: حقل خاطئ (بالقواعد نفسها عند الإنشاء).

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Not https

JSON · 422
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "The URL must start with https://",
    "fields": {
      "url": [
        "The URL must start with https://"
      ]
    }
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X PATCH "https://YOUR_DOMAIN/api/v1/webhooks/7" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "active": true
}'
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks/7");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "PATCH",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'active' => true,
    ]),
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks/7", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "active": true
  }),
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.patch(
    "https://YOUR_DOMAIN/api/v1/webhooks/7",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    json={
        "active": True,
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الطريقة POST /webhooks/{id}/test #

إرسال رسالة اختبار

ترسل رسالة ping موقَّعة إلى الرابط وتبلغك بحالة HTTP التي ردّ بها نظامك. الاختبار الناجح يصفّر عدّاد الإخفاق. وهي محدودة بـ 10 طلبات في الدقيقة على مستوى المسار (نحو 5 عملياً، انظر ملاحظات حدود الطلبات).

معاملات المسار

الاسمالنوعمطلوبالوصف
id integer مطلوب

معرّف رابط الويب هوك (من GET /webhooks).

مثال 7

الردود

200 ردّ نظامك بحالة 2xx.

ردّ نظامك بحالة 2xx.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

الحقلالنوع مطلوبالوصف
success boolean مطلوب

قيمة ثابتة true

data object مطلوب

نتيجة رسالة اختبار ناجحة.

delivered boolean مطلوب

قيمة ثابتة true

response_status integer مطلوب

حالة HTTP التي ردّ بها نظامك.

مثال

JSON · 200
{
  "success": true,
  "data": {
    "delivered": true,
    "response_status": 200
  }
}

401 مفتاح الـ API مفقود أو غير معروف. ردّ مشترك، انظر أدناه

403 الوصول مرفوض. ردّ مشترك، انظر أدناه

404 not_found:

not_found: لا يوجد هذا الرابط في حسابك.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Unknown webhook endpoint

JSON · 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "Link not found."
  }
}
422 delivery_failed:

delivery_failed: لم تصل الرسالة (ردّ غير 2xx أو تحويل أو انتهاء مهلة أو خطأ اتصال). يحمل response_status الحالة التي أعادها نظامك، أو null.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Your system refused

JSON · 422
{
  "success": false,
  "error": {
    "code": "delivery_failed",
    "message": "Not delivered: your system answered 500",
    "response_status": 500
  }
}

429 تجاوز حدّ الطلبات. ردّ مشترك، انظر أدناه

500 خطأ غير متوقع في الخادم. ردّ مشترك، انظر أدناه

أمثلة برمجية

curl
curl
curl -X POST "https://YOUR_DOMAIN/api/v1/webhooks/7/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"
PHP
PHP
<?php
$ch = curl_init("https://YOUR_DOMAIN/api/v1/webhooks/7/test");
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("DS_API_KEY"),
        "Accept: application/json",
    ],
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!($body["success"] ?? false)) {
    throw new RuntimeException("$status {$body["error"]["code"]}: {$body["error"]["message"]}");
}
print_r($body["data"]);
JavaScript
JavaScript
const response = await fetch("https://YOUR_DOMAIN/api/v1/webhooks/7/test", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.DS_API_KEY}`,
    "Accept": "application/json",
  },
});
const json = await response.json();
if (!json.success) {
  throw new Error(`${response.status} ${json.error.code}: ${json.error.message}`);
}
console.log(json.data);
Python
Python
import os
import requests

response = requests.post(
    "https://YOUR_DOMAIN/api/v1/webhooks/7/test",
    headers={
        "Authorization": f"Bearer {os.environ['DS_API_KEY']}",
        "Accept": "application/json",
    },
    timeout=30,
)
body = response.json()
if not body["success"]:
    raise RuntimeError(f"{response.status_code} {body['error']['code']}: {body['error']['message']}")
print(body["data"])

الكائنات

كائنات تُرجعها عدة نقاط نهاية وأحداث ويب هوك. يوصَف كل منها مرة واحدة هنا، وتحيل إليه الجداول الأخرى.

Parcel #

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

الحقلالنوع مطلوبالوصف
id integer مطلوب

معرّف الطرد.

tracking_number string مطلوب

رقم التتبع. استخدمه في مسارات {tracking} وفي صفحة التتبع العامة.

reference string | null مطلوب

مرجعك الخاص (رقم الطلب) المرسل عند الإنشاء.

stage string مطلوب

حالة مبسطة وثابتة. يفضّل الاعتماد عليها بدل status_code في منطق برنامجك: awaiting_funds (محفوظ بانتظار رصيد المحفظة)، وpending (الحالة 1)، وout_for_delivery (7 و8)، وdelivered (9)، وpartially_delivered (32)، وreturning (11 و12 و24 و26 و27)، وreturned (13 و30)، وprocessing (كل حالة أخرى).

إحدى القيم: pending processing out_for_delivery delivered partially_delivered returning returned awaiting_funds

status_code integer مطلوب

رمز الحالة الداخلي الدقيق (مثلاً 1 معلّق، 5 مستلم في المستودع، 7 تعيين مندوب، 9 تم التسليم، 13 رُدّ للتاجر، 32 تسليم جزئي).

status_label string مطلوب

تسمية الحالة بلغة الطلب.

company_id integer مطلوب

شركة التوصيل أو الشحن التي تتولى الطرد.

company_name string | null مطلوب

اسم تلك الشركة.

external_tracking_number string | null مطلوب

رقم التتبع لدى شركة الشحن الخارجية إن أُرسل الطرد إليها.

recipient object مطلوب

مستلم الطرد.

name string | null مطلوب

اسم المستلم.

phone string | null مطلوب

هاتف المستلم.

governorate string | null مطلوب

محافظة المستلم.

address string | null مطلوب

عنوان المستلم.

lat number | null مطلوب

خط عرض موقع المستلم.

lng number | null مطلوب

خط طول موقع المستلم.

cod_amount number مطلوب

مبلغ التحصيل عند الاستلام، بالدولار الأمريكي دائماً.

cod_collected number مطلوب

المبلغ المحصَّل حتى الآن بالدولار (المبلغ المحصَّل عند التسليم الجزئي).

weight_kg number | null مطلوب

وزن الطرد بالكيلوغرام.

charges object مطلوب

رسوم الطرد.

delivery_fee number مطلوب

أجرة التوصيل بالدولار (تكلفة شركة الشحن لطرد الشحن).

platform_fee number مطلوب

رسم المنصة بالدولار.

delivery_attempts integer مطلوب

عدد محاولات التسليم.

note string | null مطلوب

الملاحظة المرسلة مع الطرد.

tracking_url string (uri) مطلوب

صفحة التتبع العامة للطرد.

created_at string (date-time) | null مطلوب

وقت الإنشاء (ISO 8601 مع فرق التوقيت عن UTC).

updated_at string (date-time) | null مطلوب

وقت آخر تحديث (ISO 8601 مع فرق التوقيت عن UTC).

Meta #

كتلة الترقيم. لا توجد روابط ولا مؤشر (cursor).

الحقلالنوع مطلوبالوصف
page integer مطلوب

الصفحة الحالية.

per_page integer مطلوب

حجم الصفحة الفعلي.

total integer مطلوب

عدد السجلات بعد تطبيق الفلاتر.

last_page integer مطلوب

عدد الصفحات (1 عند عدم وجود نتائج).

Webhook #

رابط ويب هوك (لا يُرجَع مفتاح التوقيع أبداً).

الحقلالنوع مطلوبالوصف
id integer مطلوب

معرّف الرابط.

name string | null مطلوب

التسمية التي أعطيتها للرابط.

url string مطلوب

عنوان HTTPS الذي يستقبل الرسائل.

events array<string> مطلوب

الأحداث المشترك بها؛ ["*"] تعني كل الأحداث.

active boolean مطلوب

تكون false عند التعطيل، ومنه الإيقاف التلقائي بعد 40 محاولة فاشلة متتالية.

disabled_reason string | null مطلوب

سبب إيقاف الرابط تلقائياً.

last_status integer | null مطلوب

حالة HTTP لآخر محاولة إرسال.

last_error string | null مطلوب

خطأ آخر محاولة فاشلة.

last_sent_at string (date-time) | null مطلوب

وقت آخر محاولة (ISO 8601).

أحداث الويب هوك

ترسل المنصة هذه الرسائل إلى عناوين HTTPS التي تسجّلها (الويب هوك الصادر). كل رسالة طلب POST بصيغة JSON وموقَّع، ويُعاد إرساله إذا لم يردّ نظامك بحالة 2xx. يعرض كل حدث أدناه جسم رسالته، وتشترك الأحداث كلها في الترويسات والتوقيع نفسها.

ترويسات الطلب

الاسمالنوعالوصف
X-DS-Eventstring

اسم الحدث (مثل parcel.delivered، أو ping للاختبار).

X-DS-Event-Idstring

معرّف الحدث، evt_ يليه 24 حرفاً صغيراً. هو نفسه في كل محاولة ولكل رابط: استخدمه لتجاهل التكرار.

X-DS-Deliverystring (uuid)

معرّف UUID لهذه الرسالة إلى هذا الرابط. هو نفسه عبر المحاولات.

X-DS-Attemptinteger

رقم المحاولة ويبدأ من 1.

X-DS-Timestampstring

وقت الإرسال بثواني Unix ويتجدد في كل محاولة. وهو جزء من النص الموقَّع.

X-DS-Signaturestring

sha256= يليه التمثيل السداسي بأحرف صغيرة لـ HMAC-SHA256 بمفتاح توقيع الرابط (whsec_... بالسلسلة كاملة) على النص X-DS-Timestamp + "." + جسم الطلب الخام. قارن بدالة زمنها ثابت.

التحقق من توقيع الويب هوك (X-DS-Signature)

حدث POST parcel.created #

طرد جديد

أُنشئ طرد (من اللوحة أو الـ API أو متجر مربوط). الطرد الجديد يرسل عادةً هذا الحدث ثم parcel.status_changed (الحالة 5).

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.created"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.created",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.status_changed #

تغيّرت حالة الطرد

أي تغيير في الحالة عبر مسار عمل الطرد، ومنه الانتقال التلقائي إلى الحالة 5 بعد الإنشاء مباشرة. وقد يرسل التغيير الواحد هذا الحدث وحدث المرحلة (لكل منهما معرّف حدث خاص). لا يُرسل من نماذج الموظفين المخصصة للاستلام والمراكز ولا من بعض نماذج التراجع: اقرأ الطرد عندما تحتاج إلى حالته الحالية.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.status_changed"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.status_changed",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.out_for_delivery #

خرج للتوصيل

الطرد مع المندوب (الحالتان 7 و8).

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.out_for_delivery"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.out_for_delivery",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.delivered #

تم التسليم

سُلِّم الطرد كاملاً أو جزئياً (الحالتان 9 و32). يتضمن data.cod_collected المبلغ المحصَّل.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.delivered"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.delivered",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.returning #

قيد الإرجاع

تعذّر التسليم والطرد في طريق العودة.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.returning"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.returning",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.returned #

رُدّ للتاجر

استلم التاجر الطرد المرتجع (الحالتان 30 و13).

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.returned"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.returned",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.cancelled #

أُلغي

أبلغت شركة الشحن الخارجية المربوطة بإلغاء الطرد وعاد المبلغ إلى رصيدك. لا يُرسل عند الإلغاء عبر POST /parcels/{tracking}/cancel.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.cancelled"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.cancelled",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST parcel.awaiting_funds #

بانتظار الرصيد

حُفظ الطلب لكن رصيدك لا يكفي (مع wait_for_balance أو طلبات المتاجر). يكتمل عند شحن الرصيد.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "parcel.awaiting_funds"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data Parcel مطلوب

الطرد كما ترجعه الواجهة وكما تحمله رسائل الويب هوك (الحقول نفسها دائماً).

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "parcel.awaiting_funds",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": 1043,
    "tracking_number": "DS-000000",
    "reference": "ORDER-1043",
    "stage": "out_for_delivery",
    "status_code": 7,
    "status_label": "Delivery Man Assign",
    "company_id": 3,
    "company_name": "Example Delivery",
    "external_tracking_number": null,
    "recipient": {
      "name": "Example Name",
      "phone": "0900000000",
      "governorate": "Damascus",
      "address": "Example street, building 1",
      "lat": null,
      "lng": null
    },
    "cod_amount": 25,
    "cod_collected": 0,
    "weight_kg": 1.5,
    "charges": {
      "delivery_fee": 6,
      "platform_fee": 1
    },
    "delivery_attempts": 0,
    "note": null,
    "tracking_url": "https://YOUR_DOMAIN/t/DS-000000",
    "created_at": "2026-01-01T10:00:00+00:00",
    "updated_at": "2026-01-01T12:10:00+00:00"
  }
}

حدث POST wallet.topup #

شُحن الرصيد

أُضيف رصيد إلى محفظة الشحن لديك بطلب شحن تمت الموافقة عليه أو بدفع إلكتروني. للتجّار فقط.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "wallet.topup"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data object مطلوب

بيانات wallet.topup.

id string مطلوب

معرّف عملية الشحن (topup_<n> أو payment_<n>).

method string | null مطلوب

طريقة الدفع أو البوابة.

source string مطلوب

manual (طلب شحن تمت الموافقة عليه) أو gateway (دفع إلكتروني).

إحدى القيم: manual gateway

reference string | null اختياري

مرجع الدفع. يظهر مع gateway فقط.

amount number مطلوب

المبلغ بالدولار.

currency string مطلوب

قيمة ثابتة "USD"

recharge_balance number مطلوب

رصيد الشحن بعد الحدث بالدولار.

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "wallet.topup",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": "topup_1",
    "method": "bank_transfer",
    "source": "manual",
    "amount": 100,
    "currency": "USD",
    "recharge_balance": 150
  }
}

حدث POST wallet.withdrawal #

تقرّر طلب السحب

قُبل طلب سحب المستحقات أو رُفض. للتجّار فقط.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "wallet.withdrawal"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data object مطلوب

بيانات wallet.withdrawal.

id string مطلوب

معرّف السحب (withdrawal_<n>).

status string مطلوب

approved أو rejected.

إحدى القيم: approved rejected

reference string | null اختياري

مرجع الدفع. يظهر عند approved.

note string | null اختياري

ملاحظة الإدارة. تظهر عند rejected.

amount number مطلوب

المبلغ بالدولار.

currency string مطلوب

قيمة ثابتة "USD"

recharge_balance number مطلوب

رصيد الشحن بعد الحدث بالدولار.

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "wallet.withdrawal",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "id": "withdrawal_1",
    "status": "approved",
    "reference": null,
    "note": null,
    "amount": 50,
    "currency": "USD",
    "recharge_balance": 150
  }
}

حدث POST ping #

رسالة اختبار

تُرسل عبر POST /webhooks/{id}/test (وزر «إرسال تجربة» في اللوحة). لا يمكن اختيارها حدثاً ولا تُعاد تلقائياً.

جسم الرسالة

الحقلالنوع مطلوبالوصف
id string مطلوب

معرّف الحدث (evt_ يليه 24 حرفاً صغيراً)؛ وهو نفسه ترويسة X-DS-Event-Id.

النمط ^evt_[a-z0-9]{24}$

event string مطلوب

قيمة ثابتة "ping"

created_at string (date-time) مطلوب

وقت إنشاء الحدث (ISO 8601).

data object مطلوب

بيانات رسالة الاختبار ping.

message string مطلوب

نص اختبار مترجم.

مثال

JSON
{
  "id": "evt_abcdefghijklmnopqrstuvwx",
  "event": "ping",
  "created_at": "2026-01-01T12:10:00+00:00",
  "data": {
    "message": "Test message from Delivery Syria"
  }
}

الأخطاء

كل خطأ تثيره الواجهة نفسها يستخدم غلاف JSON نفسه. ابنِ منطق برنامجك على error.code وحالة HTTP لا على نص الرسالة. هذه هي الرموز التي يمكن أن تُرجعها هذه الواجهة؛ أما الأخطاء التي يثيرها الإطار قبل تنفيذ كود الواجهة (حدود IP والمسار والمسارات المجهولة والطرق الخاطئة) فتأتي بصيغة بسيطة مختلفة {"message": "..."}.

الردود المشتركة

قد تصدر هذه الردود عن أي نقطة نهاية في هذه الواجهة. وتسرد كل نقطة ردودها الخاصة فقط وتحيل إلى هنا لهذه الردود.

401 مفتاح الـ API مفقود أو غير معروف.

مفتاح الـ API مفقود أو غير معروف. unauthenticated: لا مفتاح في ترويسة Authorization: Bearer. invalid_key: المفتاح غير معروف (جُدِّد أو أُلغي أو كُتب خطأً أو هو من نوع آخر).

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — No key

JSON · 401
{
  "success": false,
  "error": {
    "code": "unauthenticated",
    "message": "Send the key in the header: Authorization: Bearer <API key>"
  }
}

مثال — Unknown key

JSON · 401
{
  "success": false,
  "error": {
    "code": "invalid_key",
    "message": "The key is invalid or revoked. Generate a new key from the merchant dashboard."
  }
}
403 الوصول مرفوض.

الوصول مرفوض. account_inactive: المستخدم أو ملف التاجر موقوف أو غير موجود. api_not_allowed: التاجر تابع لشركة توصيل (الواجهة لتجّار المنصة فقط). plan_feature: الباقة لا تتضمن الـ API (أو ميزة الويب هوك عند POST /webhooks)، أو لا توجد للتاجر باقة فعّالة.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Suspended account

JSON · 403
{
  "success": false,
  "error": {
    "code": "account_inactive",
    "message": "Merchant account suspended or not found."
  }
}

مثال — Company merchant

JSON · 403
{
  "success": false,
  "error": {
    "code": "api_not_allowed",
    "message": "Your account belongs to a delivery company — the API is for platform merchant accounts only."
  }
}

مثال — Plan without the API

JSON · 403
{
  "success": false,
  "error": {
    "code": "plan_feature",
    "message": "Localized text that names the feature and the plan problem."
  }
}
429 تجاوز حدّ الطلبات.

تجاوز حدّ الطلبات. يشترك في هذه الحالة ردّان مختلفان: (1) حدّ الباقة (في الدقيقة أو في اليوم): غلاف الخطأ بصيغة JSON مع error.code بقيمة rate_limited وerror.retry_after وترويسة Retry-After. (2) حدّ عنوان IP أو المسار: يردّ الإطار قبل تنفيذ كود الـ API بـ {"message": "Too Many Attempts."} (بصيغة JSON فقط عند إرسال Accept: application/json، وإلا صفحة HTML) مع الترويسات Retry-After وX-RateLimit-Limit وX-RateLimit-Remaining وX-RateLimit-Reset.

الترويسات: Retry-After X-RateLimit-Limit X-RateLimit-Remaining X-RateLimit-Reset

مثال — Plan limit

JSON · 429
{
  "success": false,
  "error": {
    "code": "rate_limited",
    "message": "Localized text with the limit and the wait time",
    "retry_after": 42
  }
}

مثال — IP or route limit

JSON · 429
{
  "message": "Too Many Attempts."
}
500 خطأ غير متوقع في الخادم.

خطأ غير متوقع في الخادم. تتضمن الرسالة مرجعاً قصيراً يستطيع الدعم العثور عليه في السجلات؛ أعد الطلب فقط إذا كانت نتيجته مجهولة.

الترويسات: X-RateLimit-Limit X-RateLimit-Remaining

مثال — Server error

JSON · 500
{
  "success": false,
  "error": {
    "code": "server_error",
    "message": "An error occurred on our side. If it happens again, contact support and mention reference E000000.",
    "reference": "E000000"
  }
}

رموز الأخطاء

الرمزHTTPالوصف
invalid_key401

المفتاح غير معروف (جُدِّد أو أُلغي أو كُتب خطأً أو هو من نوع آخر).

unauthenticated401

لا مفتاح في ترويسة Authorization: Bearer.

insufficient_balance402

رصيد المحفظة لا يكفي (تذكر الرسالة المبلغ المطلوب والمتاح). أرسل wait_for_balance: true لحفظ الطرد بالمرحلة awaiting_funds بدلاً من ذلك.

account_inactive403

المستخدم أو ملف التاجر موقوف أو غير موجود.

api_not_allowed403

التاجر تابع لشركة توصيل (الواجهة لتجّار المنصة فقط).

plan_feature403

الباقة لا تتضمن الـ API (أو ميزة الويب هوك عند POST /webhooks)، أو لا توجد للتاجر باقة فعّالة.

not_found404

لا يوجد طرد بهذا الرقم أو المرجع في حسابك (والطرد الملغى لم يعد موجوداً).

not_cancellable409

خرج الطرد من الحالة «معلّق» أو «مستلم في المستودع»، أو أُرسل إلى شركة شحن خارجية.

carrier_error422

رفضت شركة الشحن الخارجية الطرد أو أن حساب الشركة غير صالح للاستخدام.

delivery_failed422

لم تصل الرسالة (ردّ غير 2xx أو تحويل أو انتهاء مهلة أو خطأ اتصال). يحمل response_status الحالة التي أعادها نظامك، أو null.

limit_reached422

لديك أصلاً العدد الأقصى من الروابط.

quote_failed422

تعذّر حساب السعر.

validation_failed422

company_id مفقود أو غير متاح لك، أو ينقص حقل يحتاجه التسعير.

rate_limited429
server_error500

مصادر إضافية