واجهة التكامل البرمجية
تتيح هذه الواجهة لـموصّل متجر إلكتروني قراءة كتالوج Nadigit IMS ومخزونه، وحجز مخزون لسلة شراء، وتسجيل الطلبات. وفي المقابل، يُبلغ Nadigit IMS الموصّل عبر webhooks موقّعة. هذه هي الواجهة التي يستخدمها موصّل Bagisto، وهي التي يُبنى عليها موصّل لأي منصّة أخرى.
لا توثّق هذه الصفحة إلا واجهة التكامل: الواجهات البرمجية الأخرى في Nadigit IMS مخصّصة للواجهة الويب.
قبل البدء
- باقة Enterprise.
- تكامل مُسجَّل ومُزوّد في تكاملات التجارة الإلكترونية. يقدّم التزويد إعدادات الموصّل. انظر تكامل التجارة الإلكترونية.
| حقل الإعدادات | الاستعمال |
|---|---|
backendUrl | العنوان الأساسي للواجهة: تُضاف إليه المسارات أدناه |
keycloakTokenUrl | عنوان الحصول على الرموز |
keycloakClientId، keycloakClientSecret | بيانات اعتماد الموصّل |
webhookSecret | سرّ التحقق من الـ webhooks |
المصادقة
يحصل الموصّل على رمز وصول عبر تدفّق OAuth 2.0 client credentials، ثم يرسله
في ترويسة Authorization مع كل طلب.
curl -s -X POST "$KEYCLOAK_TOKEN_URL" \
-d grant_type=client_credentials \
-d client_id="$CLIENT_ID" \
-d client_secret="$CLIENT_SECRET"
GET /api/ecommerce/catalog HTTP/1.1
Authorization: Bearer <access_token>
- الرمز قصير المدة (
expires_inبالثواني): احتفظ به وجدّده قبيل انتهاء صلاحيته، بدل طلب رمز جديد مع كل استدعاء. - النطاق. لا يصل الموصّل إلا إلى واجهة التكامل، ولا يخصّ إلا المستودع والمتجر المرتبطين بالتكامل. المستودع ليس أبدًا معاملًا في الطلب: تحدّده هوية الموصّل.
الاصطلاحات
- التبادل بصيغة JSON وترميز UTF-8.
- SKU هو مرجع الصنف في Nadigit IMS، وهو فريد داخل المستودع.
- تُعبَّر الكميات بـوحدة البيع الخاصة بالصنف، مع كسور عشرية للأصناف التي تُباع
بالوزن أو القياس (
fractional). - المبالغ بعملة المنظمة.
نقاط الوصول
| الطريقة | المسار | الدور |
|---|---|---|
GET | /api/ecommerce/catalog | الكتالوج القابل للنشر، مقسّم إلى صفحات |
GET | /api/ecommerce/catalog/{sku} | صنف واحد |
GET | /api/ecommerce/stock?skus=… | مخزون 200 صنف كحدّ أقصى |
PUT | /api/ecommerce/reservations/{cartId} | حجز مخزون سلة |
POST | /api/ecommerce/orders | تسجيل طلب |
POST | /api/ecommerce/orders/{reference}/cancel | إلغاء طلب |
الكتالوج
GET /api/ecommerce/catalog?page=0&size=100
GET /api/ecommerce/catalog/ACC-POIG-BL
يضمّ الكتالوج الأصناف النشطة والمادية في المستودع المرتبط، وتُستثنى
الخدمات. القائمة مقسّمة إلى صفحات (page من 0، وsize من 1 إلى 200، و100
افتراضيًا) ومرتّبة حسب SKU. ويعيد SKU غير معروف أو غير نشط أو من مستودع آخر
الرمز 404.
{
"sku": "ACC-POIG-BL",
"name": "Poignée de fenêtre à crémone – blanc",
"description": "…",
"category": "Accessoires",
"categoryPath": ["Accessoires"],
"price": 45.0,
"taxRate": 20.0,
"taxClass": "…",
"taxInclusive": false,
"allocatable": 146.0,
"measureUnit": "Unité",
"fractional": false,
"quantityPrecision": 0,
"primaryImageUrl": "https://…",
"imageUrls": ["https://…"],
"barcodes": ["…"]
}
تعيد القائمة هذه الكائنات داخل صفحة (content، totalElements، totalPages،
number، size). لا يوفّر الكتالوج بعدُ مرشّح «معدَّل منذ»: زامنه كاملًا ثم اعتمد
على الـ webhooks للتغييرات.
المخزون
GET /api/ecommerce/stock?skus=ACC-POIG-BL,SIL-NEU-280,UNKNOWN
[
{ "sku": "ACC-POIG-BL", "found": true, "sellable": 148.0, "reservedByOthers": 2.0, "allocatable": 146.0 },
{ "sku": "UNKNOWN", "found": false, "sellable": null, "reservedByOthers": null, "allocatable": null }
]
| الحقل | المعنى |
|---|---|
sellable | المخزون القابل للبيع في المستودع |
reservedByOthers | الكمية المحجوزة لسلال أخرى أو مبيعات جارية |
allocatable | ما يمكن بيعه بعد: الكمية التي تُعرض |
found | false لـ SKU غير معروف: اسحبه من البيع |
حتى 200 SKU في كل استدعاء، مفصولة بفواصل.
الحجوزات
يمنع حجز مخزون السلة بيع صنف نفد فعلًا عبر الإنترنت. استدعِ نقطة الوصول هذه عند كل تعديل للسلة وقبيل الدفع.
PUT /api/ecommerce/reservations/cart-8841
Content-Type: application/json
{ "lines": [ { "sku": "ACC-POIG-BL", "quantity": 2 } ] }
204: يُستبدل حجز السلة بهذه الأسطر.409: يجب منع الدفع.
{
"code": "insufficient_stock",
"message": "…",
"lines": [ { "sku": "ACC-POIG-BL", "requested": 2, "allocatable": 1 } ]
}
قيمة code هي insufficient_stock (مخزون غير كافٍ، سطرًا بسطر) أو
reservations_disabled (الحجوزات المرنة معطّلة في Nadigit IMS). ينتهي الحجز
تلقائيًا: السلة المتروكة تحرّر مخزونها دون أي تدخل من الموصّل.
الطلبات
POST /api/ecommerce/orders
Content-Type: application/json
{
"reference": "WEB-1000231",
"cartId": "cart-8841",
"orderDate": "2026-09-24T18:40:00",
"customer": { "email": "customer@example.ma", "firstName": "Salma", "lastName": "Idrissi", "phone": "+212600000000" },
"lines": [ { "sku": "ACC-POIG-BL", "quantity": 2, "unitPrice": 45.0 } ],
"declaredTotal": 108.0,
"paymentMethod": "card",
"paymentReference": "ch_3Q…"
}
| الحقل | إلزامي | ملاحظة |
|---|---|---|
reference | نعم | مرجع الطلب في المتجر، 64 حرفًا كحدّ أقصى. يُستخدم مفتاحًا للتفرّد |
cartId | لا | السلة التي يُستهلك حجزها |
customer | لا | يُعثر على العميل ببريده، أو يُنشأ |
lines | نعم | SKU والكميات. unitPrice استرشادي |
shipping، declaredTotal | لا | استرشاديان، يُقارنان بالإجمالي المُعاد حسابه |
paymentMethod | لا | انظر أدناه |
paymentReference | لا | مرجع المعاملة، يُحفظ مع الدفعة |
السلوك:
- يعيد Nadigit IMS حساب الأسعار والضرائب. إذا اختلف
declaredTotal، يُقبل الطلب وتصبح قيمةpriceMismatchهيtrue. - يُخصم الطلب من مخزون المستودع ويُربط بالمتجر المرتبط.
- عدم التكرار: إعادة إرسال
referenceنفسه تعيد الطلب الموجود (alreadyExisted: true) دون إنشاء نسخة ثانية. يمكن للموصّل إعادة إرسال طلب بأمان. paymentMethod: القيمcardوwalletوstripeوpaypalوonlineوtransferوcashتسجّل دفعة، فيصبح الطلب مدفوعًا. أماcod(الدفع عند التسليم) أو قيمة فارغة أو غير معروفة فلا تسجّل شيئًا، ويبقى الطلب غير مدفوع.
{
"reference": "WEB-1000231",
"status": "Processing",
"paymentStatus": "PAID",
"totalAmount": 108.0,
"dutyFreeAmount": 90.0,
"taxAmount": 18.0,
"alreadyExisted": false,
"priceMismatch": false,
"declaredTotal": 108.0
}
الإلغاء
POST /api/ecommerce/orders/WEB-1000231/cancel
يلغي الطلب ويعيد مخزونه إلى المستودع. الطلب الملغى مسبقًا يعيد نجاحًا مع
alreadyExisted: true، والمرجع غير المعروف في المستودع يعيد 404. الاسترداد، إن
وُجد، ليس تلقائيًا.
الـ Webhooks
يستدعي Nadigit IMS الموصّل على رابط المتجر + مسار الـ webhook المسجّلين في
التكامل، بطريقة POST، بعد كل تغيير مُسجَّل.
الأحداث
product.updated: تغيّر صنف (المخزون، السعر، الحالة).
{ "event": "product.updated", "action": "upsert", "sku": "ACC-POIG-BL", "occurredAt": "2026-09-24T18:41:07Z" }
action: "upsert": أعد قراءة الصنف عبرGET /api/ecommerce/catalog/{sku}وطبّقه.action: "unpublish": اسحب الصنف من البيع (معطّل، نافد، أو لم يعد في المستودع).
order.status: تغيّرت حالة طلب ويب.
{ "event": "order.status", "reference": "WEB-1000231", "status": "Delivered", "paymentStatus": "PAID", "occurredAt": "2026-09-25T10:02:13Z" }
status | المعنى |
|---|---|
Processing | قيد التحضير (الحالة عند التسجيل) |
Delivered، Completed | مُسلَّم، مكتمل |
Canceled | ملغى |
Return_Pending، Returned، Partial_Return | إرجاع قيد المعالجة، مُرجَع، مُرجَع جزئيًا |
قيمة paymentStatus هي UNPAID أو PARTIALLY_PAID أو PAID.
التحقق من التوقيع
يحمل كل webhook ترويستين:
X-Timestamp: وقت الإرسال بالثواني منذ 1 يناير 1970؛X-Signature: HMAC-SHA256(webhookSecret, X-Timestamp + "." + body)بصيغة ست عشرية بأحرف صغيرة.
أعد حساب التوقيع على النص الخام المستلم، وقارنه في زمن ثابت، وارفض أي طابع زمني قديم جدًا (أكثر من خمس دقائق مثلًا).
$body = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', $ts . '.' . $body, $webhookSecret);
if (!hash_equals($expected, $sig) || abs(time() - (int) $ts) > 300) {
http_response_code(401);
exit;
}
const crypto = require('crypto');
function isValid(rawBody, ts, sig, secret) {
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex');
return sig.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))
&& Math.abs(Date.now() / 1000 - Number(ts)) <= 300;
}
الرد وإعادة المحاولة
أجب بـ 2xx بسرعة، ثم عالج الـ webhook. عند الفشل أو غياب الرد، يعيد Nadigit IMS
المحاولة عدة مرات مع مباعدة المحاولات. تُسجَّل كل محاولة لدى Nadigit IMS. عالج
الـ webhooks بطريقة لا تتأثر بالتكرار: قد يصل الحدث نفسه مرتين.
رموز الأخطاء
| الرمز | السبب |
|---|---|
400 | طلب غير صالح (حقل ناقص أو غير صحيح)؛ يفصّل النص الحقول |
401 | رمز غائب أو منتهي الصلاحية أو غير صالح: جدّد الرمز |
403 | وصول مرفوض، أو وظيفة غير مشمولة في باقة التثبيت |
404 | SKU أو طلب غير معروف في المستودع المرتبط |
409 | مخزون غير كافٍ أو حجوزات معطّلة (انظر الحجوزات) |
503 | تثبيت دون ترخيص نشط |
تعيد الأخطاء غير 409 نصًا على هذا الشكل:
{ "timestamp": "…", "status": 403, "error": "Forbidden", "message": "…", "path": "/api/ecommerce/catalog", "errorCode": "…" }