واجهة شركات التوصيل (Shipping API)
تستقبل شركتكم طلبات متاجر متاجرة آلياً، وتحدّث حالة كل طرد لتظهر للتاجر والعميل.
شركات مربوطة بهذه الواجهة في فلسطين: سندر Snder
1) كيف يعمل الربط
- يعطيكم فريق متاجرة مفتاحين: مفتاح اختبار (
mtj_test_…) ومفتاح تشغيل (mtj_…). كلٌّ يُعرض مرة واحدة. - عندما يضع التاجر طلباً على «جاري التوصيل» أو «تم الشحن» والعميل اختار شركتكم، يصلكم الطلب: إشعاراً فورياً (Webhook) أو بالسحب من
GET /orders. - تحدّثون حالته بـ
POST /orders/{id}/statusفتظهر فوراً للتاجر والعميل. «سُلّم» تُكمل الطلب في المتجر. - ليس عندكم مبرمج؟ كل ما سبق متاح بالأزرار في بوابة الشركاء ← «طلبات التوصيل».
2) العنوان والتوثيق
Base URL: https://motajrh.com/api/carrier/v1
Header: Authorization: Bearer YOUR_KEY
Accept: application/json
كل الردود JSON. المفتاح الخاطئ يعيد 401. الحد: 240 طلباً في الدقيقة.
3) بيئة الاختبار
بمفتاح الاختبار ترون وتغيّرون طلبات تجريبية فقط، ولا يتأثر أي متجر. أنشئوا طلباً تجريبياً (يُرسل لرابط إشعاراتكم أيضاً)، ثم جرّبوا كل الخطوات عليه:
POST https://motajrh.com/api/carrier/v1/test/orders → 201 { "order": { "id": 7, "order_number": "TEST-AB12CD", "test": true, … } }
GET https://motajrh.com/api/carrier/v1/me → { "company": "…", "mode": "test", "open_orders": 1, "zones": { … } }
بمفتاح التشغيل تعيد هذه النقطة 403. تحديث الأسعار والتحصيل بمفتاح الاختبار يُفحص ولا يُحفظ.
4) قائمة الطلبات
GET https://motajrh.com/api/carrier/v1/orders?status=new&limit=50&after_id=0
| المعامل | الوصف |
|---|---|
| status | new, accepted, picked, out, delivered, returned, failed, cancelled |
| since | الطلبات التي تغيّرت منذ هذا الوقت (ISO 8601) |
| after_id | للصفحة التالية: قيمة next_after_id من الرد السابق |
| limit | من 1 إلى 100 (الافتراضي 50) |
{
"orders": [{
"id": 1024,
"order_number": "MA-10501",
"status": "new",
"tracking_number": null,
"cod_amount": 122, // المبلغ المطلوب تحصيله (0 = مدفوع)
"currency": "ILS",
"test": false, "settled": false, "settlement_ref": null,
"created_at": "2026-10-08T12:10:00+03:00",
"store": { "id": 551, "name": "Magic Veil", "phone": "+970568823256", "url": "https://magicveil.motajrh.com",
"lat": 32.2211, "lng": 35.2544 },
"pickup": { "city": "نابلس", "district": "", "address": "…",
"lat": 32.2211, "lng": 35.2544 },
"recipient": { "name": "…", "phone": "+970568823256", "country": "فلسطين",
"zone": "wb", "zone_name": "الضفة الغربية", "region": "", "city": "نابلس",
"district": "", "address": "رفيديا، شارع الجامعة", "note": "",
"lat": 32.227, "lng": 35.242 },
"items": [{ "name": "…", "sku": "PRF1", "quantity": 1 }],
"order_total": 122, "delivery_fee": 20, "paid": false,
"quote_id": null, "distance_km": null, // إن كنتم تسعّرون لحظياً: رقم عرض السعر الذي رآه العميل
"account": "store" // من يدفع لكم الأجرة: store حساب المتجر عندكم، platform حساب المنصة الواحد
}],
"has_more": false,
"next_after_id": null
}
حقول الطلب: أين تجدون كل معلومة
| المعلومة | الحقل | ملاحظة |
|---|---|---|
| رقم الطلب عندنا | id, order_number | id رقم ثابت تستعملونه في الروابط؛ order_number ما يراه التاجر والعميل |
| رقم الطلب عندكم | tracking_number | ترسلونه أنتم مع أول تحديث للحالة، ونحفظه ونعرضه للتاجر والعميل |
| معرّف المتجر | store.id | رقم ثابت لكل متجر عندنا: احفظوا به موقع المتجر مرة واحدة |
| اسم المتجر | store.name | |
| جوال المتجر | store.phone | جوال فرع الاستلام |
| إحداثيات المتجر | store.lat, store.lng = pickup.lat, pickup.lng | موقع فرع الاستلام كما حدّده التاجر على الخريطة: أرقام عشرية (WGS84)، خط العرض lat ثم خط الطول lng. null إن لم يحدّده بعد |
| عنوان المتجر | pickup.city, pickup.district, pickup.address | |
| اسم العميل | recipient.name | |
| جوال العميل | recipient.phone | بالصيغة الدولية: +970 أو +972 ثم 9 أرقام تبدأ بـ 5 |
| إحداثيات العميل | recipient.lat, recipient.lng | الموقع الذي حدّده العميل على الخريطة عند إتمام الطلب. إن طلبتم منا «موقع العميل إلزامي» فلن يصلكم طلب بدونه؛ وإلا قد يكون null |
| وصف عنوان العميل | recipient.city, district, address, note | note: ملاحظة العميل للمندوب |
| مبلغ التحصيل | cod_amount, currency | 0 = الطلب مدفوع، لا تحصّلوا شيئاً |
| أجرة التوصيل | delivery_fee, quote_id, distance_km | ما دفعه العميل للتوصيل. مع السعر اللحظي: delivery_fee = price من عرضكم، و quote_id رقمه |
| المحتويات | items[].name, sku, quantity |
مناطق فلسطين في recipient.zone: wb الضفة الغربية، jer القدس، in48 الداخل (مناطق 48)، gaza قطاع غزة
5) طلب واحد
GET https://motajrh.com/api/carrier/v1/orders/1024 → { "order": { …, "history": [ { "status": "new", "at": "…", "by": "store" } ] } }
6) تحديث حالة الطلب
POST https://motajrh.com/api/carrier/v1/orders/1024/status
Content-Type: application/json
{ "status": "picked", "tracking_number": "SN-778812", "note": "" }
| status | معناها | ما يحدث في المتجر |
|---|---|---|
| accepted | قبلتم الطلب | يُسجَّل في سجل الطلب |
| picked | استُلم الطرد من المتجر | يُسجَّل، ويظهر رقم التتبع للعميل |
| out | مع المندوب للتسليم | يُسجَّل |
| delivered | سُلّم للعميل | يصير الطلب «تم التوصيل» ويُبلَّغ العميل |
| failed | تعذّر التسليم (يمكن إعادة المحاولة) | تنبيه للتاجر |
| returned | مرتجع للمتجر (نهائي) | تنبيه للتاجر |
الطلب المغلق (delivered / returned / cancelled) يعيد 409. الحالة غير المعروفة تعيد 422.
7) أسعاركم ومناطق تغطيتكم
أرسلوا أسعاركم فيراها كل تاجر عند إعداد شركتكم، ويعتمدها بضغطة. المنطقة التي لا ترسلونها تعني أنكم لا توصّلون إليها.
PUT https://motajrh.com/api/carrier/v1/rates
{ "country": "PS", "rates": [ { "zone": "wb", "price": 20, "days": "1-3" }, { "zone": "jer", "price": 30, "days": "1-3" }
] }
GET https://motajrh.com/api/carrier/v1/rates → { "rates": { "PS": { … } }, "zones": { "PS": { … } } }
8) التحصيل عند الاستلام
ما حصّلتموه من العملاء ولم تحوّلوه للمتاجر بعد، ثم إبلاغنا بالتحويل. يصل التاجر تنبيه ويؤكد الاستلام من لوحته.
GET https://motajrh.com/api/carrier/v1/settlements
→ { "pending": [ { "id": 1024, "order_number": "MA-10501", "store": "Magic Veil", "cod_amount": 122, "currency": "ILS" } ],
"totals": { "ILS": 122 } }
POST https://motajrh.com/api/carrier/v1/settlements
{ "order_ids": [1024, 1031], "reference": "TRX-2026-0091" } → { "settled": 2 }
للشركات التي تعمل بالخريطة: الموقع، السعر اللحظي، والطلبات المدفوعة
ثلاثة خيارات يفعّلها فريقنا لشركتكم عند الطلب، كلٌّ منها مستقل عن الآخر:
| الخيار | ماذا يفعل |
|---|---|
| موقع العميل إلزامي | العميل الذي يختار شركتكم عند الدفع لا يكمل الطلب قبل تحديد موقعه على الخريطة (زر «موقعي الحالي» أو دبوس). فلا يصلكم طلب بلا recipient.lat و recipient.lng. |
| السعر اللحظي | نستدعي نقطة تسعير عندكم بعد أن يحدد العميل موقعه، ونعرض له السعر الذي تُرجعونه كما هو. يمكن أن يكون «إلزامياً» (لا سعر ثابت: إن لم تردّوا لا تُعرض شركتكم لهذا الطلب) أو «اختيارياً» (إن لم تردّوا يُعرض سعر التاجر الثابت). |
| الطلبات المدفوعة فقط | لا تُعرض شركتكم مع «الدفع عند الاستلام»، ولا يُرسل لكم طلب قبل أن يُدفع. فيكون cod_amount صفراً في كل طلب يصلكم. |
نقطة التسعير عندكم (أنتم تبنونها ونحن نستدعيها)
POST https://your-domain/…/shipping/quote
Authorization: Bearer <مفتاح تعطوننا إياه>
Content-Type: application/json
{ "store_id": 551,
"pickup": { "lat": 32.2211, "lng": 35.2544 },
"dropoff": { "lat": 32.227, "lng": 35.242 } }
← 200 { "available": true, "quote_id": "q_8f2a1c", "price": 12, "currency": "ILS",
"distance_km": 3.4, "eta_minutes": 45, "expires_at": "2026-10-08T18:30:00+03:00" }
← 200 { "available": false } // خارج التغطية: لا تُعرض شركتكم لهذا الطلب
- price بعملة المتجر (ILS في فلسطين)، ويُعرض للعميل كما هو. إن أرسلتم currency مختلفة نتجاهل الرد.
- quote_id و distance_km و eta_minutes و expires_at اختيارية. إن أرسلتم quote_id حفظناه وأعدناه لكم في حقل quote_id من الطلب، و delivery_fee يساوي price.
- نحتفظ بالعرض 10 دقائق على الأكثر، ولا نتجاوز expires_at ناقص دقيقتين؛ بعدها نطلب سعراً جديداً. فالطلب يُنشأ دائماً بسعر ما زال صالحاً عندكم.
- ننتظر ردّكم 6 ثوانٍ. الرد غير 200، أو بلا حقل available، يُعدّ «لا ردّ».
- لا تسعير بلا موقع المتجر: إن لم يحدد التاجر موقع فرعه على الخريطة لا نستدعيكم.
من يدفع أجرة التوصيل؟
طريقتان، نتفق معكم على إحداهما (وحقل account في كل طلب وكل طلب تسعير يقول أيهما):
| account | المعنى |
|---|---|
| platform | حساب واحد للمنصة عندكم: تخصمون أجرة كل طلب من رصيد المنصة. نحن نأخذها من رصيد المتجر عندنا قبل إرسال الطلب، فلا يصلكم طلب لم تُغطَّ أجرته. إن أُلغي الطلب قبل الاستلام (order.cancelled) لا تُخصم الأجرة. |
| store | لكل متجر حسابه ورصيده عندكم يشحنه بنفسه. store.id هو ما تربطون به حساب المتجر، والتاجر يراه في لوحته ليعطيكم إياه. المنصة خارج المال. |
9) الإشعار الفوري (Webhook) — اختياري
أعطوا الفريق رابطاً يبدأ بـ https://، فنرسل إليه POST عند كل طلب جديد وعند إلغاء التاجر طلباً:
X-Motajrh-Event: order.created (or order.cancelled)
X-Motajrh-Delivery: 5521 (unique per delivery: use it to ignore a repeat)
X-Motajrh-Signature: hex( HMAC-SHA256( raw body, your webhook secret ) )
{ "event": "order.created", "order": { … the same object as in the list … } }
تحققوا من التوقيع وردّوا بـ 200 خلال 8 ثوانٍ. إن لم يردّ خادمكم نعيد المحاولة بعد دقيقة، 5 دقائق، 30 دقيقة، ساعتين، 6 ساعات، ثم 12 ساعة. والطلب يبقى دائماً في GET /orders?status=new.
10) مثال سريع
curl -H "Authorization: Bearer YOUR_KEY" -H "Accept: application/json" \
"https://motajrh.com/api/carrier/v1/orders?status=new"
curl -X POST -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
-d '{"status":"delivered"}' "https://motajrh.com/api/carrier/v1/orders/1024/status"
11) رموز الأخطاء
| 401 unauthorized | المفتاح خاطئ أو موقوف |
| 403 test_key_only | النقطة لمفتاح الاختبار فقط |
| 404 not_found | الطلب ليس لشركتكم أو غير موجود |
| 409 closed | الطلب مغلق |
| 422 | قيمة غير صحيحة (التفاصيل في errors أو message) |
| 429 | تجاوزتم 240 طلباً في الدقيقة |
اربطوا شركة التوصيل مع متاجرة
عبّئوا بيانات الشركة ويتواصل معكم فريقنا ويرسل لكم مفتاح الاختبار.