واجهة REST

واجهة REST

المسار الأساسي /api/v1. صادق بمفتاح API للمتجر (wjh_…). كل الاستجابات بنفس الغلاف: status و message و data.

العنوان الأساسي والغلاف

استدعِ الواجهة على مضيف API وجهة تحت /api/v1. الاستجابات الناجحة والأخطاء بنفس الشكل:

Response envelope
{
  "status": 200,
  "message": "ok",
  "data": { }
}

رمز HTTP يطابق حقل status (مثل 201 للإنشاء، و401/403/429 للمصادقة وحدود المعدل).

المصادقة

أنشئ مفتاح API من بوابة التاجر → إعدادات المتجر → المطورون → مفاتيح API. أرسله بأحد الترويسات:

Headers
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# or
x-api-key: wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

يُعرض المفتاح مرة واحدة عند الإنشاء. البادئة دائمًا wjh_.

حدود المعدل

تُطبَّق الحدود لكل مفتاح API مصادق (وحدّ IP منفصل قبل المصادقة):

  • ١٢٠ طلبًا في الدقيقة لكل مفتاح API
  • ٣٠٠ طلب في الدقيقة لكل IP (قبل المصادقة)
429 response
{
  "status": 429,
  "message": "Too many requests",
  "data": null,
  "code": "RATE_LIMITED"
}

النطاقات

يُمنح كل مفتاح نطاقًا واحدًا أو أكثر. النطاق الناقص → 403.

  • orders.crud — إنشاء وقراءة وتحديث وإلغاء الطلبات
  • products.crud — إنشاء وقراءة وتحديث وحذف المنتجات
  • collections.crud — إنشاء وقراءة وتحديث وحذف المجموعات
  • expenses.crud — إنشاء وقراءة وتحديث وحذف المصروفات
  • store.read — قراءة ملف المتجر
  • customers.read — قراءة العملاء (customers.crud يمنح القراءة أيضًا)
  • analytics.read — قراءة مركز التحليلات
  • discounts.read — قراءة أكواد الخصم
  • reviews.read — قراءة تقييمات المنتجات
  • shipping_fees.read — قراءة رسوم شحن العميل حسب المنطقة
  • balance.read — قراءة رصيد الشحن / المحفظة
  • webhooks.read — عرض نقاط الويب هوك والأحداث
  • webhooks.write — إنشاء نقاط الويب هوك

مرجع القيم (Enums)

قيم نصية تُرجعها وتقبلها /api/v1. استخدم القيم كما هي (حساسة لحالة الأحرف).

حالة الطلب (order.status)

القيمةالمعنى
pendingطلب جديد — لم يجهز للاستلام / الحجز بعد
waiting_for_pickupفي انتظار استلام المندوب
readyجاهز — حُجز المخزون / جرت محاولة الحجز حسب الإعداد
packedتم التغليف وبانتظار الشحن
shippedسُلِّم لشركة الشحن / قيد النقل
deliveredتم التسليم للعميل
returnedمرتجع بعد الشحن
cancelledملغي (DELETE /orders/:id ينتقل هنا عند السماح)

قناة الطلب (order.channel)

القيمةالمعنى
manualأُنشئ خارج الأتمتة (API / تشغيل)
portalأُنشئ من بوابة التاجر
storefrontأُنشئ من متجر الواجهة
shopifyمزامن من Shopify عند الربط

طريقة الدفع (order.payment.method)

القيمةالمعنى
codالدفع عند الاستلام — عادةً عيّن payment.codAmount
prepaidمدفوع قبل الشحن (بطاقة / محفظة / رابط)
otherطرق غير شائعة

حالة الشحنة (order.shipping.status)

القيمةالمعنى
pendingسجل شحنة دون حجز بعد
createdمحجوزة لدى شركة الشحن
in_transitقيد النقل
out_for_deliveryخارج للتسليم
deliveredتم التسليم
returnedإرجاع للمنشأ
failedفشل الحجز أو التسليم — راجع error / failureReason
cancelledأُلغيت الشحنة

توقيت التسليم (order.deliveryTiming)

القيمةالمعنى
pendingلم يُقيَّم الوصول المتوقع بعد
on_timeضمن نافذة الوصول المتوقع
earlyأبكر من المتوقع
lateتجاوز الوصول المتوقع

حالة المنتج / المجموعة

القيمةالمعنى
activeنشط / ظاهر حسب الإعداد
draftمسودة غير منشورة
archivedمؤرشف ومخفي (قد يؤرشف الحذف بدل المسح)

