وثائق ربط المتاجر والمنصات (Waselha Merchant API)

مرحباً بك في بوابة مطوري منصة وصلها. يوفر هذا الدليل الفني واجهة ربط برمجية قوية وآمنة تتيح للتجار والمطورين إمكانية ربط متاجرهم الإلكترونية (مثل WooCommerce، Shopify، Magento) لتوليد بوالص الشحن وإرسال الشحنات وتتبعها تلقائياً بالكامل.

الرابط الأساسي للـ API: https://api.wsalha.com/

1. المصادقة والأمان

تتم جميع العمليات البرمجية بأمان من خلال إرسال مفتاح الربط الخاص بك في ترويسات الطلب (Headers) لكل طلب HTTP. يمكنك توليد مفتاح الربط من لوحة تحكم متجر التاجر تحت تبويب الربط البرمجي (API).

يجب إرسال الترويسة التالية مع كل طلب:

X-API-Key: wsalha_live_your_actual_api_key_goes_here
Content-Type: application/json

2. الأخطاء والردود الموحدة

جميع الردود ترجع بتنسيق JSON موحد لتبسيط المعالجة البرمجية:

الرد الناجح (Success)
{
  "success": true,
  "data": {
    "trackingNumber": "WSL100239",
    "status": "Created"
  }
}
الرد الفاشل (Failure)
{
  "success": false,
  "error": {
    "code": "INVALID_GOVERNORATE",
    "message": "المحافظة المحددة غير نشطة."
  }
}
GET

قائمة المحافظات النشطة

يسترجع جميع المحافظات المفعّلة للتوصيل مع معرّفاتها. استخدم الـ id الراجع هنا في حقل governorateId عند إنشاء الشحنة.

GET /v1/lookup/governorates
مثال للرد:
{
  "success": true,
  "data": [
    {
      "id": "00000000-0000-0000-0002-000000000001",
      "nameAr": "القاهرة",
      "nameEn": "Cairo"
    },
    {
      "id": "00000000-0000-0000-0002-000000000002",
      "nameAr": "الجيزة",
      "nameEn": "Giza"
    }
    // ... باقي المحافظات
  ]
}
البيانات مُخزّنة مؤقتاً (cached) لمدة ساعة. المحافظات نادراً ما تتغير.
GET

أحياء ومناطق محافظة

يسترجع الأحياء/المناطق النشطة التابعة لمحافظة محددة. استخدم الـ id الراجع هنا في حقل districtId عند إنشاء الشحنة.

GET /v1/lookup/governorates/{governorateId}/districts
مثال للرد:
{
  "success": true,
  "data": [
    {
      "id": "a1b2c3d4-...",
      "governorateId": "00000000-0000-0000-0002-000000000001",
      "nameAr": "مدينة نصر",
      "nameEn": "Nasr City"
    },
    {
      "id": "e5f6g7h8-...",
      "governorateId": "00000000-0000-0000-0002-000000000001",
      "nameAr": "المعادي",
      "nameEn": "Maadi"
    }
  ]
}
GET

إعدادات رسوم الشحن

يسترجع الحد الأدنى لرسوم الشحن حسب المنطقة ورسوم تحصيل الدفع عند الاستلام (COD).

GET /v1/lookup/shipping-settings
مثال للرد:
{
  "success": true,
  "data": {
    "minShippingFeeSameDistrict": 20.00,
    "minShippingFeeSameGovernorate": 30.00,
    "minShippingFeeCrossGovernorate": 50.00,
    "codFeeRate": 0,
    "codFixedFee": 0,
    "minCodFee": 0,
    "currency": "EGP"
  }
}
GET

القيم المسموحة (Enums)

يسترجع جميع القيم المسموحة للأنواع المستخدمة في إنشاء الشحنة — مثل سرعة التوصيل، الطرف الدافع، ونوع التعيين. استخدم الرقم في حقل value عند إنشاء الشحنة.

