مقدمة

Toome Developer API واجهةٌ برمجية من نوع REST تتيح لأي نظام خارجي التكامل مع منصة تومي. يمكن عبرها إرسال إشعارات واتساب، استقبال الطلبات من المتاجر الخارجية، وإدارة بيانات العملاء في CRM — كل ذلك من خلال Bearer Token آمن يُصدَر لكل تطبيق مسجَّل.

Base URL: https://dygovil.com/api/v1
جميع الطلبات والاستجابات بصيغة JSON. يجب إرفاق الترويستَين Content-Type: application/json و Accept: application/json في كل طلب.

المصادقة

تعتمد الواجهة البرمجية نظام OAuth2 Client Credentials، وهو النمط المخصص للاتصالات بين الخوادم (server-to-server) حيث لا يتدخل المستخدم النهائي في عملية المصادقة. خطوات الاستخدام:

  1. سجِّل تطبيقاً جديداً من لوحة المطورين للحصول على client_id و client_secret.
  2. أرسِل طلب POST /api/v1/token بهذه البيانات للحصول على access_token.
  3. أرفِق رمز الوصول في ترويسة كل طلب لاحق: Authorization: Bearer {token}.
رموز الوصول محدودة الصلاحية. عند انتهاء صلاحية الرمز يُعيد الخادم 401 Unauthorized، فيتعين إصدار رمز جديد تلقائياً.

نطاقات الصلاحية (Scopes)

يتمتع كل تطبيق بمجموعة محددة من نطاقات الصلاحية تُمنح عند إنشائه. لا يمكن لأي طلب تجاوز النطاقات المُسندة إليه.

Scopeالصلاحية الممنوحة
notifyإرسال إشعارات واتساب عبر قوالب Template معتمدة من Meta
orders.writeإنشاء طلبات خارجية وتحديث حالاتها في تومي
orders.readاسترجاع الطلبات المحفوظة والاطلاع عليها
customers.writeإضافة عملاء جدد وتعديل بياناتهم في نظام CRM
customers.readاسترجاع بيانات العملاء مع دعم البحث والتصفية
brain.chatالتفاعل مع نظام الذكاء الاصطناعي المرتبط بحسابك

رموز الأخطاء

تُعيد الواجهة البرمجية رموز HTTP معيارية مصحوبةً بجسم JSON يتضمن تفاصيل الخطأ.

رمز HTTPالدلالة
401رمز الوصول مفقود أو منتهي الصلاحية — أعِد إصدار التوكن
403التطبيق لا يملك النطاق (scope) المطلوب لهذه العملية
404المورد المطلوب غير موجود (مثل: قالب Template غير معرَّف)
422خطأ في التحقق من صحة البيانات المُرسَلة — راجع حقل errors في الاستجابة
429تجاوزت الحد المسموح به من الطلبات — انتظِر قبل إعادة المحاولة
502فشل إرسال الرسالة عبر Meta API — قد يكون خللاً مؤقتاً من طرف واتساب

POST /token

إصدار رمز وصول (Access Token) باستخدام بيانات اعتماد التطبيق. يُستخدم هذا الرمز في ترويسة Authorization لجميع طلبات الواجهة البرمجية اللاحقة.

POST /api/v1/token

بيانات الطلب

الحقلالنوعالوضعالوصف
client_idstringمطلوبمعرّف التطبيق الفريد — يبدأ بـ tm_
client_secretstringمطلوبالمفتاح السري للتطبيق — احتفظ به في متغيرات البيئة ولا تُضمِّنه في الكود
curl -X POST https://dygovil.com/api/v1/token \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "client_id": "tm_xxxxxxxxxxxxxxxx",
    "client_secret": "your_secret_here"
  }'
$response = Http::post('https://dygovil.com/api/v1/token', [
    'client_id'     => 'tm_xxxxxxxxxxxxxxxx',
    'client_secret' => 'your_secret_here',
]);
$token = $response->json('access_token');
import requests
res = requests.post('https://dygovil.com/api/v1/token', json={
    'client_id': 'tm_xxxxxxxxxxxxxxxx',
    'client_secret': 'your_secret_here'
})
token = res.json()['access_token']
200 { "access_token": "...", "token_type": "Bearer", "scopes": ["notify","orders.write"] }
401 { "error": "invalid_client", "message": "بيانات الاعتماد غير صحيحة" }

GET /test-connection

التحقق من صلاحية رمز الوصول واستعراض نطاقات الصلاحية المُسندة إلى التطبيق. يُفيد هذا الطلب في التشخيص والتأكد من صحة الاندماج قبل الإطلاق.