حالة التقييم

القيمةالمعنى
pendingبانتظار مراجعة التاجر
approvedظاهر على المتجر
rejectedمرفوض من التاجر
hiddenمخفي من المتجر

أحداث الويب هوك

القيمةالمعنى
OrderCreatedطلب جديد
OrderUpdatedتغيّرت حقول الطلب
OrderStatusChangedانتقال حالة الطلب
ProductUpdatedإنشاء/تحديث/حذف منتج
CollectionUpdatedإنشاء/تحديث/حذف مجموعة
CustomerCreatedعميل جديد
CustomerUpdatedتغيّرت حقول العميل
ShipmentCreatedحُجزت شحنة
ShipmentDeliveredوُسمت الشحنة كمُسلَّمة
ShipmentCreateFailedفشل حجز الشحن
InventoryAdjustedتعديل المخزون
StockReceivedاستلام مخزون وارد

حقول الطلب

خصائص مهمة في كائنات الطلب. رقم البوليصة / التتبع تحت shipping عند وجود حجز شحن.

أساسي

الحقلالمعنى
idمعرّف الطلب الثابت
numberرقم الطلب الظاهر للتاجر
statusحالة دورة الحياة — انظر Enums
channelمصدر إنشاء الطلب
customerIdمعرّف العميل عند الربط
customerNameاسم المشتري
customerPhoneهاتف المشتري
shippingAddressعنوان التسليم
lineItems[]بنود الطلب
paymentالطريقة + مبلغ COD + العملة
totalsالمجموع الفرعي والشحن والخصم والإجمالي
shipmentIdsمعرّفات الشحنات المرتبطة
shippingملخص حجز الناقل (البوليصة)
notesملاحظات
tagsوسوم الطلب
createdAt / updatedAtطوابع زمنية

كائن shipping (البوليصة)

الحقلالمعنى
shipping.shipmentIdمعرّف شحنة وجهة
shipping.carrierرمز الناقل (مثل mega)
shipping.trackingNumberرقم البوليصة / التتبع من الناقل
shipping.waybillنفس trackingNumber — اسم بديل للتكامل
shipping.megaShipmentIdمعرّف الشحنة لدى الناقل عند الحجز
shipping.statusحالة الشحنة لدى الناقل
shipping.qrCodeبيانات QR عند توفرها
shipping.labelUrlرابط الملصق عند التوفر
shipping.errorخطأ الحجز إن فشل
shipping.failureReasonسبب استثناء التسليم
shipping.awbPrintedهل طُبعت البوليصة
shipping.estimatedDeliveryAtالوصول المتوقع بعد الاستلام
shipping.deliveryTimingon_time / early / late / pending

بنود السطر

الحقلالمعنى
variantIdمعرّف المتغير
productIdمعرّف المنتج الأب
skuرمز المخزون
qtyالكمية
priceسعر البيع للوحدة
unitCostتكلفة الوحدة عند الإنشاء
costSourcevariant | stock | missing
imageUrlصورة السطر عند التوفر

DELETE /orders/:id يلغي الطلب عند السماح بالانتقال إلى cancelled — ولا يحذف السجل نهائيًا.

حقول المنتج

خصائص مهمة في كائنات المنتجات من /products.

المنتج

الحقلالمعنى
idمعرّف المنتج
titleالاسم الظاهر
skuSKU على مستوى المنتج عند الاستخدام
statusactive | draft | archived
description / descriptionHtmlالوصف
tagsوسوم
collectionIdsالعضوية في المجموعات
variants[]المتغيرات القابلة للبيع
media / mediaUrlsالصور
trackInventoryهل يُتتبَّع المخزون
inventoryPolicyسياسة النفاد (مثل deny)
storeQuantityالكمية الإجمالية القابلة للبيع
categoryId / subcategoryIdتصنيف الكتالوج
brandالعلامة
price / currencyسعر العرض عند التوفر
importSourceمصدر الاستيراد عند الاستيراد (مثل vondera)
importExternalIdالمعرّف الخارجي من مصدر الاستيراد
warehouseQuantityمخزون مستودع وجهة عند الاشتراك
shopifyProductIdمعرّف منتج Shopify عند الربط

المتغير

الحقلالمعنى
idمعرّف المتغير (لـ lineItems.variantId)
skuSKU فريد للمتجر
titleعنوان المتغير
priceسعر البيع
compareAtPriceالسعر قبل الخصم
attributesالخيارات مثل الحجم واللون
inventoryQuantityالكمية المتاحة
costتكلفة الوحدة عند التعيين
barcodeالباركود عند التعيين
weightGramsوزن المتغير عند التعيين
hsCode / taxCodeأكواد الجمارك / الضريبة عند التعيين