GET /v1/lookup/enums
مثال للرد:
{
  "success": true,
  "data": {
    "deliverySpeed": [
      { "value": 0, "name": "Normal", "descriptionAr": "عادي" },
      { "value": 1, "name": "Express", "descriptionAr": "سريع" }
    ],
    "shippingPayer": [
      { "value": 0, "name": "Customer", "descriptionAr": "العميل" },
      { "value": 1, "name": "Merchant", "descriptionAr": "التاجر" }
    ],
    "assignmentType": [ // ... Marketplace, Direct, Auto ],
    "vehicleType": [ // ... أنواع المركبات ],
    "shipmentStatus": [ // ... جميع حالات الشحنة ]
  }
}
POST

حساب تكلفة الشحن المتوقعة

يستخدم لمعرفة رسوم التوصيل والحد الأدنى المسموح به للتوصيل وعمولة الدفع عند الاستلام (COD Fee) للزبون قبل تأكيد الطلب.

POST /v1/shipments/calculate-fee
مثال للـ Payload المرسل:
{
  "governorateId": "00000000-0000-0000-0002-000000000001", // من /v1/lookup/governorates
  "districtId": "a1b2c3d4-...", // من /v1/lookup/governorates/{id}/districts
  "codAmount": 1500.00
}
POST

إنشاء شحنة جديدة

يستخدم لتسجيل طلب التوصيل في نظام وصلها تلقائياً وطباعة البوليسة للتاجر.

POST /v1/shipments
مثال للـ Payload المرسل:
{
  "customerName": "أحمد محمد",
  "customerPhone": "01098765432",
  "governorateId": "00000000-0000-0000-0002-000000000001", // من /v1/lookup/governorates
  "districtId": "a1b2c3d4-...", // من /v1/lookup/governorates/{id}/districts
  "deliveryAddress": "12 شارع عباس العقاد، مدينة نصر، القاهرة",
  "productDescription": "ساعة ذكية وسماعة لاسلكية",
  "isFragile": true,
  "codAmount": 2500.00,
  "shippingFee": 50.00,
  "shippingPayer": 1, // 0: Customer, 1: Merchant — من /v1/lookup/enums
  "deliverySpeed": 0  // 0: Normal, 1: Express — من /v1/lookup/enums
}
GET

تتبع الشحنة

يستعلم عن تفاصيل الشحنة وحالتها الحالية وسجل تتبع التغييرات برقم التتبع.

GET /v1/shipments/{trackingNumber}
GET

تحميل بوليسة الشحن (Label)

يرجع رابطاً مباشراً لطباعة أو تنزيل بوليسة الشحن الرسمية للشحنة بصيغة PDF لوضعها على الطرد.

GET /v1/shipments/{shipmentId}/label
GET

قائمة شحنات التاجر

يسترجع قائمة مرقمة (Paginated) بجميع شحنات التاجر مع إمكانية الفلترة حسب الحالة.

GET /v1/shipments/list?page=1&pageSize=20&status=Created
معاملات الاستعلام (Query Parameters):
page       // رقم الصفحة (افتراضي: 1)
pageSize   // عدد العناصر بالصفحة (افتراضي: 20، الحد الأقصى: 100)
status     // فلتر اختياري بالحالة (مثل: Created, Delivered, Cancelled)
مثال للرد:
{
  "success": true,
  "data": {
    "items": [
      {
        "id": "d5e6f7...",
        "trackingNumber": "WSL100239",
        "customerName": "أحمد محمد",
        "customerPhone": "01098765432",
        "governorate": "القاهرة",
        "district": "مدينة نصر",
        "codAmount": 2500.00,
        "status": "Created",
        "createdAt": "2026-06-30T18:00:00Z"
      }
    ],
    "totalCount": 47,
    "page": 1,
    "pageSize": 20,
    "totalPages": 3,
    "hasNextPage": true,
    "hasPreviousPage": false
  }
}
POST

إلغاء شحنة

يلغي شحنة بمعرّفها. الإلغاء متاح فقط إذا كانت الشحنة في حالة Created أو AwaitingCourier ولم يتم إسنادها لمندوب بعد.

POST /v1/shipments/{shipmentId}/cancel
الـ Payload (اختياري):
{
  "reason": "العميل ألغى الطلب"
}
تم الإلغاء بنجاح
{
  "success": true,
  "data": {
    "message": "تم إلغاء الشحنة بنجاح."
  }
}
لا يمكن الإلغاء
{
  "success": false,
  "error": {
    "code": "CANNOT_CANCEL",
    "message": "لا يمكن إلغاء الشحنة بعد إسنادها."
  }
}

3. إشعارات المتاجر وتأمين التوقيع (Webhooks)

عندما تقوم بتسجيل رابط الويبهوك الخاص بك، سيقوم سيرفر وصلها بإرسال طلب HTTP POST آمن لمتجرك في كل مرة تتغير فيها حالة الشحنة.

التحقق من التوقيع الأمني (Security Signature):

لمنع أي محاولة هجوم أو انتحال شخصية، نقوم بإرسال توقيع رقمي مشفر في الترويسة X-Wsalha-Signature. يتم حساب هذا التوقيع باستخدام خوارزمية SHA256 HMAC مستخدماً سرّ التوقيع المخصص والمشترك للرابط (Webhook Secret).

مثال بلغة PHP للتحقق من التوقيع بمتجرك:
<?php
// 1. استقبل محتوى الطلب
$payload = file_get_contents('php://input');

// 2. اقرأ التوقيع من الـ Header
$headers = getallheaders();
$receivedSignature = isset($headers['X-Wsalha-Signature']) ? $headers['X-Wsalha-Signature'] : '';

// 3. احسب التوقيع المتوقع باستخدام السر المشترك الخاص بك
$secretKey = "YOUR_SHARED_WEBHOOK_SIGNING_SECRET";
$expectedSignature = hash_hmac('sha256', $payload, $secretKey);

// 4. تأكد من تطابقهما التام
if (hash_equals($expectedSignature, $receivedSignature)) {
    // الطلب آمن وصادر من سيرفر وصلها فعلاً! قم بتحديث الحالة داخلياً
    $data = json_decode($payload, true);
    http_response_code(200);
} else {
    // الطلب غير مصرح أو مشبوه! ارفضه فوراً
    http_response_code(401);
}

فحص حالة النظام (Health Check)

استخدم هذه النقطة للتحقق من أن الـ API يعمل بشكل سليم. لا تحتاج مصادقة (API Key).

GET /v1/system/health
مثال للرد:
{
  "status": "healthy",
  "timestamp": "2026-06-30T18:00:00.0000000Z",
  "version": "1.0.0"
}
يمكنك أيضاً استخدام GET /v1/system/info لاسترجاع قائمة كاملة بجميع الـ endpoints المتاحة ومعلومات المصادقة.