ادمج نظامك مع Shipper لإنشاء وتتبع الطلبات برمجياً.
Shipper Open API هي واجهة برمجة REST تتيح لك:
https://server.shipper.network/api/v1للبدء، أنشئ مفتاح API من لوحة تحكم Shipperفي التكاملات > API.
جميع طلبات API تتطلب رمز Bearer في رأس Authorization.
Authorization: Bearer YOUR_API_KEY
Accept: application/json
Content-Type: application/jsonالطلبات محدودة المعدل لكل مفتاح API. تجاوز الحد يعيد HTTP 429 (طلبات كثيرة جداً).
| نوع النقطة | الحد | النقاط |
|---|---|---|
| قراءة | 120طلب/دقيقة | GET /products, /orders, /orders/:id, /webhooks |
| مرجع | 60طلب/دقيقة | GET /countries, /countries/:code/divisions |
| كتابة | 30طلب/دقيقة | POST /orders, /webhooks |
| تدميري | 20طلب/دقيقة | POST /orders/:id/cancel, DELETE /webhooks/:id |
رؤوس حد المعدل (X-RateLimit-Limit، X-RateLimit-Remaining) مضمنة في كل استجابة.
GET /countriesيعيد جميع البلدان المدعومة مع هيكلها الجغرافي. استخدمه لفهم مستويات التقسيم الإداري المطلوبة (ولاية، معتمدية، إلخ) لكل بلد.
curl https://server.shipper.network/api/v1/countries \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
[
{
"code": "TN",
"name": "Tunisia",
"geo_structure": {
"fields": [
{ "id": "division_1_id", "label": "Governorate", "level": 1, "required": true, "depends_on": null },
{ "id": "division_2_id", "label": "Delegation", "level": 2, "required": true, "depends_on": "division_1_id" }
]
}
}
]مصفوفة geo_structure.fields تخبرك بعدد مستويات التقسيم وتسمياتها والتبعيات. استخدم depends_on لبناء قوائم متتالية.
GET /countries/{code}/divisionsيعيد أسماء التقسيمات لبلد معين. استخدمه للحصول على القيم الصحيحة لـ address.division_1 و address.division_2 عند إنشاء الطلبات.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
level | integer | - | مستوى التقسيم (افتراضي: 1 = المستوى الأعلى) |
parent_id | integer | - | تصفية حسب معرف التقسيم الأب للحصول على الأبناء |
curl https://server.shipper.network/api/v1/countries/TN/divisions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"{
"country": "TN",
"geo_structure": { ... },
"divisions": [
{ "id": 1, "name": "Tunis", "level": 1, "parent_id": null },
{ "id": 2, "name": "Sfax", "level": 1, "parent_id": null },
{ "id": 3, "name": "Sousse", "level": 1, "parent_id": null }
]
}curl "https://server.shipper.network/api/v1/countries/TN/divisions?level=2&parent_id=1" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"{
"country": "TN",
"geo_structure": { ... },
"divisions": [
{ "id": 10, "name": "Bab El Bhar", "level": 2, "parent_id": 1 },
{ "id": 11, "name": "Bab Souika", "level": 2, "parent_id": 1 },
{ "id": 12, "name": "Carthage", "level": 2, "parent_id": 1 }
]
}GET /productsيعيد كتالوج منتجاتك مع معرفات UUID. تحتاج UUID المنتج لإنشاء الطلبات عبر API.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
page | integer | - | رقم الصفحة (افتراضي: 1) |
per_page | integer | - | عناصر في الصفحة (افتراضي: 20، أقصى: 100) |
search | string | - | بحث باسم المنتج أو SKU |
curl "https://server.shipper.network/api/v1/products?per_page=10&search=shirt" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{
"data": [
{
"uuid": "2e97b37a-3118-4905-842c-19706bcf1455",
"name": "Blue T-Shirt",
"sku": "SKU-001",
"price": 190,
"status": "active",
"available_qte": 42,
"variants": [
{
"uuid": "a1b2c3d4-5678-9012-abcd-ef0123456789",
"name": "Size L",
"sku": "SKU-001-L",
"price": 190,
"available_qte": 15
}
]
}
],
"pagination": { "total": 50, "current_page": 1, "per_page": 10, "last_page": 5 }
}GET /products/{uuid}يعيد منتجاً واحداً بمعرف UUID، بما في ذلك المتغيرات والكميات المتوفرة.
curl https://server.shipper.network/api/v1/products/2e97b37a-3118-4905-842c-19706bcf1455 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{
"uuid": "2e97b37a-3118-4905-842c-19706bcf1455",
"name": "Blue T-Shirt",
"sku": "SKU-001",
"price": 190,
"status": "active",
"available_qte": 42,
"variants": [
{ "uuid": "a1b2c3d4-...", "name": "Size L", "sku": "SKU-001-L", "price": 190, "available_qte": 15 },
{ "uuid": "e5f6a7b8-...", "name": "Size M", "sku": "SKU-001-M", "price": 190, "available_qte": 27 }
]
}GET /ordersيعيد قائمة مرقمة من طلباتك. استخدم الفلاتر للتصفية حسب الحالة أو نطاق التاريخ أو مصطلحات البحث.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
page | integer | - | رقم الصفحة (افتراضي: 1) |
per_page | integer | - | عناصر في الصفحة (افتراضي: 20، أقصى: 100) |
status | string | - | تصفية حسب حالة الشحنة (مثل delivered، awaitingpackaging، canceled) |
start_date | string | - | تصفية الطلبات المنشأة في أو بعد هذا التاريخ (YYYY-MM-DD) |
end_date | string | - | تصفية الطلبات المنشأة في أو قبل هذا التاريخ (YYYY-MM-DD) |
search | string | - | البحث برقم الطلب أو اسم العميل أو رقم الهاتف |
curl "https://server.shipper.network/api/v1/orders?status=delivered&start_date=2025-01-01&per_page=10" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{
"data": [
{
"id": 555,
"status": "Paid",
"store_name": "My Store",
"is_cod": true,
"is_paid": true,
"created_at": "2025-01-10T10:00:00.000000Z",
"address": { "first_name": "Omar", "last_name": "Ben Ali", "phone1": "+21628177188" },
"items_count": 2,
"shipments_count": 1,
"external_order_id": "ORD-123",
"external_order_url": "https://mystore.com/orders/123"
}
],
"pagination": { "total": 150, "current_page": 1, "per_page": 10, "last_page": 15 }
}POST /ordersينشئ طلباً جديداً في Shipper. يعيد معرف الطلب الذي يمكنك استخدامه لتتبع الطلب.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
address | object | * | كائن عنوان المستلم (انظر الحقول أدناه) |
address.name | string | * | الاسم الكامل - يقسم تلقائياً إلى الاسم الأول واللقب |
address.phone1 | string | * | رقم الهاتف الرئيسي |
address.phone2 | string | - | رقم الهاتف الثانوي |
address.address1 | string | * | العنوان السطر 1 |
address.address2 | string | - | العنوان السطر 2 |
address.division_1 | string | - | الولاية - است خدم الاسم الدقيق من GET /countries/{code}/divisions |
address.division_2 | string | - | المعتمدية - استخدم الاسم الدقيق من GET /countries/{code}/divisions?level=2&parent_id=... |
address.country | string | * | رمز البلد من حرفين (مثل TN، DZ، MA) |
items | array | * | مصفوفة عناصر الطلب |
items[].id | string | * | UUID المنتج أو المتغير من GET /products |
items[].quantity | integer | - | الكمية (افتراضي: 1) |
items[].total_price | number | - | السعر الإجمالي لهذا العنصر. الافتراضي: سعر المنتج × الكمية |
shipping_total | number | - | تكلفة الشحن المحملة على العميل (افتراضي: 0) |
is_cod | boolean | - | ) |
auto_fulfill | boolean | - | إرسال مباشرة للتجهيز دون إنشاء مسودة (افتراضي: false) |
with_confirmation | boolean | - | طلب مكالمة تأكيد هاتفية قبل الشحن (افتراضي: false) |
store_name | string | - | اسم المتجر المصدر - يظهر في تتبع الطلب كمرجع لك |
external_order_id | string | - | معرف مرجع الطلب في نظامك - يظهر في لوحة تحكم Shipper |
external_order_url | string | - | رابط الطلب في نظامك - قابل للنقر من لوحة تحكم Shipper |
curl -X POST https://server.shipper.network/api/v1/orders \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"address": {
"name": "Omar Ben Ali",
"division_1": "Tunis",
"division_2": null,
"phone1": "28177188",
"address1": "Rue de la Liberte",
"country": "TN"
},
"items": [
{ "quantity": 1, "id": "YOUR_PRODUCT_UUID", "total_price": 190 }
],
"shipping_total": 9,
"is_cod": true,
"auto_fulfill": true,
"with_confirmation": true,
"store_name": "My Store",
"external_order_id": "ORD-12345",
"external_order_url": "https://mystore.com/orders/12345"
}'201تم الإنشاء
{
"id": 555
}GET /orders/{id}يعيد تفاصيل الطلب الكاملة بما في ذلك الحالة الحالية وأرقام تتبع الشحنات مع سجلات التسليم وعنوان المستلم.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
id | integer | * | معرف الطلب الذي أُعيد عند إنشاء الطلب |
curl https://server.shipper.network/api/v1/orders/555 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{
"id": 555,
"status": "Paid",
"contact_task_status": "called",
"shipments": [
{
"uuid": "11111111-2222-3333-4444-555555555555",
"status": "delivered",
"tracking_numbers": [
{
"number": "99999999999",
"logs": [
{ "status": "at_carrier_origin_facility", "created_at": "2025-01-15T02:02:59.000000Z", "external_timestamp": "2025-01-14 22:48:00" },
{ "status": "in_transit", "created_at": "2025-01-15T02:02:59.000000Z", "external_timestamp": "2025-01-14 23:05:00" },
{ "status": "delivered", "created_at": "2025-01-18T02:09:19.000000Z", "external_timestamp": "2025-01-17 14:16:00" }
]
}
]
}
],
"address": {
"first_name": "Omar", "last_name": "Ben Ali",
"phone1": "+21628177188", "phone2": "",
"address1": "Rue de la Liberte", "address2": "",
"division_1": "Tunis", "division_2": null, "country": "TN"
}
}POST /orders/{id}/cancelيلغي طلباً وشحناته المرتبطة. يعمل للطلبات في مرحلة التأكيد (انتظار التأكيد الهاتفي) أو مرحلة التحضير (انتظار التغليف). الطلبات التي تم شحنها لا يمكن إلغاؤها عبر API.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
id | integer | * | معرف الطلب المراد إلغاؤه |
curl -X POST https://server.shipper.network/api/v1/orders/555/cancel \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{
"success": true,
"canceled_shipments": 1
}422إذا لم يكن هناك شحنات قابلة للإلغاء:
{
"error": "No shipments available to cancel"
}تتيح لك Webhooks تلقي إشعارات HTTP فورية عند تغيير حالة الطلب أو الشحنة، بدلاً من الاستعلام المتكرر عن API.
POST /webhooksسجل رابطاً لتلقي أحداث webhook. يمكنك تسجيل حتى 5 webhooks لكل مفتاح API. يجب أن يستخدم الرابط HTTPS.
| المعلمة | النوع | مطلوب | الوصف |
|---|---|---|---|
url | string | * | رابط HTTPS الذي سيستقبل طلبات POST مع بيانات الحدث |
events | array | * | الأحداث للاشتراك: "order.status_changed" و/أو "shipment.status_changed" |
secret | string | - | مفتاح سري (16 حرف كحد أدنى) يُستخدم لتوقيع البيانات بـ HMAC-SHA256 للتحقق |
curl -X POST https://server.shipper.network/api/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mystore.com/webhooks/shipper",
"events": ["order.status_changed", "shipment.status_changed"],
"secret": "my-webhook-secret-key"
}'201
{
"id": 1,
"url": "https://mystore.com/webhooks/shipper",
"events": ["order.status_changed", "shipment.status_changed"],
"status": "active",
"created_at": "2025-03-29T10:00:00.000000Z"
}GET /webhooksيعيد جميع webhooks المسجلة لمفتاح API الحالي، بما في ذلك حالتها وعدد الإخفاقات.
curl https://server.shipper.network/api/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
[
{
"id": 1,
"url": "https://mystore.com/webhooks/shipper",
"events": ["order.status_changed", "shipment.status_changed"],
"status": "active",
"last_triggered_at": "2025-03-29T15:30:00.000000Z",
"failure_count": 0,
"created_at": "2025-03-29T10:00:00.000000Z"
}
]DELETE /webhooks/{id}يحذف تسجيل webhook. سيتوقف webhook عن تلقي الأحداث فوراً.
curl -X DELETE https://server.shipper.network/api/v1/webhooks/1 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"200
{ "success": true }عند حدوث حدث، يرسل Shipper طلب POST إلى رابطك المسجل مع جسم JSON:
{
"event": "order.status_changed",
"timestamp": "2025-01-15T10:30:00.000000Z",
"data": {
"order_id": 555,
"status": "Paid",
"previous_status": "Pending"
}
}{
"event": "shipment.status_changed",
"timestamp": "2025-01-15T10:30:00.000000Z",
"data": {
"order_id": 555,
"shipment_uuid": "11111111-2222-3333-4444-555555555555",
"status": "delivered",
"previous_status": "onitsway"
}
}إذا قدمت مفتاحاً سرياً عند تسجيل webhook، يتضمن كل طلب رأس X-Shipper-Signature. تحقق منه بحساب HMAC-SHA256 لجسم الطلب باستخدام مفتاحك السري:
// Node.js example
const crypto = require('crypto');
const signature = crypto.createHmac('sha256', 'my-webhook-secret-key')
.update(rawBody)
.digest('hex');
const isValid = signature === req.headers['x-shipper-signature'];تستخدم API رموز حالة HTTP القياسية. جميع استجابات الخطأ تتضمن جسم JSON مع التفاصيل.
| الرمز | المعنى |
|---|---|
| 200 | نجاح |
| 201 | تم إنشاء المورد بنجاح |
| 401 | غير مصرح - مفتاح API مفقود أو غير صالح |
| 403 | ممنوع - مفتاح API معطل أو ملغى |
| 404 | غير موجود - المورد المطلوب غير موجود |
| 422 | خطأ تحقق - تحقق من كائن الأخطاء في جسم الاستجابة للتفاصيل |
| 429 | طلبات كثيرة جداً - تم تجاوز حد المعدل. انتظر وأعد المحاولة |