مرجع المطوّرون

الأخطاء ورموز الحالة في واجهات الـ API

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

آخر تحديث 22 أكتوبر 2026 · آخر تحقق 22 أكتوبر 2026

الغرض#

تسرد هذه الصفحة رموز حالة HTTP وأكواد الأخطاء التي تعيدها فعلاً واجهة التاجر (/api/v1) وواجهة الشركة (/api/company/v1)، ومعنى كل منها وطريقة إصلاحه. ابنِ معالجة الأخطاء على error.code.

شكل الخطأ#

النجاح هو 200، أو 201 عند إنشاء مورد جديد، كطرد أو رابط ويب هوك. و200 مع "duplicate": true تعني أن reference موجود مسبقاً (واجهة التاجر). وكل خطأ يُرجعه الـ API نفسه يأتي بهذا الشكل:

json
{
  "success": false,
  "error": {
    "code": "validation_failed",
    "message": "...",
    "fields": { "customer_phone": ["..."] }
  }
}
  • code كود قصير بصيغة snake_case، وعليه يعتمد برنامجك.
  • message نص بلغة الطلب: العربية افتراضياً، والإنجليزية مع Accept-Language: en. وبعض الرسائل موجودة بالعربية فقط، فلا تبنِ المنطق على النص أبداً.
  • يظهر fields في معظم أخطاء التحقق: أسماء الحقول مع رسائلها، ويكرّر message عادةً أول رسالة فيها (والاستثناء خطأ merchant_id في واجهة الشركة: يحمل fields.merchant_id الرسالة «تاجر غير موجود عند شركتك.» بينما يحمل message نص merchant_id الأطول الوارد في جدول التحقق). وبعض أخطاء واجهة الشركة (stage غير معروف، أو deliveryman_id ناقص أو لمندوب من شركة أخرى، أو action غير معروف) تحمل message فقط. وأسماء الحقول هي الأسماء الداخلية للمنصة (customer_name وcustomer_phone وcustomer_address وcustomer_city وlat وlong وshop_id بدل pickup_location_id).
  • يظهر retry_after (بالثواني) مع rate_limited، وreference مع server_error، وresponse_status مع delivery_failed.

ترتيب الفحوصات#

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

الخطوة واجهة التاجر واجهة الشركة
1 وجود المفتاح: unauthenticated وجود المفتاح: unauthenticated
2 صحة المفتاح: invalid_key صحة المفتاح: invalid_key
3 الحساب فعّال: account_inactive الحساب والشركة فعّالان: account_inactive
4 ليس تاجر شركة: api_not_allowed الاشتراك فعّال: subscription_expired
5 الباقة تتضمن الـ API: plan_feature الباقة تتضمن الـ API: plan_feature
6 حدّ الباقة: rate_limited حدّ الباقة: rate_limited

رموز الحالة وأكواد الأخطاء#

