API Webhooks
تتيح لك الـ Webhooks تلقي إشعارات HTTP في الوقت الفعلي عند حدوث أحداث في متجر Mercozy الخاص بك. بدلاً من استطلاع API، قم بتسجيل عنوان URL وسيقوم Mercozy بإرسال بيانات الحدث تلقائياً.
البدء السريع
ابدأ في 3 خطوات:
الخطوة 1: سجّل نقطة النهاية
احصل على مفتاح API الخاص بك من الإعدادات > التكامل > مفاتيح API. يتطلب إذن المسؤول. يتم إنشاء سر توقيع Webhook (whsec_xxx) تلقائيًا عند إنشاء نقطة نهاية ويظهر مرة واحدة فقط.
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks" \
-H "X-API-Key: mk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"name": "My ERP Integration",
"url": "https://your-app.com/webhooks/mercozy",
"events": ["order.created", "order.cancelled", "payment.received"]
}'الخطوة 2: عالج الأحداث الواردة
app.post('/webhooks/mercozy', (req, res) => {
// 1. Verify signature (see below)
const signature = req.headers['x-webhook-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// 2. Process the event
const { type, data } = req.body;
switch (type) {
case 'order.created':
syncOrderToERP(data);
break;
case 'payment.received':
updateAccountingSystem(data);
break;
}
// 3. Respond quickly with 200
res.status(200).json({ received: true });
});الخطوة 3: اختبر نقطة النهاية
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks/{id}/test" \
-H "X-API-Key: mk_live_your_key_here"نقاط النهاية
/webhooks
عرض جميع نقاط نهاية Webhook المسجلة.
/webhooks
تسجيل نقطة نهاية Webhook جديدة لتلقي إشعارات الأحداث.
/webhooks/:id
تحديث نقطة نهاية Webhook موجودة (URL أو الأحداث أو حالة التفعيل).
/webhooks/:id
حذف نقطة نهاية Webhook. لن يتم تسليم الأحداث بعد الآن.
مرجع الحقول
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
id | string | لا | معرف Webhook الفريد (للقراءة فقط) |
name | string | نعم | اسم وصفي لنقطة النهاية هذه |
url | string | نعم | عنوان URL لنقطة نهاية HTTPS لتلقي أحداث Webhook |
events | string[] | نعم | مصفوفة أنواع الأحداث للاشتراك فيها |
secret | string | لا | سر التوقيع للتحقق من الحمولة (للقراءة فقط، يُنشأ عند الإنشاء) |
isActive | boolean | لا | ما إذا كان Webhook نشطاً (افتراضي: true) |
createdAt | datetime | لا | طابع زمني ISO 8601 (للقراءة فقط) |
أنواع الأحداث المتاحة
يدعم Mercozy 18 نوعاً من أحداث Webhook في 6 فئات. اشترك فقط في الأحداث التي تحتاجها.
الطلبات
- order.created
يُطلق عند إنشاء طلب جديد
- order.updated
يُطلق عند تعديل تفاصيل الطلب
- order.cancelled
يُطلق عند إلغاء طلب
- order.completed
يُطلق عند وضع علامة اكتمال على الطلب
- order.status_changed
يُطلق عند أي تغيير في حالة الطلب
المدفوعات
- payment.received
يُطلق عند تحصيل الدفع أو الدفع عند الاستلام
- payment.refunded
يُطلق عند استرداد أو إلغاء الدفع
المنتجات
- product.created
يُطلق عند إضافة منتج جديد
- product.updated
يُطلق عند تغيير تفاصيل المنتج
- product.deleted
يُطلق عند حذف منتج
المخزون
- stock.low
يُطلق عند انخفاض المخزون دون الحد الأدنى
- stock.updated
يُطلق عند تغيير كمية المخزون
العملاء
- customer.created
يُطلق عند تسجيل عميل جديد
- customer.updated
يُطلق عند تحديث معلومات العميل
التوصيل
- delivery.batch_started
يُطلق عند إرسال دفعة توصيل
- delivery.batch_completed
يُطلق عند اكتمال جميع محطات الدفعة
- delivery.completed
يُطلق عند اكتمال توصيل فردي
- delivery.failed
يُطلق عند فشل محاولة التوصيل
حمولة Webhook
يتضمن كل تسليم Webhook نوع الحدث والطابع الزمني وبيانات المورد ذات الصلة.
بيانات حدث الطلب
{
"id": "evt_clx1abc2def3",
"type": "order.created",
"timestamp": "2026-03-19T10:30:00Z",
"data": {
"id": "clx9order123",
"orderNumber": "ORD-1042",
"status": "PENDING",
"total": 4999,
"currency": "USD"
}
}بيانات حدث الدفع
{
"id": "evt_clx2pay4ghi5",
"type": "payment.received",
"timestamp": "2026-03-19T10:35:00Z",
"data": {
"orderId": "clx9order123",
"orderNumber": "ORD-1042",
"amount": 4999,
"currency": "USD",
"paymentMethod": "CARD",
"status": "CAPTURED"
}
}بيانات حدث المنتج
{
"id": "evt_clx3prod6jkl",
"type": "product.created",
"timestamp": "2026-03-19T11:00:00Z",
"data": {
"id": "clx9prod789",
"name": "Organic Coffee Beans",
"sku": "COF-001",
"price": 1299,
"status": "ACTIVE"
}
}بيانات حدث التوصيل
{
"id": "evt_clx4del7mno",
"type": "delivery.completed",
"timestamp": "2026-03-19T14:22:00Z",
"data": {
"orderId": "clx9order123",
"orderNumber": "ORD-1042"
}
}ترويسات HTTP
يتضمن كل طلب webhook الترويسات التالية:
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
Content-Type | string | نعم | application/json |
X-Webhook-Signature | string | نعم | توقيع HMAC-SHA256: sha256={الملخص_السداسي} |
X-Webhook-Timestamp | string | نعم | طابع زمني Unix بالمللي ثانية |
X-Webhook-ID | string | نعم | معرّف حدث فريد لإزالة التكرار |
User-Agent | string | نعم | Mercozy-Webhook/1.0 (+https://www.mercozy.com/docs/webhooks) |
التحقق من التوقيع
يتضمن كل webhook ترويسة X-Webhook-Signature تحتوي على توقيع HMAC-SHA256. تحقق دائماً من هذا التوقيع قبل معالجة الحدث للتأكد من أن الطلب صادر من Mercozy.
Node.js
const crypto = require('crypto');
function verifyWebhook(rawBody, signature, timestamp, secret) {
// Signature is computed over "timestamp.body"
const message = timestamp + '.' + rawBody;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Express middleware
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-webhook-signature'];
const ts = req.headers['x-webhook-timestamp'];
if (!verifyWebhook(req.body, sig, ts, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body);
// Process event...
res.status(200).json({ received: true });
});Python
import hmac
import hashlib
def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
# Signature is computed over "timestamp.body"
message = (timestamp + '.').encode() + payload
expected = 'sha256=' + hmac.new(
secret.encode(),
message,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# Flask example
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
sig = request.headers.get('X-Webhook-Signature')
ts = request.headers.get('X-Webhook-Timestamp')
if not verify_webhook(request.data, sig, ts, WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.get_json()
# Process event...
return {'received': True}, 200PHP
<?php
function verifyWebhook(string $payload, string $signature, string $timestamp, string $secret): bool {
// Signature is computed over "timestamp.body"
$message = $timestamp . '.' . $payload;
$expected = 'sha256=' . hash_hmac('sha256', $message, $secret);
return hash_equals($expected, $signature);
}
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (!verifyWebhook($payload, $signature, $timestamp, $webhookSecret)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process event...
http_response_code(200);
echo json_encode(['received' => true]);سياسة إعادة المحاولة
إذا أعادت نقطة النهاية رمز حالة غير 2xx أو انتهت المهلة (10 ثانية)، سيعيد Mercozy محاولة التسليم بتراجع أسي:
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
المحاولة 1 | لا | فوري | |
المحاولة 2 | لا | بعد ~1s | |
المحاولة 3 | لا | بعد ~4s |
بعد 3 محاولات فاشلة، يتم وضع علامة فشل على التسليم. يمكنك إعادة المحاولة يدوياً من لوحة التحكم أو عبر API.
أفضل الممارسات
استجب خلال 5 ثوانٍ — أعد حالة 200 فوراً وعالج الحدث بشكل غير متزامن. مهلة Mercozy هي 10 ثانية.
تحقق دائماً من التوقيعات — تحقق من ترويسة X-Webhook-Signature قبل معالجة أي حدث لمنع الطلبات المزيفة.
عالج التكرارات (التساوي) — استخدم ترويسة X-Webhook-ID لإزالة تكرار الأحداث. احفظ معرّفات الأحداث المعالجة وتخطَّ ما تمت معالجته.
استخدم نقاط نهاية HTTPS — يتطلب Mercozy عناوين URL بروتوكول HTTPS في بيئة الإنتاج لحماية بيانات webhook أثناء النقل.
سجّل وراقب — سجّل جميع الـ webhooks الواردة وراقب حالات الفشل. استخدم API سجلات التسليم للتحقق من حالة التسليم.