حقول رسوم الشحن والرصيد

نقاط قراءة رسوم المناطق ورصيد محفظة / تسوية الشحن.

منطقة رسوم الشحن

الحقلالمعنى
sectorIdمعرّف المنطقة
nameاسم المنطقة
govId / govNameالمحافظة
feeرسوم التوصيل للعميل
currencyعملة الرسوم
isOverridetrue عند تجاوز افتراضي وجهة
sourceمصدر الرسوم
estimatedArrivalHoursساعات الوصول المتوقعة

الرصيد

الحقلالمعنى
availableالرصيد المتاح
pendingالمبلغ المعلّق
settledالمُسوّى عند التوفر
currencyعملة الرصيد
lowThresholdحد التحذير
isLowtrue عند انخفاض الرصيد
sourcecached | live | simulated
syncedAtآخر مزامنة

مرّر refresh=1 على /balance لفرض مزامنة فورية من الناقل.

الطلبات

النطاق: orders.crud. DELETE يلغي الطلب (انتقال حالة) — لا يوجد حذف نهائي.

List — request
GET /api/v1/orders?pageSize=20
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "ord_01JABC",
        "number": "10042",
        "status": "pending",
        "customerName": "Ahmed Hassan",
        "customerPhone": "+201012345678",
        "payment": { "method": "cod", "codAmount": 495, "currency": "EGP" },
        "totals": { "subtotal": 450, "shipping": 45, "total": 495, "currency": "EGP" },
        "createdAt": "2026-10-08T17:12:04.000Z"
      }
    ],
    "nextPageToken": null
  }
}
Create — request
POST /api/v1/orders
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "customerName": "Ahmed Hassan",
  "customerPhone": "+201012345678",
  "shippingAddress": {
    "city": "Cairo",
    "area": "Nasr City",
    "line1": "12 Nile St",
    "phone": "+201012345678"
  },
  "lineItems": [
    {
      "productId": "prd_01J",
      "variantId": "var_01J",
      "sku": "TEE-BLK-M",
      "title": "Cotton tee",
      "qty": 2,
      "price": 225
    }
  ],
  "payment": { "method": "cod", "codAmount": 495, "currency": "EGP" }
}
Create — response
{
  "status": 201,
  "message": "created",
  "data": {
    "id": "ord_01JABC",
    "number": "10042",
    "status": "waiting_for_pickup",
    "channel": "manual",
    "customerName": "Ahmed Hassan",
    "customerPhone": "+201012345678",
    "lineItems": [
      {
        "variantId": "var_01J",
        "productId": "prd_01J",
        "sku": "TEE-BLK-M",
        "title": "Cotton tee",
        "qty": 2,
        "price": 225,
        "unitCost": 80,
        "costSource": "variant"
      }
    ],
    "payment": { "method": "cod", "codAmount": 495, "currency": "EGP" },
    "totals": { "subtotal": 450, "shipping": 45, "total": 495, "currency": "EGP" },
    "shipmentIds": ["shp_01J"],
    "shipping": {
      "shipmentId": "shp_01J",
      "carrier": "mega",
      "status": "created",
      "trackingNumber": "WJH123456789",
      "waybill": "WJH123456789",
      "megaShipmentId": "mega_987654",
      "qrCode": "MEGA-QR-PAYLOAD",
      "labelUrl": "https://labels.example.com/WJH123456789.pdf",
      "awbPrinted": false
    },
    "createdAt": "2026-10-08T17:12:04.000Z"
  }
}
Cancel — request
DELETE /api/v1/orders/ord_01JABC
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Cancel — response
{
  "status": 200,
  "message": "cancelled",
  "data": {
    "id": "ord_01JABC",
    "status": "cancelled"
  }
}

أيضًا: GET /api/v1/orders/:id و PATCH /api/v1/orders/:id.

المنتجات

النطاق: products.crud.