HTTP error.code الواجهة المعنى طريقة الإصلاح
401 unauthenticated كلتاهما لا يوجد مفتاح في ترويسة Authorization: Bearer أرسل المفتاح في هذه الترويسة
401 invalid_key كلتاهما المفتاح غير معروف: جُدّد أو أُلغي أو كُتب خطأ أو هو من نوع آخر انسخ المفتاح الحالي من اللوحة؛ واستخدم مفتاح «API للمطورين» (sk_) على /api/v1 ومفتاح الشركة (ck_) على /api/company/v1
402 insufficient_balance كلتاهما الرصيد لا يكفي؛ وتذكر الرسالة المبلغ المطلوب والمتاح اشحن المحفظة، أو أرسل wait_for_balance: true (واجهة التاجر)
402 subscription_expired الشركة انتهى اشتراك الشركة جدّده من لوحة الشركة
403 account_inactive كلتاهما مستخدم المفتاح، أو التاجر أو الشركة، موقوف أو غير موجود تواصل مع مسؤول المنصة
403 api_not_allowed التاجر التاجر تابع لشركة توصيل استخدم حساب تاجر منصة
403 plan_feature كلتاهما الباقة لا تتضمن الميزة (الـ API، أو الويب هوك لـ POST /webhooks)، أو ليس للتاجر باقة فعّالة اشترك أو رقِّ الباقة؛ وتسمّي الرسالة الميزة
404 not_found كلتاهما لا يوجد طرد بهذا الرقم أو المرجع في حسابك أو شركتك، أو لا يوجد ويب هوك كهذا تحقق من القيمة؛ والطرد الملغى لم يعد موجوداً
409 not_cancellable التاجر غادر الطرد حالة «بانتظار الاستلام» أو «بالمستودع — جاهز للتوزيع»، أو ذهب إلى شركة شحن خارجية لا يمكن إلغاء سوى الطرد «بانتظار الاستلام» أو «بالمستودع — جاهز للتوزيع» الذي لم يُرسل إلى شركة شحن خارجية
409 duplicate_reference الشركة للتاجر طرد بالـ reference نفسه اجلبه بـ GET /parcels?merchant_id=<id>&reference=<reference> (فـ GET /parcels/{reference} وحده يبحث في طرود كل تجّارك)
409 deliveryman_full الشركة يحمل المندوب أقصى عدد من الطرود المفتوحة اختر مندوباً آخر، أو أرسل force: true
409 not_allowed الشركة الطرد عند شركة شحن خارجية تتحكم بحالته لا تغيّر حالته من هنا
409 invalid_transition الشركة الإجراء لا يناسب الحالة الحالية، أو collected أكبر من مبلغ التحصيل اقرأ السبب في الرسالة
422 validation_failed كلتاهما حقل ناقص أو خاطئ؛ ويعدّدها fields (وفي بعض حالات واجهة الشركة تأتي الرسالة فقط) راجع القسم التالي
422 quote_failed التاجر تعذّر حساب السعر افحص company_id وحقول المستلم
422 carrier_error كلتاهما رفضت شركة الشحن الخارجية الطرد، أو هي غير مفعّلة، أو لا يمكن استخدامها (حسابك الخاص غير مربوط، أو العملة أو shipping_paid_by غير مدعوم) عالج السبب المذكور في الرسالة
422 limit_reached التاجر بلغت أقصى عدد من روابط الويب هوك احذف رابطاً أو رقِّ الباقة
422 delivery_failed التاجر لم يصل ping التجريبي إلى رابطك؛ وقد يُضاف response_status افحص رابطك وخادمك
429 rate_limited كلتاهما بلغت حدّ الباقة في الدقيقة أو في اليوم (أما الحد العام وحدود المسارات فتردّ بلا error.code، انظر «أخطاء خارج هذا الشكل») انتظر retry_after ثانية
500 server_error كلتاهما خطأ غير متوقع في المنصة. وتُرجعه واجهة الشركة في كل مرة أيضاً عند تعيين مندوب لطرد لا تسمح حالته بالانتقال إلى «مع مندوب التوصيل» أعد المحاولة لاحقاً وأعطِ الدعم قيمة reference؛ وعند التعيين افحص status_code أولاً

وهكذا يظهر الحقلان الإضافيان retry_after وreference:

json
{
  "success": false,
  "error": {
    "code": "rate_limited",
    "message": "...",
    "retry_after": 42
  }
}
json
{
  "success": false,
  "error": {
    "code": "server_error",
    "message": "...",
    "reference": "E3FA91C"
  }
}

أخطاء التحقق (422)#

يربط fields كل حقل فاشل برسائله. وهذه الحقول التي ستصادفها أكثر من غيرها:

الحقل السبب المعتاد مثال على الرسالة
company_id غائب، أو الشركة غير متاحة لك «company_id مطلوب — جيب القائمة من GET /companies»
customer_name وcustomer_phone وcustomer_address غائبة؛ والهاتف يقبل من 6 إلى 30 حرفاً من الأرقام و+ والمسافات و- والأقواس نص التحقق القياسي
customer_city تعذّر العثور على المحافظة، أو لا سعر للشركة إليها، أو هي خارج التغطية «شركة التوصيل تحسب حسب المحافظة: ما قدرنا نعرف محافظة المستلم من العنوان "..." — اختر المحافظة من القائمة.»
lat وlong خارج النطاق، أو التسعير حسب المسافة يحتاج موقع المستلم «شركة التوصيل تحسب حسب المسافة: حدد موقع المستلم على الخريطة.»
shop_id مكان الاستلام ليس لك، أو لا تملك أي مكان، أو لا موقع له على الخريطة للتسعير حسب المسافة، أو انتهى حجز المستودع «الفرع المختار لا يتبع لك»
warehouse_items مكان الاستلام مستودع والمنتجات غائبة أو تتجاوز المخزون تسمّي الرسالة المنتج والكمية
weight خارج المدى من 0.01 إلى 1000، أو أكبر من أقصى وزن للشركة «"..." بتقبل طرود لحد N كغ — وزن الطرد M كغ.»
cod_amount سالب أو أكبر من 100,000,000 نص التحقق القياسي
cod_currency أو currency عملة غير مدعومة، أو لا تقبلها الشركة، أو لا سعر صرف «"..." بتقبل المبالغ بـ: ... — غيّر عملة الطرد.»
shipping_paid_by ليس sender ولا customer ولا included_in_cod نص التحقق القياسي
plan استُهلكت حصة الطرود في باقة التاجر (واجهة التاجر فقط؛ أما انتهاء الباقة أو غيابها فيعطي 403 والكود plan_feature) «وصلت لحد باقتك: N طرد خلال مدة الاشتراك (لحد ...)، واستعملت M. رقّي باقتك أو جدّد الاشتراك لتكمّل.»
merchant_id واجهة الشركة: ليس من تجّارك message: «merchant_id مطلوب ولازم يكون تاجر عند شركتك (GET /merchants).»؛ وfields.merchant_id: «تاجر غير موجود عند شركتك.»
collected واجهة الشركة: partial بدون رقم «التسليم الجزئي بدو collected (المبلغ اللي انحصّل).»
delivery_man_id واجهة الشركة: تشترط شركتك أن يكون المندوب متصلاً وهو غير متصل تطلب الرسالة من المندوب أن يضغط «متصل» في تطبيق المندوب
url وevents وname وactive قواعد ويب هوك واجهة التاجر: https فقط، ومضيف عام، وحدث واحد على الأقل «لازم الرابط يكون https://»

