العنوان الأساسي: https://nexcodesa.com/api/v1
كل الردود بصيغة JSON، وكل رد — نجح أو فشل — يأتي بالشكل نفسه:
{"success": true, "data": { ... }}
{"success": false, "error": {"code": "...", "message": "..."}}
تحقّق من success أولاً، ثم من error.code. رسالة message للقراءة البشرية وقد تتغيّر صياغتها؛ code ثابت ويصلح للبرمجة عليه.
هذا الغلاف يصف ما يخرج من الواجهة نفسها. أما ما يُرفض قبل أن يصلها — مسار غير معروف، أو طريقة HTTP خاطئة، أو معرّف غير رقمي في GET /products/{id} — فيعود بالشكل {"message": "..."} وحده، بلا success وبلا error.code. فأي رد لا يحمل success هو خطأ من هذا النوع: راجع المسار والطريقة، ولا تبحث فيه عن رمز خطأ لن تجده.
سجّل دخولك لترى حالة مفتاحك وأمثلة بمراجع منتجاتك أنت.
يدعم الإصدار v1 شراء القسائم واستلام الأكواد، وشراء شحن اللاعب عبر ID للتنفيذ من الإدارة. استخدم /products للقسائم و/topup-products لشحن ID. لا توجد إشعارات webhook أو callback للعميل حالياً؛ تُقرأ حالة الشحن عبر GET /orders/{reference}.
أنشئ المفتاح من صفحة واجهة البرمجة في لوحة التجار، واضبط قائمة IP المسموح بها إن احتجت. أرسل الطلبات من خادمك عبر HTTPS مع Authorization: Bearer وAccept: application/json. للشراء أضف Content-Type: application/json وIdempotency-Key. أمثلة curl مكتوبة لـ Bash؛ عرّف TOKEN محلياً بمفتاحك ولا تنشره في المتصفح أو المستودع.
ابدأ بـ GET /ping ثم GET /balance. للقسائم اقرأ GET /products واستخدم id في product_id. لشحن ID اقرأ GET /topup-products واستخدم id في system_product_id مع delivery_type=top_up وplayer_id. السعر والمخزون قد يتغيران بين القراءة والشراء؛ رد الشراء هو النتيجة النهائية للقبول، وGET الطلب يوضح حالة التنفيذ الحالية.
هذه واجهة حية وليست بيئة تجريبية: نجاح POST /orders يخصم من المحفظة فعلياً. الأرقام والأكواد والأرصدة أدناه أمثلة توضيحية فقط، وليست منتجات مضمونة التوفر أو أكواداً قابلة للشحن. استبدل product_id بالرقم الذي يعيده حسابك، واستخدم مفتاح Idempotency-Key جديداً لكل شراء مستقل.
merchant_reference مرجع منتج تربطه من لوحة التجار، وليس رقم الطلب في نظامك. حده 64 محرفاً ويبدأ بحرف أو رقم؛ يسمح بالحروف والأرقام والمسافة والنقطة والشرطة والشرطة السفلية والرموز / : #. لا يوجد حقل لمرجع طلب خارجي؛ احتفظ بالربط بين رقم طلبك وdata.reference عندك.
GET /products: القيمة الافتراضية لـ per_page هي 50. GET /orders: الافتراضية 25. يقيد الخادم per_page بين 1 و100، وpage يبدأ من 1. كلاهما يعيد data.items وdata.pagination؛ اقرأ حتى last_page. قائمة الطلبات لا تدعم مرشحات حالة أو تاريخ حالياً.
القراءة الناجحة HTTP 200 والشراء المقبول HTTP 201. القسائم تُسلّم متزامناً بحالة completed؛ شحن ID يبدأ pending إلى أن تنفذه الإدارة. إعادة نتيجة محفوظة تعيد 201 مع Idempotent-Replay: true، وقد تحمل الحالة الأصلية؛ اقرأ GET للحالة الحالية. رموز القسائم نصوص، وserial_number وpin_code اختياريان. تواريخ created_at وserver_time بصيغة ISO 8601. المبالغ أرقام بعملة currency؛ استخدم حساباً عشرياً في نظامك.
عند 429 انتظر عدد الثواني في error.retry_after_seconds. لا تعتمد على ترويسة Retry-After لأنها غير مرسلة حالياً. عند 409 افحص error.code: request_in_progress يستلزم الانتظار، وrequest_abandoned يستلزم قراءة مرجع الطلب المعاد. عند انقطاع الشبكة أو 5xx لا تنشئ مفتاح شراء جديداً قبل تسوية النتيجة. أخطاء البوابة أو المسارات غير الموجودة قد لا تستخدم غلاف JSON المعتاد؛ افحص HTTP وContent-Type أولاً.
تحميل ملف OpenAPI 3.0.3 — يمكن استيراده في Postman وأدوات الربطمع كل طلب أرسل مفتاحك في ترويسة Authorization:
Authorization: Bearer nx_ab12cd34.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
لكل مفتاح حدّ طلبات في الدقيقة. عند تجاوزه يأتي الرد 429 مع retry_after_seconds يخبرك بعدد الثواني قبل المحاولة التالية.
تتحقق أن المفتاح يعمل. ابدأ بها قبل أي شيء فيه مال.
curl -H "Accept: application/json" -H "Authorization: Bearer $TOKEN" \
https://nexcodesa.com/api/v1/ping
رصيد محفظتك المتاح للشراء.
المنتجات المتاحة ومخزون كل منها.
| المعامل | الشرح |
|---|---|
search | بحث بالاسم |
in_stock | 1 لإبقاء المنتجات التي يمكن الشراء منها فعلاً: يكفي أن يكون على رفّ المنتج نفسه أكواد، أو على رفّ فئة مفعّلة منه. والمنتج الذي كل أكواده تحت فئة موقوفة لم يعد يظهر، لأن تلك الأكواد لا يصل إليها طلب. |
per_page | عدد العناصر في الصفحة (حتى 100) |
page | رقم الصفحة |
available_stock عدد الأكواد المتاحة على الرفّ في تلك اللحظة، محسوباً منها لا مقروءاً من رقم مخزّن. أكواد لا وحدات: إذا كان quantity_step يساوي 3 وavailable_stock يساوي 4، فالقابل للشراء 3 فقط، لأن الكمية يجب أن تكون من مضاعفات الخطوة. ومخزون الفئة (variations) رفّ مستقل عن رفّ المنتج نفسه، ولا يُجمع معه.
المنتج الذي قسمه موقوف يغيب عن GET /products كلياً، وGET /products/{id} يردّ عليه product_not_found بالرمز 404 — نفس ما يحدث للمنتج الموقوف نفسه. حذف لا علامة: لا تنتظر sellable أن ينبّهك، فالصف غير موجود أصلاً.
| الحقل | الشرح |
|---|---|
price | سعر الوحدة القابلة للبيع — وهو نفس السعر الذي يدفعه التاجر من محفظته في المتجر، لا سعر التكلفة. يكون null إذا لم يكن للمنتج سعر بيع مسجّل. |
quantity_step | عدد الأكواد التي تُكوّن وحدة واحدة. قيمته 1 في الغالبية العظمى، ويجب أن تكون quantity في الطلب من مضاعفاته. |
sellable | false يعني أن الطلب سيُرفض — لا تحاول شراءه. وtrue ليس إذناً بالشراء وحده: كل ما يقوله أن للرفّ سعراً مسجّلاً. الموقوف — منتجاً أو فئة أو قسماً — لا يُعلَّم بـfalse بل لا يظهر، والمخزون سؤال ثالث يجيب عنه in_stock. |
in_stock | true إذا كان على أحد رفوف هذا المنتج أكواد يصل إليها طلب: رفّه هو، أو رفّ فئة مفعّلة منه. وهو نفسه ما يفلتر به المعامل in_stock=1، ولا يغني عن available_stock ولا يناقضه: قد يأتيك true وavailable_stock صفراً، ومعناها أن المخزون كله تحت فئة، فاطلب الفئة. |
merchant_reference | اسمك أنت لهذا الرفّ إن ربطته، أو null. يظهر لكل رفّ على حدة: الفئة رفّ مستقل وقد تُربط وحدها. |
منتج واحد بتفاصيله وفئاته. نفس حقول GET /products لعنصر واحد، وهي الطريقة التي تتحقق بها من السعر والمخزون قبل الشراء مباشرة دون سحب القائمة كاملة.
curl -H "Accept: application/json" -H "Authorization: Bearer $TOKEN" \
https://nexcodesa.com/api/v1/products/12
الرقم في المسار هو product_id عندنا، لا مرجعك أنت. المرجع يُستعمل في الشراء فقط؛ ولقراءة رفّ ربطته باسمك، ابحث عنه في GET /products حيث يأتي merchant_reference بجانب كل رفّ.
منتج غير موجود أو غير مفعّل يردّ product_not_found بالرمز 404.
في وضع شراء القسائم، الأكواد تعود في الرد مباشرة ويُخصم المبلغ من محفظتك. أما شحن ID فيُقبل للتنفيذ من الإدارة كما هو موضح في قسم شحن اللاعب أدناه.
| الحقل | الشرح |
|---|---|
product_id | رقم المنتج عندنا. لم يتغيّر ولن يتغيّر، وكل تكامل قائم يعمل به كما هو. |
merchant_reference | اختياري وإضافي. اسمك أنت للمنتج، بعد أن تربطه من صفحة «واجهة البرمجة» في لوحتك. يصل إلى الرفّ نفسه الذي يصله product_id، فلا تحتاج أن تحفظ أرقامنا في كودك. |
variation_id | اختياري مع product_id. ومع merchant_reference لا داعي له أصلاً: الفئة جزء من الربط نفسه. |
quantity | عدد الأكواد. من مضاعفات quantity_step، وحتى 100 في الطلب الواحد. |
product_id وmerchant_reference معاً رددنا product_reference_ambiguous بدل أن نختار أحدهما. السبب: لو تعارضا — كأن تكون غيّرت وجهة المرجع ونسيت الرقم المكتوب في كودك — فكل اختيار نختاره خاطئ، والشراء ليس المكان الذي نخمّن فيه. ومرجع غير معروف يُردّ بـ product_reference_not_found، ولا نشتري لك شيئاً تقريبياً.
Idempotency-Key إلزامية.
ولّد UUID فريداً بحروف ASCII لكل شراء مستقل، واستخدمه نفسه عند إعادة المحاولة ضمن عميل API نفسه. النتيجة الناجحة المحفوظة تعاد دون خصم ثانٍ. إرسال بيانات مختلفة تحت مفتاح موجود يعيد 409. البصمة تعتمد على مدخلات الطلب بعد تحليلها والمسار، وليست بايتات HTTP الخام: مسافات تنسيق JSON وحدها لا تغيّرها، لكن ترتيب الحقول وأنواع القيم ومعاملات الرابط قد تغيّرها. احفظ جسم JSON الأصلي وأعد إرساله دون تغيير لتجنب التعارض.
5xx فيبقي النتيجة مجهولة والمفتاح قيد التنفيذ. تصبح النتائج الناجحة مؤهلة للحذف المجدول بعد سبعة أيام من الطلب الأصلي؛ بعد الحذف يمكن أن يؤدي المفتاح نفسه إلى شراء جديد، فلا تعِد استخدام مفاتيح قديمة. اقرأ مرجع الطلب المحفوظ عبر GET /orders/{reference} لاسترجاع عملية سابقة.
request_in_progress. بعد خمس دقائق، إن وُجد شراء سابق تعاد request_abandoned مع مرجعه في error.reference لتقرأه عبر GET /orders/{reference}. إن لم يوجد شراء، يمكن لمحاولة واحدة استلام التنفيذ وتبدأ مهلة الخمس دقائق من جديد. يعمل الاسترجاع مع product_id أو merchant_reference. تصبح السجلات غير المكتملة مؤهلة للحذف المجدول بعد يوم من إنشائها الأصلي؛ بعد الحذف قد تصبح الإعادة شراء جديداً. لا تعتمد على مفتاح قديم لتسوية نتيجة مجهولة؛ راجع GET /orders وتواصل مع الدعم قبل شراء آخر.
curl -X POST https://nexcodesa.com/api/v1/orders \
-H "Accept: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: 9f1c0a7e-6b2f-4f0b-9a1d-2f3c4d5e6a7b" \
-H "Content-Type: application/json" \
-d '{"product_id": 12, "quantity": 3}'
أو بمرجعك أنت، بعد ربط المنتج:
curl -X POST https://nexcodesa.com/api/v1/orders \
-H "Accept: application/json" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: b3072e7d-9d2a-46c9-98fd-d113cf52419a" \
-H "Content-Type: application/json" \
-d '{"merchant_reference": "PUBG-60", "quantity": 3}'
{
"success": true,
"data": {
"reference": "01J9Z6...",
"status": "completed",
"product_id": 12,
"variation_id": null,
"merchant_reference": "PUBG-60",
"quantity": 3,
"units": 3,
"units_per_sale": 1,
"unit_price": 10.00,
"total_price": 30.00,
"currency": "SAR",
"created_at": "2026-09-21T00:00:00+00:00",
"codes": [
{"code": "EXAMPLE-CODE-001"},
{"code": "EXAMPLE-CODE-002"},
{"code": "EXAMPLE-CODE-003"}
]
}
}
quantity عدد الأكواد، وunits عدد الوحدات القابلة للبيع (quantity ÷ units_per_sale). unit_price سعر الوحدة، وtotal_price هو حاصل ضربهما بالضبط. وunits_per_sale هنا هو quantity_step نفسه في GET /products: رقم واحد باسمين، أحدهما يصف المنتج والآخر يصف ما بِيع. للمنتج المعتاد (units_per_sale = 1) الأرقام هي ما كانت عليه دائماً.
كل طلب في الردود يحمل merchant_reference: اسمك أنت للرفّ الذي خرجت منه الأكواد، أو null إن لم تربطه. يُقرأ لحظة عرض الطلب لا وقت الشراء، فيعرض اسمك الحالي؛ وproduct_id بجانبه هو السجل الثابت لما بيع فعلاً.
استرجاع طلب سابق بأكواده. النطاق هو المفتاح لا الحساب: ترى ما اشتراه هذا المفتاح وحده، ومرجع اشتراه مفتاح آخر — ولو كان مفتاحاً ثانياً لك في الحساب نفسه — يردّ 404 كأنه غير موجود.
قائمة ما اشتراه هذا المفتاح، الأحدث أولاً. النطاق هو المفتاح لا الحساب، فمفتاحك الثاني لا يرى طلبات الأول.
يعيد /topup-products منتجات شحن ID اليدوي المتاحة من كتالوج المنصة. استخدم id المعاد هنا في system_product_id عند الشراء، ولا تستخدم رقم منتج القسائم. يدعم search وpage وper_page (الافتراضي 50 والحد 100). /topup-products/{id} يعيد تفاصيل منتج واحد أو 404 إذا لم يعد معروضاً. المنتجات غير النشطة أو المربوطة بمزود خارجي لا تظهر هنا.
أرسل POST /orders مع delivery_type=top_up وsystem_product_id وplayer_id، إضافة إلى ترويسة Idempotency-Key. معرّف اللاعب سلسلة نصية من 1 إلى 64 محرفاً من الحروف الإنجليزية والأرقام والشرطة والشرطة السفلية؛ أرسله بين علامتي اقتباس للحفاظ على الأصفار الأولى. quantity اختياري وقيمته الوحيدة 1: باقة واحدة للاعب واحد في كل طلب. لا تجمع حقول شحن ID مع product_id أو variation_id أو merchant_reference.
بعض الألعاب تحتاج حقولاً إضافية مثل الخادم. يعرض المنتج fields مع id وtype وrequired وoptions. أرسلها ككائن fields بمفاتيح هي أرقام الحقول وقيم نصية؛ مثال: "fields":{"42":"EU"}. استخدم قيمة value من options للقوائم. player_id مستقل؛ لا ترسله مرة ثانية داخل fields. الحقول المجهولة أو الناقصة أو غير الصحيحة تعيد validation_failed قبل الخصم.
عند قبول الطلب يُخصم سعر الباقة مرة واحدة وتعود استجابة HTTP 201. status=pending تعني قبول الطلب وانتظار التنفيذ، وليست تم الشحن. يظهر الطلب للإدارة، ويرسل إلى تلقرام إذا كان المنتج محدداً في إعدادات البوت وأصبح جاهزاً للتنفيذ. راقب GET /orders/{reference} بالمفتاح نفسه لمعرفة النتيجة. لا توجد إشعارات webhook للعميل حالياً؛ استعلم دورياً مع احترام حد الطلبات.
status يصبح completed بعد الشحن أو failed عند الفشل أو الرفض. fulfilment_status يوضح التفاصيل: pending أو pending_review أو processing أو completed أو failed. refunded=true تؤكد إعادة المبلغ إلى المحفظة. failure_reason يكون wrong_id أو no_stock عند الرفض بهذا السبب من تلقرام، أو fulfilment_failed لبقية حالات الفشل. codes تبقى مصفوفة فارغة دائماً، حتى بعد اكتمال الشحن.
تكرار POST بنفس المفتاح والبيانات يعيد استجابة الإنشاء المحفوظة دون خصم آخر؛ هذه الاستجابة قد تظل pending بعد إكمال الطلب، لذلك استخدم GET لقراءة الحالة الحالية. ينطبق مسار استعادة الطلب وقواعد 5xx والاحتفاظ بالمفاتيح على شحن ID أيضاً. نفاد المخزون قبل القبول أو نقص الرصيد يرفض الشراء دون خصم. فشل التنفيذ الكامل بعد القبول يمر بمسار الاسترجاع؛ الحالات غير المؤكدة أو المنفذة جزئياً تحتاج مراجعة الإدارة.
curl -X POST https://nexcodesa.com/api/v1/orders \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 5cd789f0-2463-4da1-b15e-b11d8f07a553" \
-d '{"delivery_type":"top_up","system_product_id":1,"player_id":"001234567"}'
curl -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
https://nexcodesa.com/api/v1/orders/REPLACE_WITH_RETURNED_REFERENCE
أمثلة JSON التالية توضيحية وتشمل أسماء الحقول كما يعيدها التطبيق. جميع المسارات أدناه تضاف إلى عنوان الأساس المعروض أعلى الصفحة.
GET /ping · HTTP 200{
"success": true,
"data": {
"client": "Example client",
"server_time": "2026-09-21T00:00:00+00:00",
"rate_limit_per_minute": 60
}
}
GET /balance · HTTP 200{
"success": true,
"data": {
"balance": 100,
"currency": "SAR"
}
}
GET /products · HTTP 200{
"success": true,
"data": {
"items": [
{
"id": 12,
"name": "Example game voucher",
"type": "voucher",
"currency": "SAR",
"merchant_reference": null,
"available_stock": 3,
"in_stock": true,
"price": 10,
"quantity_step": 1,
"sellable": true,
"variations": []
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 1,
"last_page": 1
}
}
}
GET /products/{product} · HTTP 200{
"success": true,
"data": {
"id": 12,
"name": "Example game voucher",
"type": "voucher",
"currency": "SAR",
"merchant_reference": null,
"available_stock": 3,
"in_stock": true,
"price": 10,
"quantity_step": 1,
"sellable": true,
"variations": []
}
}
GET /orders · HTTP 200{
"success": true,
"data": {
"items": [
{
"reference": "01K5A6B7C8D9E0F1G2H3J4K5M6",
"status": "completed",
"product_id": 12,
"variation_id": null,
"merchant_reference": null,
"quantity": 3,
"units": 3,
"units_per_sale": 1,
"unit_price": 10,
"total_price": 30,
"currency": "SAR",
"created_at": "2026-09-21T00:00:00+00:00",
"codes": [
{
"code": "EXAMPLE-CODE-001"
},
{
"code": "EXAMPLE-CODE-002"
},
{
"code": "EXAMPLE-CODE-003"
}
]
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
}
POST /orders · HTTP 201{
"success": true,
"data": {
"reference": "01K5A6B7C8D9E0F1G2H3J4K5M6",
"status": "completed",
"product_id": 12,
"variation_id": null,
"merchant_reference": null,
"quantity": 3,
"units": 3,
"units_per_sale": 1,
"unit_price": 10,
"total_price": 30,
"currency": "SAR",
"created_at": "2026-09-21T00:00:00+00:00",
"codes": [
{
"code": "EXAMPLE-CODE-001"
},
{
"code": "EXAMPLE-CODE-002"
},
{
"code": "EXAMPLE-CODE-003"
}
]
}
}
{
"success": true,
"data": {
"reference": "01K5A6B7C8D9E0F1G2H3J4K5M7",
"status": "pending",
"delivery_type": "top_up",
"system_product_id": 1,
"player_id": "001234567",
"quantity": 1,
"units": 1,
"units_per_sale": 1,
"unit_price": 25,
"total_price": 25,
"currency": "SAR",
"created_at": "2026-09-21T08:00:00+00:00",
"fulfilment_status": "processing",
"refunded": false,
"failure_reason": null,
"codes": []
}
}
GET /orders/{reference} · HTTP 200{
"success": true,
"data": {
"reference": "01K5A6B7C8D9E0F1G2H3J4K5M6",
"status": "completed",
"product_id": 12,
"variation_id": null,
"merchant_reference": null,
"quantity": 3,
"units": 3,
"units_per_sale": 1,
"unit_price": 10,
"total_price": 30,
"currency": "SAR",
"created_at": "2026-09-21T00:00:00+00:00",
"codes": [
{
"code": "EXAMPLE-CODE-001"
},
{
"code": "EXAMPLE-CODE-002"
},
{
"code": "EXAMPLE-CODE-003"
}
]
}
}
GET /topup-products · HTTP 200{
"success": true,
"data": {
"items": [
{
"id": 1,
"name": "Example ID top-up package",
"category": "Example game",
"delivery_type": "top_up",
"price": 25,
"currency": "SAR",
"available_stock": 3,
"sellable": true,
"quantity_step": 1,
"max_quantity": 1,
"fields": []
}
],
"pagination": {
"page": 1,
"per_page": 50,
"total": 1,
"last_page": 1
}
}
}
GET /topup-products/{product} · HTTP 200{
"success": true,
"data": {
"id": 1,
"name": "Example ID top-up package",
"category": "Example game",
"delivery_type": "top_up",
"price": 25,
"currency": "SAR",
"available_stock": 3,
"sellable": true,
"quantity_step": 1,
"max_quantity": 1,
"fields": []
}
}
{"success": false, "error": {"code": "order_refused", "message": "Insufficient stock", "reason": "insufficient_stock"}}
| الرمز | HTTP | المعنى |
|---|---|---|
missing_token |
401 | لم تُرسل ترويسة المصادقة |
invalid_token |
401 | المفتاح غير صحيح |
client_disabled |
403 | الحساب معطّل |
ip_not_allowed |
403 | العنوان خارج القائمة المسموحة |
rate_limited |
429 | تجاوزت حد الطلبات |
client_without_wallet |
409 | المفتاح غير مرتبط بحساب فيه محفظة. يأتيك رمزاً مستقلاً على GET /balance، ويأتيك سبباً في error.reason تحت order_refused إذا حاولت الشراء: علّة واحدة في موضعين. |
idempotency_key_required |
400 | الشراء بلا مفتاح تكرار |
idempotency_key_too_long |
400 | قيمة Idempotency-Key أطول من 128 بايتاً. تُرفض كما هي ولا تُقصّ، لأن مفتاحاً مقصوصاً قد يطابق مفتاحاً آخر فيردّ عليك نتيجة طلبية ليست لك. |
idempotency_key_reused |
409 | نفس المفتاح لمحتوى مختلف |
request_in_progress |
409 | طلب بنفس المفتاح ما زال يُنفَّذ |
request_abandoned |
409 | طلب بنفس المفتاح لم يكتمل وقد أُنشئت طلبيته — اقرأها من GET /orders/{reference}، والمرجع يأتيك في error.reference. لا تشترِ مرة أخرى. |
validation_failed |
422 | بيانات ناقصة أو غير صالحة (التفاصيل في error.fields) |
variation_mismatch |
422 | الفئة (variation_id) لا تنتمي إلى المنتج المطلوب |
product_not_found |
404 | يخصّ GET /products/{id} وحده: المنتج غير موجود، أو موقوف، أو قسمه موقوف. في الشراء الأمر مختلف: رقم منتج لا وجود له يسقط في التحقق فيعود validation_failed بالرمز 422، ومنتج قائم لكنه موقوف يعود order_refused بالرمز 409 ومعه reason: product_inactive. |
product_reference_not_found |
404 | merchant_reference غير مربوط بأي منتج في حسابك. المرجع الذي وصلنا يعود إليك في error.merchant_reference لتقارنه بما أرسلت. |
product_reference_ambiguous |
422 | سمّيت المنتج مرّتين: product_id مع merchant_reference، أو variation_id يخالف الفئة المحفوظة في الربط. |
order_not_found |
404 | لا توجد طلبية بهذا المرجع تحت هذا المفتاح. مرجع خاطئ ومرجع يخصّ مفتاحاً آخر يعطيان الجواب نفسه، عمداً. |
order_refused |
409 | رُفض الشراء. الحقل error.reason يسمّي السبب (انظر الجدول التالي)، لكنه ليس مضموناً: رفض غير متوقّع يأتي بلا error.reason أصلاً. غيابه يعني سبباً مجهولاً لا سبباً عابراً — لا تُعِد المحاولة آلياً عليه، اقرأ error.message وعامله كعطل. |
server_error |
500 | خطأ غير متوقع. لا تفترض أن شيئاً لم يُخصم: أعد المحاولة بنفس مفتاح التكرار، فإن جاءك request_abandoned فالطلبية قائمة ومرجعها في الرد. |
error.reason مع order_refused)| السبب | هل تعيد المحاولة؟ | المعنى |
|---|---|---|
insufficient_stock |
نعم، لاحقاً | المخزون أقل من المطلوب في هذه اللحظة |
insufficient_balance |
بعد الشحن | رصيد المحفظة لا يكفي |
quantity_step |
نعم، بكمية أخرى | يُباع هذا المنتج بوحدات من عدّة أكواد؛ الكمية يجب أن تكون من مضاعفات quantity_step |
product_inactive |
لا | المنتج أو الفئة أو القسم موقوف |
price_unavailable |
لا | لا يوجد سعر بيع مسجّل لهذا الرفّ. لا تكرّر المحاولة، تواصل مع الدعم. |
client_without_wallet |
لا | المفتاح غير مرتبط بحساب فيه محفظة |
لا خصم بلا أكواد.
الخصم وتسليم الأكواد يحدثان معاً أو لا يحدث أيّهما: أي فشل قبل اعتماد المعاملة يعيد الرصيد والمخزون كما كانا. وثغرة واحدة نصرّح بها: فشل بعد الاعتماد — أثناء تجهيز الرد — يترك الطلبية قائمة والمحفظة مخصومة، ويصلك 500. ليس خصماً بلا أكواد، بل أكواد لم تصلك: استعدها بإعادة المحاولة بنفس مفتاح التكرار، فيردّك request_abandoned بمرجع الطلبية لتقرأها بأكوادها من GET /orders/{reference}.
لا كود لعميلين. الأكواد تُقفل أثناء البيع، فطلبان متزامنان على آخر كود لا ينتهيان بنفس الكود — أحدهما يحصل عليه والآخر يُرفض بوضوح.
NEXCODE · للدعم التقني تواصل مع مزوّد الخدمة.