List — request
GET /api/v1/products?pageSize=20
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "prd_01J",
        "title": "Cotton tee",
        "status": "active",
        "sku": "TEE-BLK",
        "slug": "cotton-tee",
        "brand": "Demo",
        "categoryId": "apparel",
        "subcategoryId": "tshirts",
        "description": "Soft cotton tee",
        "descriptionHtml": "<p>Soft cotton tee</p>",
        "tags": ["basics"],
        "collectionIds": ["col_01J"],
        "seo": { "title": "Cotton tee", "description": "Soft cotton tee" },
        "media": ["media/tee.jpg"],
        "mediaUrls": ["https://cdn.example.com/media/tee.jpg"],
        "trackInventory": true,
        "inventoryPolicy": "deny",
        "storeQuantity": 24,
        "warehouseQuantity": 10,
        "importSource": "vondera",
        "importExternalId": "43254206",
        "variants": [
          {
            "id": "var_01J",
            "sku": "TEE-BLK-M",
            "title": "M",
            "price": 225,
            "compareAtPrice": 275,
            "cost": 80,
            "barcode": "6220000000000",
            "attributes": { "Color": "Black", "Size": "M" },
            "inventoryQuantity": 12,
            "weightGrams": 180
          }
        ]
      }
    ],
    "nextPageToken": null,
    "warehouseEnrolled": true
  }
}
Create — request
POST /api/v1/products
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "title": "Cotton tee",
  "sku": "TEE-BLK",
  "status": "active",
  "description": "Soft cotton tee",
  "variants": [
    {
      "sku": "TEE-BLK-M",
      "price": 225,
      "compareAtPrice": 275,
      "cost": 80,
      "attributes": { "Color": "Black", "Size": "M" },
      "inventoryQuantity": 12
    }
  ]
}
Create — response
{
  "status": 201,
  "message": "created",
  "data": {
    "id": "prd_01J",
    "title": "Cotton tee",
    "sku": "TEE-BLK",
    "status": "active",
    "storeQuantity": 12,
    "variants": [
      {
        "id": "var_01J",
        "sku": "TEE-BLK-M",
        "price": 225,
        "compareAtPrice": 275,
        "cost": 80,
        "attributes": { "Color": "Black", "Size": "M" },
        "inventoryQuantity": 12
      }
    ]
  }
}

أيضًا: GET / PATCH / DELETE /api/v1/products/:id.

المجموعات

النطاق: collections.crud. مجموعات منتجات التاجر (وليس تصنيفات الكتالوج الثابتة).

List — request
GET /api/v1/collections
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      { "id": "col_01J", "title": "Summer", "slug": "summer", "status": "active" }
    ],
    "nextPageToken": null
  }
}
Create — request
POST /api/v1/collections
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "title": "Summer",
  "slug": "summer",
  "status": "active",
  "productIds": ["prd_01J"]
}
Create — response
{
  "status": 201,
  "message": "created",
  "data": {
    "id": "col_01J",
    "title": "Summer",
    "slug": "summer",
    "status": "active",
    "productIds": ["prd_01J"]
  }
}

المصروفات

النطاق: expenses.crud.

List — request
GET /api/v1/expenses?from=2026-10-01&to=2026-10-31
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "exp_01J",
        "categoryName": "Rent",
        "amount": 5000,
        "currency": "EGP",
        "expenseDate": "2026-10-01"
      }
    ]
  }
}
Create — request
POST /api/v1/expenses
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "categoryId": "cat_rent",
  "amount": 5000,
  "currency": "EGP",
  "expenseDate": "2026-10-01",
  "vendor": "Landlord Co",
  "notes": "October rent",
  "recurringRule": "monthly"
}
Create — response
{
  "status": 201,
  "message": "created",
  "data": {
    "id": "exp_01J",
    "categoryId": "cat_rent",
    "categoryName": "Rent",
    "amount": 5000,
    "currency": "EGP",
    "expenseDate": "2026-10-01",
    "vendor": "Landlord Co",
    "recurringRule": "monthly"
  }
}

أيضًا: GET / PATCH / DELETE /api/v1/expenses/:id.

التحليلات

النطاق: analytics.read. مرّر from / to بصيغة YYYY-MM-DD.

Request
GET /api/v1/analytics?from=2026-10-01&to=2026-10-17
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "from": "2026-10-01",
    "to": "2026-10-17",
    "summary": {
      "orders": 128,
      "revenue": 64250,
      "currency": "EGP"
    },
    "series": [
      { "day": "2026-10-01", "orders": 8, "revenue": 4200 }
    ]
  }
}

أكواد الخصم

النطاق: discounts.read (قراءة فقط).

Request
GET /api/v1/discounts
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "dsc_01J",
        "code": "SUMMER10",
        "type": "percent",
        "value": 10,
        "active": true
      }
    ]
  }
}

أيضًا: GET /api/v1/discounts/:id.

العملاء