أخطاء خارج هذا الشكل#

تُنتَج بعض الأخطاء قبل أن يعمل كود الـ API، فلا تستخدم الغلاف:

  • المسار غير الموجود (404) وطريقة HTTP الخاطئة (405) والحد العام للطلبات وحدود المسارات (429). مع Accept: application/json تحصل على جسم JSON فيه message؛ وبدونها تحصل على صفحة HTML.
  • ومع ترويسة JSON تردّ هذه الحدود بـ {"message": "Too Many Attempts."} ومعه الترويسات Retry-After وX-RateLimit-Limit وX-RateLimit-Remaining وX-RateLimit-Reset. فقد يأتي 429 من ثلاثة مصادر: الحد العام (60 طلباً في الدقيقة لكل عنوان IP) وحدود المسارات (بلا error.code)، وحدّ الباقة (rate_limited داخل الغلاف).
  • في حالات نادرة قد يقع خلل غير متوقع قبل معالجة الأخطاء الخاصة بالـ API، فيكون الرد {"success": false, "message": "..."} مع 500.
json
{ "message": "Too Many Attempts." }

التعامل مع الأخطاء في برنامجك#

  1. افحص حالة HTTP أولاً

    4xx تعني أن طلبك يجب أن يتغيّر، عدا 429. و5xx تعني عادةً أن المشكلة من جهة المنصة، فأعد المحاولة لاحقاً. وهناك حالة لا تزول بإعادة المحاولة: في واجهة الشركة، تعيين مندوب لطرد لا تسمح حالته بالانتقال إلى «مع مندوب التوصيل»، كطرد بانتظار الاستلام أو ما زال في مرحلة الاستلام، يعطي 500 والكود server_error في كل مرة؛ فافحص status_code للطرد قبل استدعاء التعيين.

  2. اعتمد على error.code

    استخدم error.code لتحديد ما يفعله برنامجك، وerror.fields لإبراز الحقول، وerror.message لعرضه على المستخدم فقط.

  3. انتظر عند 429

    توقّف مدة error.retry_after ثانية، أو المدة الواردة في ترويسة Retry-After عندما يردّ الحد العام أو أحد حدود المسارات (بلا error.code)، ثم أعد المحاولة.

  4. اجعل إعادة محاولة الإنشاء آمنة

    بعد انتهاء المهلة أو 500 عند إنشاء طرد، ابحث عن الطرد قبل إنشائه من جديد: بـ GET /parcels/{reference} في واجهة التاجر، وبـ GET /parcels?merchant_id=<id>&reference=<reference> في واجهة الشركة (فـ GET /parcels/{reference} وحده هناك يبحث في طرود كل تجّارك وقد يُرجع طرد تاجر آخر). وفي واجهة التاجر يُرجع إرسال reference نفسه الطرد الموجود مع "duplicate": true.

أخطاء شائعة#

  • اعتبار 200 مع "duplicate": true طرداً جديداً. هو الطرد الذي أنشأته سابقاً.
  • توقّع 409 عند تكرار reference في واجهة التاجر. ذلك في واجهة الشركة؛ أما واجهة التاجر فتُرجع الطرد القديم.
  • إعادة محاولة 4xx دون تغيير. أصلح الطلب أولاً.
  • تحليل error.message. يتغيّر مع اللغة، وبعض الرسائل بالعربية فقط.
  • عدم إرسال Accept: application/json. عندها تصلك الأخطاء التي تقع قبل كود الـ API (انظر «أخطاء خارج هذا الشكل») صفحات HTML.
  • تجاهل fields. فهو، عندما يوجد، يسمّي الحقل الذي فشل بالضبط.

الحدود والصلاحيات#

  • plan_feature وrate_limited وapi_not_allowed تتوقف على باقتك ونوع حسابك، لا على جسم الطلب.
  • تُستخدم اللغتان ar وen فقط في الرسائل.
  • الأكواد المعلَّمة «التاجر» أو «الشركة» موجودة في تلك الواجهة وحدها.

API

  • POST /api/v1/parcels
  • POST /api/v1/parcels/{tracking}/cancel
  • POST /api/company/v1/parcels
  • POST /api/company/v1/parcels/{tracking}/status