GET/api/v1/test-connection
curl https://dygovil.com/api/v1/test-connection \
  -H "Authorization: Bearer {your_token}"
200 { "status":"success", "app":{"name":"My App","tenant_id":42}, "scopes":{...} }

GET /templates

استرجاع جميع قوالب الرسائل (Templates) المعتمدة من Meta والمتاحة لحسابك. لا يمكن إرسال رسالة Template إلا بعد ظهورها في هذه القائمة بحالة معتمدة.

GET/api/v1/templates
تُنشأ القوالب من داخل لوحة تومي، ثم تُرسَل تلقائياً إلى Meta لمراجعتها. فور الموافقة عليها تظهر هنا جاهزةً للاستخدام — لا يلزم أي إجراء إضافي من المطور.
200
{
  "success": true,
  "count": 2,
  "data": [
    {
      "id": 5,
      "name": "order_confirmed",
      "language": "ar",
      "category": "UTILITY",
      "body": "مرحباً 1، تم تأكيد طلبك رقم 2 ✅",
      "variables_count": 2
    }
  ]
}

POST /notify

إرسال قالب رسالة واتساب (Template) إلى أي رقم هاتف — حتى في غياب محادثة سابقة مع المستخدم. يُستخدم لإرسال إشعارات المعاملات كتأكيد الطلبات وتذكيرات المواعيد وتنبيهات الشحن. يستلزم نطاق الصلاحية: notify.

POST/api/v1/notify

معاملات الطلب

الحقلالنوعالوضعالوصف
phonestringمطلوبرقم الهاتف بالصيغة الدولية بدون + (مثال: 201012345678)
template_namestringمطلوباسم القالب المعتمد كما يظهر في GET /templates
variablesarrayاختياريقيم المتغيرات الديناميكية مرتّبةً وفق ترتيب {{1}}، {{2}}، ...
languagestringاختياريرمز اللغة (القيمة الافتراضية: ar)
curl -X POST https://dygovil.com/api/v1/notify \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "201012345678",
    "template_name": "order_confirmed",
    "variables": ["Ahmed", "#1042", "150 ج.م"]
  }'
Http::withToken($token)->post('/api/v1/notify', [
    'phone'         => '201012345678',
    'template_name' => 'order_confirmed',
    'variables'     => ['Ahmed', '#1042', '150 ج.م'],
]);
requests.post('/api/v1/notify',
    headers={'Authorization': f'Bearer {token}'},
    json={
        'phone': '201012345678',
        'template_name': 'order_confirmed',
        'variables': ['Ahmed', '#1042', '150 ج.م']
    }
)
200 { "success": true, "message": "تم إرسال الإشعار بنجاح.", "phone": "201012345678", "template_used": "order_confirmed" }
404 { "error": "template_not_found", "message": "القالب غير موجود أو لم تُوافق عليه Meta بعد." }

POST /orders

استقبال طلب قادم من نظامك الخارجي وحفظه في تومي، مع إمكانية إرسال إشعار واتساب للعميل في الوقت ذاته. يستلزم نطاق الصلاحية: orders.write.

POST/api/v1/orders

معاملات الطلب

الحقلالنوعالوضعالوصف
order_refstringمطلوبرقم الطلب الفريد في نظامك الخارجي
customer_phonestringمطلوبرقم هاتف العميل بالصيغة الدولية
customer_namestringاختيارياسم العميل الكامل
totalnumberاختياريإجمالي قيمة الطلب
currencystringاختياريرمز العملة وفق ISO 4217 (مثال: EGP، SAR، USD)
itemsarrayاختياريقائمة المنتجات — كل عنصر: {name, qty, price}
statusstringاختياريحالة الطلب: pending | confirmed | shipped | cancelled
notify_templatestringاختيارياسم قالب الإشعار الذي سيُرسَل للعميل فور تسجيل الطلب
notify_variablesarrayاختياريقيم متغيرات القالب مرتّبةً وفق ترتيب ظهورها في النص
metaobjectاختياريبيانات إضافية مخصصة تُحفظ مع الطلب للرجوع إليها لاحقاً
curl -X POST https://dygovil.com/api/v1/orders \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "order_ref": "ORD-1042",
    "customer_phone": "201012345678",
    "customer_name": "Ahmed Ali",
    "total": 350.00,
    "currency": "EGP",
    "items": [
      {"name": "تيشيرت أبيض", "qty": 2, "price": 175}
    ],
    "notify_template": "order_confirmed",
    "notify_variables": ["Ahmed", "ORD-1042"]
  }'
