توثيق API للمطورين
اربط موقعك الخاص بنظام أسهل ناو: استقبل طلبات من موقعك مباشرة في نفس قائمة طلبات الفروع، واقرأ المنتجات والمخزون والفروع لحظياً. المفتاح بيتنشئ من فريق أسهل ناو — تواصل معنا للحصول على مفتاح لحسابك.
البداية السريعة
كل الطلبات بتتبعت إلى https://www.ashalnow.com/api/v1، وكل طلب لازم يحمل هيدر المصادقة التالي:
Authorization: Bearer <keyId>:<secret>لو حددنا لمفتاحك نطاقات مسموحة (allowed domains)، لازم هيدر Origin يبقى من نفس النطاق ده وإلا الطلب هيترفض بـ 403. كل استجابة ناجحة بترجع بنفس الشكل:
{ "success": true, "data": ..., "meta": { "timestamp": "..." } }وأي فشل بنفس الشكل ده:
{ "success": false, "error": { "code": "NOT_FOUND", "message": "المنتج غير موجود" } }حدود الطلبات
كل مفتاح له حد افتراضي 60 طلب/دقيقة و5000 طلب/يوم (قابل للتعديل من فريقنا حسب احتياجك). تجاوز الحد بيرجع 429 RATE_LIMITED.
نقاط النهاية (Endpoints)
/productsيحتاج صلاحية: products:readقائمة المنتجات. فلاتر اختيارية: page, limit, category, search, inStock, minPrice, maxPrice, sort (name|-name|price|-price|newest).
curl "https://www.ashalnow.com/api/v1/products?inStock=true&limit=20" \
-H "Authorization: Bearer ak_xxx:xxxxxx"
{
"success": true,
"data": [
{ "id": "...", "name": "Cola 330ml", "barcode": "...", "categoryName": "Drinks",
"sellingPrice": 15, "quantity": 42, "imageUrl": null }
],
"meta": { "page": 1, "limit": 20, "total": 118, "timestamp": "2026-07-25T10:00:00.000Z" }
}/products/:idيحتاج صلاحية: products:readبيانات منتج واحد.
curl https://www.ashalnow.com/api/v1/products/PRODUCT_ID \
-H "Authorization: Bearer ak_xxx:xxxxxx"/products/:id/stockيحتاج صلاحية: inventory:readكمية منتج معيّن. أضِف ?branchId=... لكمية فرع بعينه، وإلا يرجع الإجمالي على كل الفروع.
curl "https://www.ashalnow.com/api/v1/products/PRODUCT_ID/stock?branchId=BRANCH_ID" \
-H "Authorization: Bearer ak_xxx:xxxxxx"/categoriesيحتاج صلاحية: products:readكل التصنيفات.
curl https://www.ashalnow.com/api/v1/categories \
-H "Authorization: Bearer ak_xxx:xxxxxx"/branchesيحتاج صلاحية: branches:readالفروع النشطة فقط. لو المتجر مالوش فروع، القائمة بترجع فاضية — الطلب في هذه الحالة لا يحتاج branchId ولا area. serviceAreas هي نفس المناطق المستخدمة في تحديد الفرع تلقائياً عند إنشاء طلب بـ customer.area.
curl https://www.ashalnow.com/api/v1/branches \
-H "Authorization: Bearer ak_xxx:xxxxxx"
{ "success": true, "data": [
{ "id": "...", "name": "Nasr City branch", "address": "...", "phone": "...",
"acceptsPickup": true, "acceptsDelivery": true,
"serviceAreas": ["Nasr City", "Fifth Settlement"] }
] }/inventoryيحتاج صلاحية: inventory:readكمية كل المنتجات دفعة واحدة. أضِف ?branchId=... لكميات فرع بعينه.
curl "https://www.ashalnow.com/api/v1/inventory?branchId=BRANCH_ID" \
-H "Authorization: Bearer ak_xxx:xxxxxx"/inventory/:productIdيحتاج صلاحية: inventory:readنفس منطق /products/:id/stock — بديل بنفس الشكل.
curl https://www.ashalnow.com/api/v1/inventory/PRODUCT_ID \
-H "Authorization: Bearer ak_xxx:xxxxxx"/ordersيحتاج صلاحية: orders:writeإنشاء طلب جديد من موقعك. العميل يتربط تلقائياً برقم الهاتف (لو موجود مسبقاً بيتحدّث، ولو جديد بيتعمله سجل). الكميات بتتفحص مقابل المخزون المتاح لحظياً لكن لا تُخصم إلا عند تنفيذ الطلب من نقطة البيع. لو المتجر عنده فروع، لازم واحد من الاتنين: branchId (لو عارف الفرع بنفسك)، أو customer.area (يتحدد الفرع تلقائياً حسب أي فرع بيغطي المنطقة دي — الطلب يترفض برسالة واضحة لو مفيش فرع بيغطيها أو أكتر من فرع بيغطيها مع بعض).
curl -X POST https://www.ashalnow.com/api/v1/orders \
-H "Authorization: Bearer ak_xxx:xxxxxx" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"name": "Ahmed Mohamed", "phone": "01012345678",
"address": "6th of October, District 1", "area": "Nasr City"
},
"items": [ { "productId": "PRODUCT_ID", "quantity": 2 } ],
"deliveryMethod": "delivery",
"notes": "Please call before delivery"
}'
// branchId is optional here — if the store has branches it's determined automatically from "area"
{ "success": true, "data": {
"id": "...", "status": "pending",
"customer": { "id": "...", "name": "Ahmed Mohamed", "phone": "01012345678" },
"items": [ { "productId": "...", "productName": "...", "quantity": 2 } ],
"branchId": "...", "deliveryMethod": "delivery", "createdAt": "..."
} }/ordersيحتاج صلاحية: orders:readالطلبات اللي أنشأها هذا المفتاح فقط (مفيش مشاركة طلبات بين مفاتيح مختلفة). فلاتر: page, limit, status.
curl "https://www.ashalnow.com/api/v1/orders?status=pending" \
-H "Authorization: Bearer ak_xxx:xxxxxx"/orders/:idيحتاج صلاحية: orders:readتفاصيل طلب واحد اتعمل بنفس المفتاح، بما فيها حالته الحالية (pending/fulfilled/cancelled).
curl https://www.ashalnow.com/api/v1/orders/ORDER_ID \
-H "Authorization: Bearer ak_xxx:xxxxxx"/webhooks/testيبعت حدث test.ping اصطناعي لرابط الـ webhook المسجّل على مفتاحك — للتأكد من إن التوقيع والاستقبال شغّالين قبل الاعتماد عليهم.
curl -X POST https://www.ashalnow.com/api/v1/webhooks/test \
-H "Authorization: Bearer ak_xxx:xxxxxx"أكواد الأخطاء
| الكود | HTTP | المعنى |
|---|---|---|
| UNAUTHORIZED | 401 | المفتاح غير صحيح، أو الصيغة غلط (لازم Authorization: Bearer keyId:secret). |
| RATE_LIMITED | 429 | تجاوزت حد الطلبات في الدقيقة أو في اليوم لهذا المفتاح. |
| NOT_FOUND | 404 | المسار أو المورد (منتج/طلب) غير موجود. |
| ERROR | 400/403/500 | خطأ في التحقق من البيانات، صلاحية ناقصة، أو خطأ داخلي — الرسالة (message) بتوضّح السبب بالتفصيل. |
Webhooks
لو سجّلت رابط webhook على مفتاحك، هنبعتلك POST لكل حدث من الأحداث دي:
- order.created
- order.delivered
- order.cancelled
- inventory.low
- inventory.out
- product.updated
- product.disabled
شكل الـ payload:
{
"event": "order.created",
"apiVersion": "v1",
"timestamp": "2026-07-25T10:00:00.000Z",
"clientId": "ak_xxx",
"data": { ... }
}كل طلب بيحمل هيدر X-AshalNow-Signature بالشكل sha256=<hex> — وهو HMAC-SHA256 لنص الـ body الخام (قبل أي JSON.parse) باستخدام الـ webhook secret الخاص بمفتاحك. تأكد من التوقيع قبل ما تصدّق أي حدث:
const crypto = require("crypto");
const expected = "sha256=" + crypto
.createHmac("sha256", webhookSecret)
.update(rawBody) // raw string, not parsed JSON
.digest("hex");
const valid = expected === receivedSignatureHeader;لو السيرفر عندك رجّع غير 2xx أو ماردش خلال 10 ثواني، بنعيد المحاولة تلقائياً على فترات (دقيقة، 5 دقايق، 30 دقيقة، ساعتين، 24 ساعة) قبل ما نعتبر التسليم فاشل نهائياً.
SDK جاهز (JavaScript / Node.js)
عميل خفيف بدون أي مكتبات خارجية — استخدمه من سيرفرك أنت (مش من متصفح العميل، عشان السر بتاعك ميتسربش).
تحميل ashalnow.jsconst AshalNow = require("./ashalnow.js");
const client = new AshalNow({ keyId: "ak_xxx", secret: "xxxxxx" });
const products = await client.listProducts({ inStock: true });
const order = await client.createOrder({
customer: { name: "Ahmed Mohamed", phone: "01012345678", address: "..." },
items: [{ productId: "PRODUCT_ID", quantity: 2 }],
deliveryMethod: "delivery",
});