النطاق: customers.read (أو customers.crud). قراءة فقط على /api/v1.

Request
GET /api/v1/customers?pageSize=20
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "cus_01JDEF",
        "name": "Ahmed Hassan",
        "phone": "+201012345678",
        "email": "ahmed@example.com"
      }
    ],
    "nextPageToken": null
  }
}

أيضًا: GET /api/v1/customers/:id.

التقييمات

النطاق: reviews.read.

Request
GET /api/v1/reviews?status=approved&limit=20
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "rev_01J",
        "productId": "prd_01J",
        "rating": 5,
        "body": "Great quality",
        "status": "approved",
        "createdAt": "2026-10-08T10:00:00.000Z"
      }
    ]
  }
}

أيضًا: GET /api/v1/reviews/:id.

رسوم شحن العميل

النطاق: shipping_fees.read. رسوم المناطق المفروضة على العملاء (افتراضيات وجهة/ميجا + تجاوزات المتجر).

List — request
GET /api/v1/shipping-fees?govId=cairo&limit=50
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "currency": "EGP",
    "megaDefaultsSource": "work_places",
    "items": [
      {
        "sectorId": "sec_nasr_city",
        "name": "Nasr City",
        "govId": "cairo",
        "govName": "Cairo",
        "fee": 45,
        "currency": "EGP",
        "isOverride": false,
        "source": "wijha_default",
        "estimatedArrivalHours": 48
      }
    ]
  }
}
Resolve one zone — request
GET /api/v1/shipping-fees/resolve?sectorId=sec_nasr_city
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Resolve one zone — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "sectorId": "sec_nasr_city",
    "fee": 45,
    "currency": "EGP",
    "isOverride": false,
    "source": "wijha_default",
    "estimatedArrivalHours": 48
  }
}

رصيد الشحن

النطاق: balance.read. رصيد التسوية / المحفظة لحساب شحن المتجر.

Request
GET /api/v1/balance
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json

# Optional: force a fresh sync from the carrier
# GET /api/v1/balance?refresh=1
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "available": 1250.5,
    "pending": 320,
    "settled": 0,
    "currency": "EGP",
    "lowThreshold": 200,
    "isLow": false,
    "source": "cached",
    "syncedAt": "2026-10-08T12:00:00.000Z"
  }
}

معلومات المتجر

النطاق: store.read. ملف عام آمن فقط (بدون أسرار شركة الشحن).

Request
GET /api/v1/store
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Response
{
  "status": 200,
  "message": "ok",
  "data": {
    "id": "str_01JSTORE",
    "name": "Demo Store",
    "slug": "demo-store",
    "status": "active",
    "country": "EG",
    "timezone": "Africa/Cairo",
    "currency": "EGP",
    "contact": {
      "supportEmail": "hello@example.com",
      "supportPhone": "+201012345678",
      "tagline": "Quality basics",
      "logoUrl": "https://cdn.example.com/logo.png"
    },
    "createdAt": "2026-01-01T00:00:00.000Z",
    "updatedAt": "2026-10-08T12:00:00.000Z"
  }
}

Webhooks (عبر الواجهة)

النطاقات: webhooks.read للعرض؛ webhooks.write للإنشاء. نفس نقاط بوابة المطورون → Webhooks.

List — request
GET /api/v1/webhooks/endpoints
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
List — response
{
  "status": 200,
  "message": "ok",
  "data": {
    "items": [
      {
        "id": "wh_01J",
        "nickname": "ERP sync",
        "url": "https://example.com/wijha/hooks",
        "events": ["OrderCreated", "OrderStatusChanged"],
        "active": true,
        "hasSecret": true
      }
    ],
    "nextPageToken": null
  }
}
Create — request
POST /api/v1/webhooks/endpoints
Authorization: Bearer wjh_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "url": "https://example.com/wijha/hooks",
  "method": "POST",
  "nickname": "ERP sync",
  "events": ["OrderCreated", "OrderStatusChanged"],
  "secret": "super-secret-min-8",
  "active": true
}
Create — response
{
  "status": 201,
  "message": "created",
  "data": {
    "id": "wh_01J",
    "url": "https://example.com/wijha/hooks",
    "method": "POST",
    "nickname": "ERP sync",
    "events": ["OrderCreated", "OrderStatusChanged"],
    "hasSecret": true,
    "secret": "super-secret-min-8",
    "active": true,
    "status": "active"
  }
}

أيضًا: GET /api/v1/webhooks/events و GET /api/v1/webhooks/endpoints/:id.