Http::withToken($token)->post('/api/v1/orders', [
    'order_ref'        => 'ORD-1042',
    'customer_phone'   => '201012345678',
    'total'            => 350.00,
    'notify_template'  => 'order_confirmed',
    'notify_variables' => ['Ahmed', 'ORD-1042'],
]);
201 { "success": true, "order_id": 7, "order_ref": "ORD-1042", "notified": true }

GET /orders

استرجاع قائمة الطلبات الخارجية المحفوظة في تومي مع دعم ترقيم الصفحات. يستلزم نطاق الصلاحية: orders.read.

GET/api/v1/orders?per_page=20

POST /customers

إضافة عميل جديد إلى نظام CRM في تومي، أو تحديث بياناته إن كان رقم هاتفه موجوداً مسبقاً. يستلزم نطاق الصلاحية: customers.write.

POST/api/v1/customers

معاملات الطلب

الحقلالنوعالوضعالوصف
phonestringمطلوبرقم الهاتف — يُستخدم معرّفاً فريداً للعميل في النظام
namestringاختياريالاسم الكامل للعميل
emailstringاختياريعنوان البريد الإلكتروني
genderstringاختياريmale | female | unknown
sourcestringاختياريمصدر اكتساب العميل (مثال: shopify، website، referral)
statusstringاختياريمرحلة العميل في مسار المبيعات: lead | interested | customer
curl -X POST https://dygovil.com/api/v1/customers \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "201012345678",
    "name": "Ahmed Ali",
    "email": "ahmed@example.com",
    "source": "shopify",
    "status": "customer"
  }'
201 { "success": true, "action": "created", "customer": {"id":15,"name":"Ahmed Ali","phone":"201012345678"} }
200 { "success": true, "action": "updated", ... }

GET /customers

استرجاع قائمة العملاء مع دعم البحث النصي والتصفية بالحالة وترقيم الصفحات. يستلزم نطاق الصلاحية: customers.read.

GET/api/v1/customers?status=customer&search=ahmed&per_page=20

مثال تطبيقي: ربط متجر إلكتروني

عند وصول طلب جديد من متجر Shopify عبر Webhook، أرسِله إلى تومي لحفظه وإشعار العميل فوراً عبر واتساب:

// معالج Webhook القادم من Shopify
$order = $request->json()->all();

Http::withToken($token)->post('https://dygovil.com/api/v1/orders', [
    'order_ref'        => $order['order_number'],
    'customer_phone'   => $order['phone'],
    'customer_name'    => $order['customer']['first_name'],
    'total'            => $order['total_price'],
    'notify_template'  => 'order_confirmed',
    'notify_variables' => [$order['customer']['first_name'], $order['order_number']],
]);

مثال تطبيقي: تأكيد الحجوزات

عقب تسجيل حجز مؤكَّد في نظامك، أرسِل قالب الإشعار مباشرةً إلى العميل دون الحاجة إلى محادثة مسبقة معه:

Http::withToken($token)->post('https://dygovil.com/api/v1/notify', [
    'phone'         => $booking->customer_phone,
    'template_name' => 'booking_confirmed',
    'variables'     => [
        $booking->customer_name,
        $booking->service_name,
        $booking->date->format('Y-m-d H:i'),
    ],
]);

مثال تطبيقي: استيراد العملاء تلقائياً

عند إتمام المستخدم تسجيله في موقعك، أضِفه تلقائياً إلى نظام CRM في تومي كي يبدأ الذكاء الاصطناعي التفاعل معه فوراً:

// بعد إتمام تسجيل المستخدم في موقعك
Http::withToken($token)->post('https://dygovil.com/api/v1/customers', [
    'phone'  => $user->phone,
    'name'   => $user->name,
    'email'  => $user->email,
    'source' => 'website_registration',
    'status' => 'lead',
]);

🔐 Toome Auth — خدمة التحقق بكلمة مرور لمرة واحدة (OTP)

Toome Auth خدمةٌ مستقلة لإرسال رموز التحقق (OTP) عبر واتساب — وقريباً عبر الرسائل القصيرة (SMS). تُتيح للمطورين إضافة طبقة تحقق آمنة لأي تطبيق أو موقع إلكتروني في خطوات بسيطة. تدعم الخدمة مسارَي تكامل مختلفَين:

مسار التكامل الحالة المناسبة مسار الطلب آلية المصادقة
Type A — TenantApp صاحب متجر أو تطبيق لديه اشتراك تومي نشط وفعَّل ميزة OTP /api/v1/otp/* Bearer Token (عبر POST /token + نطاق otp)
Type B — Standalone OTP App تطبيق مستقل مخصص للتحقق فقط دون الحاجة إلى اشتراك تومي /api/auth/v1/otp/* Authorization: Bearer {api_key} + X-App-Secret

يُغطي هذا القسم Type B (التطبيق المستقل). إن كنت تستخدم Type A، راجع قسم المصادقة وتأكد من تفعيل نطاق otp.

مصادقة Toome Auth OTP

يتطلب كل طلب في هذا المسار إرفاق ترويستَين في HTTP headers: الأولى تحمل مفتاح API الخاص بتطبيقك، والثانية السر المشترك (App Secret) للتحقق من هويتك.

Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxx
X-App-Secret: your_app_secret_here

يمكن الاطلاع على API Key و App Secret من لوحة المطورين ← تطبيقات OTP ← عرض المفاتيح. يشترط أن يكون التطبيق في حالة active (بعد مراجعته وقبوله من فريق الإدارة).

أمان المفاتيح: لا تُضمِّن API Key أو App Secret في كود الواجهة الأمامية (JavaScript/Mobile). يجب أن تُجرى جميع طلبات OTP من الخادم الخلفي (backend) حصراً.

POST /api/auth/v1/otp/send

إرسال رمز تحقق OTP إلى رقم هاتف عبر واتساب. يُعيد الطلب request_id فريداً يُستخدم في الخطوات اللاحقة.

POST /api/auth/v1/otp/send
Authorization: Bearer sk_live_xxxx
X-App-Secret: your_secret

{
  "phone":   "201012345678",
  "channel": "whatsapp",
  "locale":  "ar",
  "meta":    { "order_id": "ORD-789" }
}
{
  "success":    true,
  "request_id": "req_01JXXXXXXXXXXXXXXXXXXX",
  "expires_at": "2026-06-12T14:05:00Z",
  "cooldown_seconds": 60
}
$res = Http::withHeaders([
    'Authorization' => 'Bearer ' . $apiKey,
    'X-App-Secret'  => $appSecret,
])->post('https://dygovil.com/api/auth/v1/otp/send', [
    'phone'  => $user->phone,
    'locale' => 'ar',
]);
$requestId = $res->json('request_id');
الحقلالنوعالوصف
phone *stringرقم الهاتف بصيغة E.164 دون الرمز + (مثال: 201012345678)
channelstringقناة الإرسال: whatsapp (افتراضي) | sms
localestringلغة رسالة OTP: ar (افتراضي) | en
metaobjectبيانات سياقية اختيارية تُعاد في Webhook عند نجاح التحقق (مثال: رقم الطلب، معرّف الجلسة)

POST /api/auth/v1/otp/verify

التحقق من الرمز الذي أدخله المستخدم. عند النجاح، يُبطَل الرمز فوراً ولا يمكن إعادة استخدامه. يُرجع الطلبُ success: true مع بيانات المستخدم وأي بيانات meta أُرفقت عند الإرسال.

{
  "request_id": "req_01JXXXXXXXXXXXXXXXXXXX",
  "code":       "482917"
}
// نجاح
{
  "success":  true,
  "phone":    "201012345678",
  "meta":     { "order_id": "ORD-789" },
  "verified_at": "2026-06-12T14:03:22Z"
}

// كود خاطئ
{
  "success":    false,
  "error_code": "INVALID_CODE",
  "attempts_remaining": 2
}
$res = Http::withHeaders([
    'Authorization' => 'Bearer ' . $apiKey,
    'X-App-Secret'  => $appSecret,
])->post('https://dygovil.com/api/auth/v1/otp/verify', [
    'request_id' => $requestId,
    'code'       => $userInput,
]);
if ($res->json('success')) {
    // تمَّ التحقق — أكمِل تسجيل المستخدم أو منحه الصلاحية
}

POST /api/auth/v1/otp/resend

إعادة إرسال رمز OTP للرقم ذاته باستخدام request_id الأصلي. يشترط انتهاء مهلة الانتظار بين الإرساليات (افتراضياً 60 ثانية) قبل قبول هذا الطلب.

{
  "request_id": "req_01JXXXXXXXXXXXXXXXXXXX"
}

إذا استُدعي هذا الطلب قبل انتهاء مهلة الانتظار، يُعيد الخادم الخطأ COOLDOWN_ACTIVE مصحوباً بحقل retry_after يُشير إلى عدد الثواني المتبقية.

DELETE /api/auth/v1/otp/{request_id}

إلغاء طلب OTP وإبطال الرمز المرتبط به فوراً. يُستخدم عندما يتحقق المستخدم بوسيلة بديلة، أو يتراجع عن العملية، أو تنتهي جلسته قبل إتمام التحقق.

DELETE /api/auth/v1/otp/req_01JXXXXXXXXXXXXXXXXXXX

GET /api/auth/v1/otp/logs

استرجاع سجل تاريخي لطلبات OTP مع دعم التصفية بالهاتف وحالة الطلب وترقيم الصفحات. مفيد لأغراض المراجعة والتدقيق.

GET /api/auth/v1/otp/logs?status=verified&per_page=20&page=1
{
  "data": [
    {
      "request_id": "req_01JXXX",
      "phone":      "201012345678",
      "channel":    "whatsapp",
      "status":     "verified",
      "created_at": "2026-06-12T14:00:00Z"
    }
  ],
  "meta": { "total": 148, "per_page": 20, "current_page": 1 }
}

القيم المتاحة للتصفية بحقل status: pending (قيد الانتظار) | verified (تم التحقق) | expired (انتهت الصلاحية) | cancelled (ملغى) | failed (فشل الإرسال)

GET /api/auth/v1/apps/stats

استرجاع إحصاءات أداء تطبيق OTP خلال الثلاثين يوماً الأخيرة، مصنَّفةً حسب القناة.

{
  "total_sent":     1420,
  "total_verified": 1184,
  "verify_rate":    "83.4%",
  "today":          47,
  "by_channel": {
    "whatsapp": { "sent": 1400, "verified": 1170 },
    "sms":      { "sent": 20,   "verified": 14   }
  }
}

أرقام الاختبار (Test Phones)

تُتيح لك هذه الميزة تسجيل ما يصل إلى 10 أرقام هواتف مع رموز تحقق ثابتة لأغراض الاختبار. عند إرسال OTP إلى أي من هذه الأرقام:

  • لا تُرسَل أي رسالة واتساب فعلية.
  • لا يُستهلَك أي رصيد أو توكن.
  • يُعاد الرمز الثابت الذي حددته مسبقاً مخزَّناً في Redis.
  • تعمل الميزة في كلا الوضعَين: Live وSandbox.

يمكن إدارة هذه الأرقام من لوحة المطورين ← تطبيقات OTP ← عرض التطبيق ← قسم أرقام الاختبار. الاستجابة تتضمن حقل test_phone: true في كل طلب موجَّه إلى رقم اختبار.

أرقام الاختبار مخصصة لبيئة التطوير فقط. عند الإطلاق للإنتاج، لا حاجة لإجراء أي تغيير في الكود — فقط أزِل الأرقام من القائمة أو لا تُرسِل إليها.

رموز أخطاء OTP

تُعيد واجهة OTP رمز خطأ نصياً محدداً (error_code) يُسهِّل التعامل الآلي مع حالات الخطأ المختلفة.

error_codeرمز HTTPالسبب والمعالجة المقترحة
MISSING_CREDENTIALS401ترويسة Authorization أو X-App-Secret غير مُرفَقة في الطلب
INVALID_API_KEY401مفتاح API غير موجود في النظام — تحقق من صحة المفتاح
INVALID_SECRET401App Secret غير مطابق — راجع بيانات التطبيق في لوحة المطورين
APP_PENDING_REVIEW403التطبيق لا يزال قيد المراجعة ولم يُفعَّل بعد
APP_REJECTED403طلب التطبيق مرفوض — تواصَل مع الدعم الفني للاستفسار
RATE_LIMITED429تجاوز الحد المسموح به (60 طلباً / دقيقة لكل تطبيق)
COOLDOWN_ACTIVE429لم تنقضِ مهلة الانتظار بين الإرساليات — راجع retry_after في الاستجابة
INVALID_CODE422الرمز المُدخَل غير صحيح — راجع attempts_remaining لمعرفة المحاولات المتبقية
OTP_EXPIRED410انتهت صلاحية رمز OTP — أرسِل طلباً جديداً باستخدام POST /otp/send
OTP_ALREADY_VERIFIED409سبق التحقق من هذا الرمز — لا يمكن استخدامه مجدداً
NOT_FOUND404المعرّف request_id غير موجود أو انتهت صلاحيته في قاعدة البيانات