Start here
كل ما تحتاجه للبدء قبل طلبك الأول.
EnvoiSMS.ma هي بنية تحتية للرسائل المبرمجة للمغرب. تحافظ مساراتنا المحلية نحو IAM و Inwi و Orange، مع تحويل تلقائي بين المسارات، على زمن وصول منخفض.
اختبر نقاط النهاية مباشرة واكتشف مخططات OpenAPI 3.1 الكاملة وأنشئ نماذج الأكواد فوراً.
قم بتوليد مفتاح API الخاص بك "smr_..." من لوحة تحكم EnvoiSMS.ma.
استخدم مصادقة Bearer في ترويسات HTTP الخاصة بك مع كل طلب.
اختبر عملية الربط عبر مفاتيح Sandbox (env_test_...) على الرابط المباشر للتحقق من طلباتك دون استهلاك أي رصيد حقيقي.
ادمج واجهة واتساب للأعمال لتقليل تكاليف رموز التحقق (OTP) بمقدار 10 مرات.
قم بتهيئة Webhook موقّع لاستلام تقارير التسليم في الوقت الفعلي.
تابع استهلاكك وفواتيرك بالدرهم المغربي مباشرة من لوحة التحكم.
// config/services.php
'envoisms' => [
'key' => env('ENVOISMS_API_KEY'),
],
// Usage
Http::withToken(config('services.envoisms.key'))
->post('https://api.envoisms.ma/v1/messages', [
'to' => '+212612345678',
'message' => 'Votre commande est en cours de livraison 🚚',
'from' => 'MaBoutique'
]); OpenAPI Spec المصادقة
مفاتيح Bearer والرؤوس والقيود الأمنية.
يتطلب كل مسار /v1 مفتاح واجهة برمجة تطبيقات صالحًا يتم تمريره في ترويسة Authorization كرمز Bearer. يمكن توليد أو إلغاء مفاتيح الاختبار والإنتاج من وحدة التحكم الخاصة بك.
Authorization: Bearer smr_xxx
يتم إرجاع X-RateLimit-Limit و X-RateLimit-Remaining مع كل طلب.
الطلبات الواردة من عناوين IP غير المهيأة ترجع حالة 401.
يتم دعم JSON و Authorization و X-EnvoiSMS.ma-Signature و X-EnvoiSMS.ma-Version.
POST /v1/messages HTTP/1.1
Host: api.envoisms.ma
Authorization: Bearer smr_xxxxxxxx
Content-Type: application/json
Accept: application/jsonOpen Source
حزم SDK الرسمية والمكتبات البرمجية
قم بربط واجهة برمجة EnvoiSMS في تطبيقك بسهولة باستخدام مكتباتنا البرمجية المفتوحة المصدر.
npm install envoismscomposer require envoisms/envoisms-phppip install envoismscomposer require envoisms/laravel-otpgo get github.com/envoisms/envoisms-gonpx -y @envoisms/mcp-serverإرسال رسالة
يرسل رسالة SMS أو رسالة واتساب للأعمال إلى مستلم واحد.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| to | string | مطلوب | رقم الهاتف بصيغة E.164 (+212...). |
| message | string | مطلوب | المحتوى النصي (بحد أقصى 1600 حرف). يُقبل أيضاً تحت الاسم "body". |
| from | string | اختياري | مُعرّف مرسل (Sender ID) مخصص (مثال: NOM_MARQUE). القيمة الافتراضية "EnvoiSMS". |
| channel | string | اختياري | "sms" أو "whatsapp". القيمة الافتراضية "sms". يرسل "whatsapp" من رقم واتساب للأعمال الخاص بك والمتصل (وإلا 403 WHATSAPP_NOT_CONNECTED). لإرسال نص عادي إلى عميل يستخدم واتساب يكفي "sms": بلا ربط ولا نموذج ولا نافذة 24 ساعة. ما لم تكن الرسالة نموذجاً، لا تُقبل رسالة واتساب إلا إذا راسلك جهة الاتصال خلال آخر 24 ساعة — وإلا 400 OUT_OF_24H_WINDOW دون أي خصم (مع cascade يُتخطّى واتساب لصالح القناة التالية). |
| cascade | boolean | اختياري | عند تفعيله، يحاول واتساب ثم يتحول إلى SMS: فوراً إذا رفض واتساب الرسالة أو أبلغ بفشلها (الرقم غير مسجل في واتساب، نافذة 24 ساعة مغلقة…)، أو إذا لم يصل إشعار التسليم خلال cascade_timeout (120 ثانية افتراضياً). لا يُفوتَر إلا الإرسال الذي خرج فعلاً: رسالة واتساب المرفوضة أو الفاشلة لا تُفوتَر وتدفع ثمن SMS وحدها. أما رسالة واتساب التي لم يصل إشعار تسليمها فقد خرجت (قد تُسلَّم عند عودة الهاتف للاتصال)، لذلك تُفوتَر مع رسالة SMS الاحتياطية، وتُسترد إذا أبلغ واتساب لاحقاً بفشلها. نصيحة: اجعل مدة صلاحية (TTL) قالب واتساب لا تتجاوز cascade_timeout، حتى لا يستلم الهاتف العائد للاتصال الرسالتين معاً. |
| cascade_timeout | integer | اختياري | مع cascade: عدد ثواني انتظار إشعار التسليم قبل القناة التالية، من 30 إلى 43200 (12 ساعة). الافتراضي: 120. المدة الأقصر تعني احتياطاً أسرع لكن إرسالاً مزدوجاً مُفوتَراً أكثر؛ والأطول تعني تكرارات أقل. |
| metadata | object | اختياري | أزواج مفاتيح-قيم مخصصة تُخزَّن مع الرسالة وتُمرَّر في Webhooks (لا تُعاد في مسارات GET /v1/messages). مفتاح واحد له معنى لدى المنصة: purpose: "otp" يشير إلى رمز لمرة واحدة تنشئه بنفسك ويفعّل إعادة التسليم التلقائية (انظر الملاحظات). |
| buttons | array | اختياري | مصفوفة من كائنات أزرار واتساب التفاعلية (بحد أقصى 3، من النوع "copy" | "url" | "call"). |
| interactive | object | اختياري | كائن رسالة تفاعلية غنية لواتساب: قوائم منسدلة ("list")، أزرار استجابة سريعة ("button")، استمارات دردشة أصلية ("flow")، زر رابط ("cta_url": الإجراء {"name":"cta_url","parameters":{"display_text","url"}}) أو طلب موقع ("location_request_message"). |
| template | object | اختياري | (واتساب) نموذج معتمد في حسابك: {"name", "language"}، والقيم في metadata.variables. النوع الوحيد المسموح به خارج نافذة الـ 24 ساعة؛ يُسعَّر حسب فئة النموذج. |
| image | video | audio | document | sticker | object | اختياري | (واتساب) وسائط عبر "id" (معرّف وسائط مرفوعة) أو عبر "link" (رابط https)، وليس الاثنين معاً. "caption" للصورة والفيديو والمستند؛ و"filename" للمستند. |
| reaction | object | اختياري | (واتساب) {"message_id": wamid، "emoji": "👍"} — تفاعل مع رسالة من المحادثة؛ الرمز الفارغ يزيل التفاعل. غير مُفوتَر. |
| contacts | array | اختياري | (واتساب) بطاقات جهات اتصال (بحد أقصى 20): name.formatted_name إلزامي؛ وphones وemails وurls وaddresses وorg وbirthday اختيارية. |
| location | object | اختياري | (واتساب) دبوس موقع: {"latitude"، "longitude"، "name"?، "address"?}. |
| context | object | اختياري | (واتساب) {"message_id": wamid} — رد مع اقتباس رسالة سابقة. صالح لجميع الأنواع باستثناء reaction. |
| phone_number_id | string | اختياري | (واتساب) الرقم المتصل الذي يرسل؛ افتراضياً رقمك الافتراضي. |
- هل ترسل رموز OTP؟ هناك نهجان. يتولى /v1/verify/send الدورة الكاملة (التوليد، التسليم، التحقق، انتهاء الصلاحية) ويبقى المسار الموصى به. إذا كنت تنشئ رموزك بنفسك وترسلها هنا، أضف metadata: {"purpose": "otp"}: عند فشل تسليم مؤكد من الشبكة على رقم مغربي والرمز لا يزال حديثاً (أقل من 10 دقائق)، تعيد المنصة إرساله تلقائياً مرة واحدة عبر مسار SMS بديل — بنفس معرّف الرسالة ودون أي تكلفة إضافية. بدون هذه العلامة تُعامَل الرسالة كرسالة SMS عادية.
- واتساب: ما لم تكن الرسالة نموذجاً، لا تُرسَل رسالة (نص، وسائط، تفاعل، جهات اتصال، موقع، تفاعلية) إلا إلى جهة اتصال راسلت رقمك خلال آخر 24 ساعة؛ وإلا يُرفض الطلب بـ 400 OUT_OF_24H_WINDOW قبل أي خصم. مع مفتاح sandbox تبقى عملية الإرسال محاكاة ويشير الرد إلى الرفض في "warnings". لإظهار «يكتب…» أثناء تحضير الرد، راجع POST /v1/messages/typing.
- فواصل الأسطر (\n) مدعومة بالكامل على جميع القنوات وتظهر بشكل صحيح لدى المستلم.
- تنسيق النص الغني (عريض، مائل، إلخ) غير مدعوم على قناة SMS (نص عادي فقط).
- تدعم قناة واتساب تنسيق النص بالصيغة القياسية (*عريض*، _مائل_، ~مشطوب~).
curl -X POST "https://api.envoisms.ma/v1/messages" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+212612345678",
"message": "Votre code de validation est 849204",
"from": "MaBoutique",
"channel": "whatsapp"
}'{
"id": "msg_8f2d...",
"to": "+212612345678",
"channel": "whatsapp",
"cascade": false,
"status": "queued",
"cost": {
"eur": 0.03,
"mad": 0.33
},
"segments": 1,
"created_at": "2026-05-15T10:30:00Z"
}إرسال جماعي (Bulk)
يرسل حتى 10,000 رسالة في طلب API واحد مع مستلمين أو محتويات مختلفة لكل رسالة.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| messages | array | مطلوب | مصفوفة من الكائنات تحتوي على "to" و"message" (أو "body") وكائن اختياري "metadata". |
| from | string | اختياري | مُعرّف مرسل (Sender ID) عام للدفعة بأكملها. |
| channel | string | اختياري | القناة العامة ("sms" أو "whatsapp"). القيمة الافتراضية "sms". |
- فواصل الأسطر (\n) مدعومة بالكامل في نصوص الرسائل الجماعية.
- تنسيق النص الغني (عريض، مائل، إلخ) غير مدعوم على قناة SMS (نص عادي فقط).
- تدعم قناة واتساب تنسيق النص بالصيغة القياسية (*عريض*، _مائل_، ~مشطوب~).
curl -X POST "https://api.envoisms.ma/v1/messages/bulk" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"to": "+212611111111",
"message": "Hello Client 1"
},
{
"to": "+212622222222",
"message": "Hello Client 2"
}
],
"from": "ENVOISMS",
"channel": "sms"
}'{
"batch_id": "batch_9a3c...",
"total": 2,
"channel": "sms",
"estimated_cost": {
"eur": 0.056,
"mad": 0.62
},
"messages": [
{
"id": "msg_1a2b...",
"to": "+212611111111",
"status": "queued"
},
{
"id": "msg_3c4d...",
"to": "+212622222222",
"status": "queued"
}
]
}مؤشر الكتابة في واتساب
يضع علامة «مقروءة» على رسالة واتساب مستلمة ويُظهر لمرسلها «يكتب…» أثناء تحضير الرد (يختفي عند الرد أو بعد نحو 25 ثانية). ليست رسالة: لا يُخزَّن أو يُفوتَر أي شيء.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| message_id | string | مطلوب | معرّف واتساب (wamid) للرسالة المستلمة التي ترد عليها. |
| typing_indicator | boolean | اختياري | القيمة false ترسل إشعار القراءة فقط. الافتراضي: true. |
| phone_number_id | string | اختياري | الرقم المتصل الذي استلم الرسالة؛ افتراضياً رقمك الافتراضي. |
curl -X POST "https://api.envoisms.ma/v1/messages/typing" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"status": "ok",
"message_id": "wamid.HBgLMjEyNjEyMzQ1Njc4FQIAEhgg",
"typing_indicator": true
}قائمة الرسائل
يسترجع قائمة مقسّمة على صفحات بجميع الرسائل المرسلة من الحساب.
| المعلمة | النوع | الحالة | الوصف |
|---|---|---|---|
| limit | integer | اختياري | عدد النتائج المطلوب إرجاعها (1-200، الافتراضي: 50). |
| offset | integer | اختياري | عدد النتائج المطلوب تخطيها لأغراض التقسيم على صفحات (الافتراضي: 0). |
| status | string | اختياري | التصفية حسب الحالة (queued, sent, delivered, failed, undeliverable, unconfirmed). |
| channel | string | اختياري | التصفية حسب القناة (sms, whatsapp). |
| from_date | string | اختياري | التصفية حسب تاريخ البداية (بصيغة ISO 8601). |
| to_date | string | اختياري | التصفية حسب تاريخ النهاية (بصيغة ISO 8601). |
curl -X GET "https://api.envoisms.ma/v1/messages?limit=50&offset=0" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "msg_8f2d...",
"to": "+212612345678",
"channel": "whatsapp",
"body": "Votre code de validation est 849204",
"sender_id": "MaBanque",
"status": "delivered",
"cost_mad": 0.13,
"created_at": "2026-05-15T10:30:00Z"
}
],
"limit": 50,
"offset": 0,
"total": 1
}حالة الرسالة
يعرض تفاصيل رسالة محددة وحالة تسليمها في الوقت الفعلي.
- الحالات الممكنة: queued, sent, delivered, failed, undeliverable, unconfirmed. تعني "unconfirmed" أن المشغّل لم يؤكد التسليم ولم ينفه — وقد يحل محلها إشعار استلام يصل لاحقاً.
- حقل metadata المقدَّم عند الإرسال لا يُعاد هنا؛ بل يُمرَّر في Webhooks.
curl -X GET "https://api.envoisms.ma/v1/messages/:id" \
-H "Authorization: Bearer smr_xxx"{
"id": "msg_8f2d...",
"campaign_id": null,
"to": "+212612345678",
"channel": "sms",
"body": "Votre code de validation est 849204",
"sender_id": "MaBanque",
"unicode": 0,
"segments": 1,
"status": "delivered",
"error_code": null,
"error_message": null,
"cost_eur": 0.0436,
"cost_mad": 0.48,
"scheduled_at": null,
"sent_at": "2026-05-15T10:30:02Z",
"delivered_at": "2026-05-15T10:30:05Z",
"failed_at": null,
"operator": "Maroc Telecom",
"sandbox": 0,
"created_at": "2026-05-15T10:30:00Z"
}قائمة القوالب
يسترجع جميع قوالب واتساب وSMS المعتمدة في حسابك.
curl -X GET "https://api.envoisms.ma/v1/templates" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "tpl_1234...",
"name": "otp_verification",
"channel": "whatsapp",
"body": "Votre code de validation est {{1}}",
"status": "approved",
"category": "otp",
"created_at": "2026-05-15T10:30:00Z"
}
],
"total": 1
}إنشاء قالب
يقدّم قالباً جديداً للاعتماد من قبل مشغّلي الشبكات أو واتساب.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | مطلوب | الاسم الداخلي للقالب. |
| channel | string | مطلوب | "sms" أو "whatsapp". |
| body | string | مطلوب | محتوى الرسالة مع المتغيرات (مثال: {{1}}). |
| category | string | اختياري | فئة القالب (مثال: "otp"، "marketing"). |
| language | string | اختياري | واتساب: رمز لغة Meta (مثال: "fr"، "ar"، "en_US"). القيمة الافتراضية "fr". |
| sample_values | object | string[] | اختياري | واتساب: قيمة توضيحية لكل متغير، إلزامية لمراجعة Meta (مثال: {"1": "Amine"} أو ["Amine"]). |
| header_example_url | string | اختياري | واتساب، ترويسة صورة/فيديو/مستند: رابط https عام لملف توضيحي يُرفع إلى Meta للمراجعة. |
| add_security_recommendation | boolean | اختياري | واتساب، فئة "authentication": يضيف تنبيه الأمان من Meta. نص الرسالة تحدده Meta؛ ويُقبل أيضاً code_expiration_minutes (من 1 إلى 90). |
- يمر قالب واتساب أولاً بمراجعة EnvoiSMS (pending_admin)، ثم يُقدَّم إلى Meta على حساب واتساب للأعمال الخاص بك (pending_meta). Meta وحدها تعتمده (approved)، وفئته النهائية هي التي تحددها Meta.
curl -X POST "https://api.envoisms.ma/v1/templates" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "tpl_1234...",
"name": "order_confirmation",
"channel": "whatsapp",
"language": "fr",
"status": "pending_admin"
}مزامنة القوالب من Meta
يستورد جميع قوالب حساب واتساب للأعمال الخاص بك (الحالة، الفئة، الجودة). القالب الذي لم يعد لدى Meta يصبح deleted_on_meta.
curl -X POST "https://api.envoisms.ma/v1/templates/sync" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"ok": true,
"wabas": ["1234567890"],
"fetched": 12,
"updated": 9,
"inserted": 3,
"marked_deleted": 1,
"complete": true,
"errors": []
}قائمة مُعرّفات المرسل (Sender IDs)
يسترجع قائمة مُعرّفات المرسل الخاصة بك مع حالة اعتماد كل منها.
curl -X GET "https://api.envoisms.ma/v1/sender-ids" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "sid_9a8b...",
"sender_id": "MABANQUE",
"status": "approved",
"requested_at": "2026-05-10T09:00:00Z"
}
]
}طلب مُعرّف مرسل (Sender ID)
يقدّم مُعرّف مرسل جديداً للاعتماد (مطلوب للمغرب).
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| sender_id | string | مطلوب | اسم المرسل المطلوب (بحد أقصى 11 حرفاً). |
| rc_url | string | اختياري | رابط إلى السجل التجاري (Registre de Commerce) لأغراض التحقق. |
curl -X POST "https://api.envoisms.ma/v1/sender-ids" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "sid_9a8b...",
"sender_id": "MABANQUE",
"status": "pending"
}الملف التعريفي لواتساب للأعمال
يعرض المعلومات العامة لملفك التعريفي الموثق في واتساب للأعمال (الاسم، الصورة، الوصف، العنوان، الموقع الإلكتروني).
curl -X GET "https://api.envoisms.ma/v1/whatsapp/profile" \
-H "Authorization: Bearer smr_xxx"{
"about": "Service client officiel EnvoiSMS.ma",
"address": "Casablanca, Maroc",
"description": "Infrastructure de messagerie programmable pour les entreprises au Maroc.",
"email": "[email protected]",
"websites": [
"https://votremarque.ma"
],
"profile_picture_url": "https://pps.whatsapp.net/v/..."
}تحديث الملف التعريفي لواتساب
يحدّث المعلومات المرئية لعملائك في ملفك التعريفي الرسمي على واتساب للأعمال.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| about | string | اختياري | حالة نصية قصيرة (بحد أقصى 139 حرفاً). |
| description | string | اختياري | وصف مفصل لنشاطك التجاري (بحد أقصى 512 حرفاً). |
| address | string | اختياري | العنوان الفعلي لمقرك أو متجرك. |
| string | اختياري | البريد الإلكتروني للتواصل مع العملاء. | |
| websites | array | اختياري | مصفوفة تحتوي على ما يصل إلى رابطين لموقعك الإلكتروني. |
curl -X POST "https://api.envoisms.ma/v1/whatsapp/profile" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"success": true,
"updated_at": "2026-08-30T10:00:00Z"
}توليد رمز OTP
يرسل رمز تحقق لمرة واحدة. وضعان حسب اختيارك: "whatsapp" — تحقق مُدار، الأبسط (تولّد EnvoiSMS الرمز وتسلّمه عبر واتساب من مرسل موثّق؛ إذا رفضت Meta الإرسال عبر واتساب يُرسَل الرمز عبر SMS؛ ومع تطبيق Verify مُعدّ بخيار auto_cascade يُرسَل SMS أيضاً عند انتهاء مهلة القناة، 30 ثانية افتراضياً؛ لا رمز تخزّنه من جانبك) — أو "sms" — تحتفظ بالتحكم الكامل في الرمز والقالب والمرسل. في الحالتين، يتم التحقق بنفس الاستدعاء /v1/verify/check. هل تريد علامتك التجارية على رسالة SMS الاحتياطية للتحقق المُدار؟ متاح عند الطلب: [email protected].
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| to | string | مطلوب | المستلم بصيغة E.164. |
| channel | string | اختياري | "whatsapp" (تحقق مُدار: واتساب، مع SMS احتياطي إذا رفضت Meta الإرسال أو، مع auto_cascade، بعد مهلة القناة؛ الرمز صالح 10 دقائق، 3 محاولات، يُفوتَر لكل عملية تحقق بتعرفة واتساب OTP) أو "sms" (رمز يُولَّد لك ويُرسَل بعلامتك التجارية). الافتراضي: "sms". |
| app_id | string | اختياري | مُعرّف تطبيق Verify المُهيّأ في لوحة التحكم (مثال: vra_...). يطبّق تلقائياً إعدادات الرمز والمُهَل وتسلسل القنوات. |
| brand | string | اختياري | (قناة sms) اسم العلامة التجارية المعروض (مثال: MonApp، بحد أقصى 32 حرفاً). القيمة الافتراضية "EnvoiSMS". |
| code_length | integer | اختياري | (قناة sms) طول الرمز المُولَّد (من 4 إلى 8 أرقام، الافتراضي: 6). |
| expiry | integer | اختياري | مدة صلاحية الرمز بالثواني (من 60 إلى 1800، الافتراضي: 600). على قناة whatsapp تُحدّ بـ 600 (حد قالب المصادقة). |
| cascade | array | اختياري | (قناة sms) قائمة مرتّبة من القنوات للتحويل التلقائي المتسلسل (مثال: ["whatsapp", "sms"]). |
| template | string | اختياري | (قناة sms) نص مخصص مع المتغيرين {{code}} و{{brand}}. في وضع whatsapp، تُدار الرسالة المترجمة (fr/en/es) نيابة عنك. |
| otp_button_text | string | اختياري | (قناة whatsapp) تسمية مخصصة لزر النسخ التلقائي في واتساب (بحد أقصى 25 حرفاً). |
| web_otp_domain | string | اختياري | (اختياري، قناة sms) نطاق الويب لملء W3C WebOTP التلقائي (مثال: "https://mysite.ma"). يضيف علامة @domain #code في نهاية الرسالة. |
| app_hash | string | اختياري | (اختياري، قناة sms) رمز تجزئة توقيع تطبيق Android بطول 11 حرفاً (SMS Retriever API) للكشف التلقائي عن الرمز على Android. |
- الملء التلقائي لرمز OTP (iOS و Android): للسماح للمستخدمين بملء الرمز المستلم تلقائياً بنقرة واحدة فوق لوحة المفاتيح، أضف ببساطة autocomplete="one-time-code" و inputmode="numeric" في حقل <input> في موقعك.
- فترة الانتظار لمكافحة الإغراق (cooldown): يشير الحقل "resend_after_seconds" إلى مدة الانتظار الدقيقة قبل إعادة المحاولة (60 ثانية لواتساب وفقاً لمعايير Meta، و30 ثانية لـ SMS). ينطبق حد يومي قدره 10 عمليات تحقق لكل رقم.
curl -X POST "https://api.envoisms.ma/v1/verify/send" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+212612345678",
"brand": "MonApp",
"channel": "whatsapp",
"code_length": 6,
"expiry": 600
}'{
"session_id": "vrf_7e2a...",
"to": "+212612345678",
"channel": "whatsapp",
"resend_after_seconds": 60,
"fallback_channels": ["sms", "whatsapp"],
"expires_at": "2026-05-15T10:35:00Z",
"status": "sent",
"cost": { "eur": 0.05, "mad": 0.55 }
}إعادة إرسال رمز OTP (SMS أو واتساب)
يعيد إرسال نفس رمز OTP النشط عبر SMS أو واتساب بعد انقضاء فترة الانتظار (30 ثانية لـ SMS، و60 ثانية لواتساب). لا يتم إنشاء رمز جديد، مما يمنع تعارض الإدخال.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| session_id | string | مطلوب | مُعرّف الجلسة المستلم من الاستدعاء الأولي لـ /v1/verify/send. |
| channel | string | اختياري | قناة إعادة الإرسال المستهدفة ("sms" | "whatsapp"). الافتراضي: "sms". |
- متاح في جميع الباقات بما فيها Starter: يتطلب /v1/verify/resend نفس صلاحية "verify" التي يتطلبها /v1/verify/send، لا أكثر.
- من أين يبدأ العد: تبدأ فترة الانتظار من آخر تسليم فعلي، لا من استدعائك — 60 ثانية بعد تسليم واتساب، و30 ثانية بعد رسالة SMS. يعيد GET /v1/verify/{session_id} العد التنازلي الجاري ("resend_available_in_seconds")، ويحمل ترويسة Retry-After في استجابة 429 عدد الثواني المتبقية بدقة. النافذة خاصة بحسابك وبالرقم: لا يعيقك أبداً نشاط عميل آخر نحو الرقم نفسه.
- مفاتيح الاختبار (env_test_): لا يُسلَّم شيء ولا يُحتسب شيء. تحمل الاستجابة عندئذٍ "sandbox": true و"sandbox_code"، حتى لا تُخلط إعادة إرسال محاكاة بأخرى مُسلَّمة فعلاً. لا يمكن لمفتاح اختبار إعادة إرسال إلا الجلسات التي أنشأها، ولا لمفتاح حي إلا الجلسات الحية.
curl -X POST "https://api.envoisms.ma/v1/verify/resend" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"session_id": "vrf_7e2a...",
"message_id": "wamid.HBgMMjEy...",
"to": "+212612345678",
"channel": "whatsapp",
"status": "sent",
"resend_after_seconds": 60,
"expires_at": "2026-05-15T10:35:00Z"
}التحقق من رمز OTP
يتحقق من صحة الرمز الذي أدخله المستخدم لجلسة تحقق معينة.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| session_id | string | مطلوب | مُعرّف الجلسة المستلم من استدعاء /v1/verify/send. |
| code | string | مطلوب | الرمز الذي استلمه المستخدم وأدخله. |
curl -X POST "https://api.envoisms.ma/v1/verify/check" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"session_id": "vrf_7e2a...",
"code": "849204"
}'{
"session_id": "vrf_7e2a...",
"verified": true,
"verified_at": "2026-05-15T10:35:12Z"
}حالة جلسة OTP
يعرض حالة جلسة تحقق محددة (تم التحقق أو منتهية الصلاحية).
curl -X GET "https://api.envoisms.ma/v1/verify/:id" \
-H "Authorization: Bearer smr_xxx"{
"id": "vrf_7e2a...",
"to": "+212612345678",
"channel": "whatsapp",
"expires_at": "2026-05-15T10:40:00Z",
"verified_at": "2026-05-15T10:35:12Z",
"created_at": "2026-05-15T10:30:00Z"
}التحقق من الرقم
يتحقق من صحة تنسيق رقم الهاتف ومشغّل الشبكة (carrier) ونوع الخط والموقع الجغرافي.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| number | string | مطلوب | رقم الهاتف المطلوب التحقق منه (بصيغة محلية أو دولية). |
| country_code | string | اختياري | رمز الدولة ISO المكون من حرفين (مثال: MA، FR). يُوصى به إذا كان الرقم بصيغة محلية. |
curl -X POST "https://api.envoisms.ma/v1/verify/lookup" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"number": "+212612345678",
"country_code": "MA"
}'{
"valid": true,
"number": "212612345678",
"local_format": "0612345678",
"international_format": "+212612345678",
"country_prefix": "212",
"country_code": "MA",
"country_name": "Morocco",
"location": "Casablanca",
"carrier": "Maroc Telecom (IAM)",
"line_type": "mobile"
}عرض المحادثات
يسترجع قائمة محادثات واتساب مع تتبع نافذة خدمة العملاء (24 ساعة) وحالة المساعد الآلي في الوقت الفعلي.
| المعلمة | النوع | الحالة | الوصف |
|---|---|---|---|
| limit | integer | اختياري | أقصى عدد للمحادثات المسترجعة (الافتراضي 30، الأقصى 100). |
| bot_status | string | اختياري | التصفية حسب حالة المساعد الآلي ("active" أو "muted"). |
curl -X GET "https://api.envoisms.ma/v1/conversations?limit=50&offset=0" \
-H "Authorization: Bearer smr_xxx"{
"conversations": [
{
"phone": "+212612345678",
"contact_name": "Yassine Alami",
"last_message": "Bonjour, je souhaite visiter l'appartement témoin",
"last_message_at": "2026-08-30T11:42:00Z",
"unread_count": 1,
"bot_muted": true,
"can_reply_free": true,
"window_expires_at": "2026-08-31T11:42:00Z"
}
],
"total": 1
}سجل محادثة محددة
يسترجع السجل الكامل للرسائل المتبادلة مع جهة اتصال معينة على واتساب.
curl -X GET "https://api.envoisms.ma/v1/conversations/:phone" \
-H "Authorization: Bearer smr_xxx"{
"phone": "+212612345678",
"contact_name": "Yassine Alami",
"bot_muted": true,
"messages": [
{
"id": "msg_01J...",
"direction": "inbound",
"body": "Je souhaite des informations sur le projet Casablanca Marina",
"type": "text",
"timestamp": "2026-08-30T11:40:00Z"
},
{
"id": "msg_02J...",
"direction": "outbound",
"body": "Bonjour Yassine ! Quel type de bien recherchez-vous ?",
"type": "interactive",
"timestamp": "2026-08-30T11:40:05Z"
}
]
}الرد المباشر في المحادثة
يرسل رد مستشار ويوقف المساعد الآلي في هذه المحادثة (إعادة التفعيل عبر POST /v1/conversations/:phone/toggle-bot). تتطلب رسالة واتساب الحرة أن يكون جهة الاتصال قد راسلك خلال آخر 24 ساعة (وإلا 400 OUT_OF_24H_WINDOW)؛ ويمكن إرسال نموذج معتمد في أي وقت.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| message | string | اختياري | نص الرد (أو شرح الوسائط المرفقة). إلزامي في غياب نموذج أو وسائط. |
| channel | string | اختياري | "whatsapp" (الافتراضي) أو "sms". |
| template_name | string | اختياري | نموذج واتساب معتمد يُرسَل بدل النص الحر (مع template_language وvariables). |
| media_url | string | اختياري | رابط https (أو data URI) لصورة أو ملف PDF للإرفاق؛ media_type هو "image" أو "document". |
| phone_number_id | string | اختياري | رقم واتساب المتصل الذي يرد. |
curl -X POST "https://api.envoisms.ma/v1/conversations/:phone/messages" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"ok": true,
"message": {
"id": "msg_03J...",
"phone": "212612345678",
"role": "agent",
"message": "Bonjour Yassine, votre visite est confirmée.",
"status": "sent",
"channel": "whatsapp",
"created_at": "2026-08-30T11:45:00Z"
}
}عرض العملاء المؤهلين
يسترجع العملاء المؤهلين تلقائياً عبر AtlasAI™ مع تقييم BANT وحالتهم في نظام إدارة العملاء.
| المعلمة | النوع | الحالة | الوصف |
|---|---|---|---|
| stage | string | اختياري | التصفية حسب المرحلة ("new"، "contacted"، "meeting_scheduled"، "closed_won"، "closed_lost"). |
| min_score | integer | اختياري | الحد الأدنى لتقييم BANT (0 إلى 100). |
- يتم تأهيل وتقييم العملاء المحتملين تلقائياً عبر محركات AtlasAI™ (Conversational Engine و Voice و Vision) مباشرة من رسائل واتساب الواردة. هذه المحركات مدمجة حصرياً في WABA ولا تتوفر كواجهات برمجية منفصلة.
curl -X GET "https://api.envoisms.ma/v1/qualified-leads?limit=50&offset=0" \
-H "Authorization: Bearer smr_xxx"{
"leads": [
{
"id": "lead_01J...",
"phone": "+212612345678",
"name": "Dr. Benjelloun",
"preset": "medical_equipment",
"bant_score": 85,
"is_hot": true,
"breakdown": {
"budget": 25,
"authority": 25,
"need": 20,
"timeline": 15
},
"intent": "Échographe Doppler pour nouveau cabinet",
"stage": "meeting_scheduled",
"created_at": "2026-08-30T09:15:00Z"
}
],
"total": 1
}تحديث حالة العميل المؤهل
يحدّث مرحلة العميل المؤهل في مسار المبيعات التجاري.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| status | string | مطلوب | "new" | "contacted" | "meeting_scheduled" | "closed_won" | "closed_lost" |
| notes | string | اختياري | ملاحظات المتابعة التجارية الداخلية. |
curl -X POST "https://api.envoisms.ma/v1/qualified-leads/:id/status" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"success": true,
"lead_id": "lead_01J...",
"stage": "meeting_scheduled"
}قائمة جهات الاتصال
يسترجع جميع جهات الاتصال في حسابك، مع إمكانية التصفية بكلمة مفتاحية أو حسب القائمة.
| المعلمة | النوع | الحالة | الوصف |
|---|---|---|---|
| limit | integer | اختياري | عدد النتائج لكل صفحة (1-500، الافتراضي: 100). |
| offset | integer | اختياري | إزاحة التقسيم على صفحات (الافتراضي: 0). |
| q | string | اختياري | البحث حسب الاسم أو الهاتف أو البريد الإلكتروني. |
| list_id | string | اختياري | التصفية لعرض أعضاء قائمة جهات اتصال محددة فقط. |
curl -X GET "https://api.envoisms.ma/v1/contacts?limit=50&offset=0" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "ctc_a2b3...",
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"custom1": "VIP",
"custom2": null,
"custom3": null,
"created_at": "2026-05-10T14:20:00Z"
}
],
"limit": 100,
"offset": 0,
"total": 1
}إنشاء / تعديل جهة اتصال
يضيف جهة اتصال أو يحدّث بيانات جهة اتصال موجودة (المطابقة عبر الرقم).
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| phone | string | مطلوب | رقم الهاتف بصيغة E.164. |
| name | string | اختياري | الاسم الكامل لجهة الاتصال. |
| string | اختياري | عنوان البريد الإلكتروني. | |
| list_id | string | اختياري | ربط جهة الاتصال فوراً بقائمة موجودة. |
| custom_fields | object | اختياري | كائن يحتوي على ما يصل إلى 3 حقول مخصصة ("custom1"، "custom2"، "custom3"). |
curl -X POST "https://api.envoisms.ma/v1/contacts" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"list_id": "lst_f84b..."
}'{
"id": "ctc_a2b3...",
"phone": "+212612345678",
"name": "Karim Bennani",
"email": "[email protected]",
"custom1": "VIP",
"custom2": null,
"custom3": null,
"created_at": "2026-05-10T14:20:00Z"
}استيراد جهات الاتصال
يستورد بشكل جماعي حتى 5,000 جهة اتصال في طلب واحد.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| contacts | array | مطلوب | مصفوفة من الكائنات تحتوي على "phone" و"name" (اختياري) و"email" (اختياري). |
| list_id | string | اختياري | مُعرّف القائمة التي سيتم استيراد المجموعة إليها. |
curl -X POST "https://api.envoisms.ma/v1/contacts/import" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{
"phone": "+212611111111",
"name": "Karim"
},
{
"phone": "+212622222222",
"name": "Youssef"
}
],
"list_id": "lst_f84b..."
}'{
"imported": 150,
"skipped": 3
}حذف جهة اتصال
يحذف جهة اتصال نهائياً باستخدام مُعرّفها الفريد.
curl -X DELETE "https://api.envoisms.ma/v1/contacts/:id" \
-H "Authorization: Bearer smr_xxx"{
"deleted": true,
"id": "ctc_a2b3..."
}عرض القوائم
يسترجع جميع قوائم جهات الاتصال المُنشأة لحملات البث.
curl -X GET "https://api.envoisms.ma/v1/contacts/lists" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "lst_f84b...",
"name": "Newsletter Clients",
"description": "Clients inscrits à notre lettre d'information",
"count": 1420,
"created_at": "2026-04-15T09:00:00Z"
}
]
}إنشاء قائمة
ينشئ مجموعة جديدة فارغة (قائمة جهات اتصال) مخصصة للحملات.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | مطلوب | اسم القائمة. |
| description | string | اختياري | وصف القائمة. |
curl -X POST "https://api.envoisms.ma/v1/contacts/lists" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Newsletter Clients",
"description": "Clients inscrits"
}'{
"id": "lst_f84b...",
"name": "Newsletter Clients",
"description": "Clients inscrits",
"count": 0
}قائمة إلغاءات الاشتراك
يسترجع قائمة الأرقام التي ألغت اشتراكها (STOP) في رسائلك.
curl -X GET "https://api.envoisms.ma/v1/optouts" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"phone": "+212611111111",
"opted_out_at": "2026-06-01T12:00:00Z"
}
],
"total": 1
}إضافة إلغاء اشتراك
يضيف رقماً يدوياً إلى قائمة إلغاء الاشتراك الخاصة بك (قائمة حظر شاملة).
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| phone | string | مطلوب | رقم الهاتف بصيغة E.164. |
curl -X POST "https://api.envoisms.ma/v1/optouts" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"success": true,
"phone": "+212611111111",
"opted_out_at": "2026-06-01T12:00:00Z"
}إزالة إلغاء اشتراك
يزيل رقماً من قائمة إلغاء الاشتراك.
curl -X DELETE "https://api.envoisms.ma/v1/optouts/:phone" \
-H "Authorization: Bearer smr_xxx"{
"deleted": true,
"phone": "+212611111111"
}قائمة أحداث الموافقة
سجل موافقات بالإضافة فقط (القانون 09-08، المادة 10): كل موافقة وكل سحب حدث مؤرَّخ بمصدره ودليله. تكتب المنصة بنفسها الكلمات المفتاحية STOP/START المستلمة على واتساب والرسائل القصيرة وأول محادثة يفتحها الزبون. أضف format=csv لتصدير المجموعة المصفاة كاملة.
| المعلمة | النوع | الحالة | الوصف |
|---|---|---|---|
| phone | string | اختياري | رقم E.164 للتصفية. |
| purpose | string | اختياري | marketing أو transactional أو otp أو service. |
| status | string | اختياري | granted أو withdrawn. |
| from | string | اختياري | الأحداث المسجلة ابتداءً من هذا التاريخ بصيغة ISO 8601. |
| format | string | اختياري | csv لتنزيل المجموعة الكاملة كملف. |
curl -X GET "https://api.envoisms.ma/v1/consents?limit=50&offset=0" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "cns_9f2a...",
"phone": "+212612345678",
"channel": "whatsapp",
"purpose": "marketing",
"status": "withdrawn",
"source": "whatsapp_keyword",
"evidence": { "keyword": "stop", "lang": "fr" },
"recorded_at": "2026-09-05T09:00:00.000Z",
"created_at": "2026-09-05T09:00:00.000Z"
}
],
"total": 1,
"limit": 100,
"offset": 0
}تسجيل حدث موافقة
يسجّل أن شخصاً منح موافقته أو سحبها، مع الدليل الذي بحوزتك (النص المعروض، الرابط، عنوان IP، المرجع). يمكن تأريخ recorded_at بأثر رجعي لموافقة مستوردة، لكن ليس في المستقبل. يوضع سحب التسويق فوراً في قائمة الاستبعاد.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| phone | string | مطلوب | رقم الهاتف بصيغة E.164. |
| purpose | string | مطلوب | marketing أو transactional أو otp أو service. |
| status | string | اختياري | granted (افتراضي) أو withdrawn. |
| channel | string | اختياري | whatsapp أو sms أو any (افتراضي). |
| source | string | اختياري | api (افتراضي) أو form أو import أو dashboard. مصادر الكلمات المفتاحية محجوزة للمنصة. |
| evidence | object | اختياري | كائن JSON حر (< 4 كيلوبايت): النص المعروض، الرابط، عنوان IP، المرجع. |
| recorded_at | string | اختياري | تاريخ ISO 8601 لفعل الشخص (افتراضياً: الآن). |
curl -X POST "https://api.envoisms.ma/v1/consents" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "cns_9f2a...",
"phone": "+212612345678",
"channel": "any",
"purpose": "marketing",
"status": "granted",
"source": "form",
"evidence": { "text": "J'accepte de recevoir les offres par WhatsApp", "url": "https://example.ma/inscription" },
"recorded_at": "2026-09-01T10:00:00.000Z",
"created_at": "2026-09-09T12:00:00.000Z"
}حالة الموافقة وسجلها لرقم
الجواب عن «أرني موافقة هذا الشخص»: الحالة الحالية لكل غرض (مشتقة من أحدث حدث، unknown بلا سجل، ولا تُفترض الموافقة أبداً)، ووجود الرقم في قائمة الاستبعاد، والسجل الكامل.
curl -X GET "https://api.envoisms.ma/v1/consents/:phone" \
-H "Authorization: Bearer smr_xxx"{
"phone": "+212612345678",
"opted_out": true,
"opted_out_at": "2026-09-05T09:00:00Z",
"state": {
"marketing": { "status": "withdrawn", "channel": "whatsapp", "source": "whatsapp_keyword", "recorded_at": "2026-09-05T09:00:00.000Z", "record_id": "cns_3" },
"transactional": { "status": "unknown" },
"otp": { "status": "unknown" },
"service": { "status": "granted", "channel": "whatsapp", "source": "whatsapp_inbound", "recorded_at": "2026-07-01T09:00:00.000Z", "record_id": "cns_1" }
},
"history": []
}قائمة الحملات
يسترجع جميع حملاتك المجدولة أو الجارية حالياً.
curl -X GET "https://api.envoisms.ma/v1/campaigns" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "cmp_8d2a...",
"name": "Soldes d'été 2026",
"channel": "sms",
"list_id": "lst_f84b...",
"template_id": null,
"body": "Bonjour {{name}}, profitez de -50% sur toute la collection avec le code ETE50 !",
"sender_id": "SOLDES",
"status": "draft",
"scheduled_at": null,
"created_at": "2026-06-01T12:00:00Z"
}
]
}إنشاء حملة
يسجّل حملة جديدة كمسودة أو يجدولها في تاريخ محدد.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | مطلوب | اسم الحملة. |
| body | string | مطلوب | نص الرسالة. يمكن استخدام المتغير {{name}}. (أحد الاثنين مطلوب: body أو template_id.) |
| template_id | string | مطلوب | بدلاً من ذلك، مُعرّف قالب معتمد. (أحد الاثنين مطلوب: body أو template_id.) |
| channel | string | اختياري | "sms" أو "whatsapp". القيمة الافتراضية "sms". |
| list_id | string | اختياري | مُعرّف قائمة جهات الاتصال المستهدفة. |
| sender_id | string | اختياري | اسم المرسل. |
| scheduled_at | string | اختياري | تاريخ الجدولة (ISO 8601). يغيّر الحالة إلى "scheduled". |
| buttons | array | اختياري | مصفوفة من أزرار واتساب التفاعلية (بحد أقصى 3، من النوع "copy" | "url" | "call"). |
| metadata | object | اختياري | بيانات وصفية مخصصة (مثال: خيارات وتيرة الإرسال / throttling: {"throttling": "50_min"}). |
curl -X POST "https://api.envoisms.ma/v1/campaigns" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Soldes d'été 2026",
"body": "Bonjour {{name}}, profitez de -50% avec le code ETE50 !",
"channel": "sms",
"list_id": "lst_f84b...",
"sender_id": "SOLDES"
}'{
"id": "cmp_8d2a...",
"status": "draft"
}تفاصيل الحملة
يسترجع تفاصيل الحملة وجدولتها وحالة تنفيذها.
curl -X GET "https://api.envoisms.ma/v1/campaigns/:id" \
-H "Authorization: Bearer smr_xxx"{
"id": "cmp_8d2a...",
"name": "Soldes d'été 2026",
"channel": "sms",
"list_id": "lst_f84b...",
"body": "Bonjour {{name}}, profitez de -50%...",
"sender_id": "SOLDES",
"status": "running",
"total_count": 1420,
"sent_count": 840,
"started_at": "2026-06-15T10:00:00Z",
"created_at": "2026-06-01T12:00:00Z"
}إطلاق حملة
يبدأ فوراً بث حملة في حالة مسودة إلى جميع جهات الاتصال المرتبطة بها.
curl -X POST "https://api.envoisms.ma/v1/campaigns/:id/send" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "cmp_8d2a...",
"queued": 1420,
"total": 1420
}قائمة Webhooks
يسترجع قائمة جميع نقاط نهاية Webhooks المسجلة لديك.
curl -X GET "https://api.envoisms.ma/v1/webhooks" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "whk_5f2b...",
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
],
"active": true,
"last_triggered_at": "2026-06-15T09:30:15Z",
"last_status": 200,
"created_at": "2026-05-01T10:00:00Z"
}
]
}إنشاء Webhook
يسجّل عنوان HTTPS للاستدعاء (callback) لاستلام إشعارات الأحداث.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| url | string | مطلوب | عنوان URL آمن يبدأ بـ "https://". |
| events | array | اختياري | مصفوفة من الأحداث (مثال: ["message.delivered", "message.failed"]). تُقبل أحرف البدل "message.*" و"*". الافتراضي: ["message.delivered", "message.failed"]. |
| secret | string | اختياري | مفتاح توقيع سري. إذا لم يُقدَّم، سيتم توليده تلقائياً. |
curl -X POST "https://api.envoisms.ma/v1/webhooks" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
]
}'{
"id": "whk_5f2b...",
"url": "https://mon-serveur.ma/api/envoisms-receiver",
"events": [
"message.delivered",
"message.failed"
],
"secret": "whsec_2f8a9e7d...",
"active": true
}تعديل Webhook
يحدّث إعدادات Webhook (العنوان أو الأحداث المشترك بها أو حالة التفعيل).
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| url | string | اختياري | عنوان HTTPS جديد. |
| events | array | اختياري | قائمة جديدة بالأحداث المشترك بها. |
| active | boolean | اختياري | تفعيل (true) أو تعطيل (false) الـ Webhook. |
curl -X PATCH "https://api.envoisms.ma/v1/webhooks/:id" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mon-serveur.ma/api/envoisms-receiver-updated",
"active": false
}'{
"updated": true,
"id": "whk_5f2b..."
}حذف Webhook
يعطّل نقطة نهاية Webhook ويحذفها منطقياً.
curl -X DELETE "https://api.envoisms.ma/v1/webhooks/:id" \
-H "Authorization: Bearer smr_xxx"{
"deleted": true,
"id": "whk_5f2b..."
}اختبار Webhook
يطلق حدث اختبار ("message.test") إلى العنوان المُهيّأ للـ Webhook.
curl -X POST "https://api.envoisms.ma/v1/webhooks/:id/test" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"queued": true,
"id": "whk_5f2b..."
}عرض روابط الويب هوك الواردة
يسترجع جميع نقاط التقاط بيانات الإعلانات المهيأة على حسابك.
curl -X GET "https://api.envoisms.ma/v1/inbound-webhooks" \
-H "Authorization: Bearer smr_xxx"{
"webhooks": [
{
"id": "inw_9a8b...",
"name": "Campagne TikTok Ads Casablanca",
"source": "tiktok_ads",
"catch_url": "https://api.envoisms.ma/v1/inbound-webhooks/catch/inw_9a8b...",
"auto_start_funnel": true,
"total_received": 142,
"created_at": "2026-08-20T14:00:00Z"
}
]
}إنشاء ويب هوك وارد جديد
ينشئ رابط التقاط لاستقبال بيانات العملاء فورياً من إعلانات TikTok وMeta Lead Ads وZapier أو Make.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | مطلوب | اسم وصفي للمصدر (مثال: "إعلانات فيسبوك لعروض الصيف"). |
| source | string | اختياري | معرّف المصدر ("tiktok_ads"، "meta_leads"، "google_forms"، "custom"). الافتراضي: "custom". |
| auto_start_funnel | boolean | اختياري | إذا كانت true، يبدأ فوراً مسار تأهيل واتساب عبر AtlasAI™ بمجرد استلام بيانات العميل. |
curl -X POST "https://api.envoisms.ma/v1/inbound-webhooks" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"id": "inw_9a8b...",
"name": "Campagne TikTok Ads Casablanca",
"catch_url": "https://api.envoisms.ma/v1/inbound-webhooks/catch/inw_9a8b...",
"auto_start_funnel": true
}الاطلاع على الرصيد
يعرض الرصيد المتاح بالدرهم المغربي (MAD) مع العملة والباقة النشطة.
curl -X GET "https://api.envoisms.ma/v1/billing/balance" \
-H "Authorization: Bearer smr_xxx"{
"balance_mad": 1492.5,
"currency": "MAD",
"plan": "croissance"
}حالة المدفوعات الآلية
يشير إلى ما إذا كانت المدفوعات الآلية (MPP / HTTP 402) مفعّلة على هذه النسخة. يمكن للوكيل الاستعلام عن هذه النقطة قبل محاولة أي طلب مدفوع.
- عندما تكون قيمة "enabled" false، يعيد أي طلب مدفوع 503 بدلاً من 402.
curl -X GET "https://api.envoisms.ma/v1/machine-payments/status" \
-H "Authorization: Bearer smr_xxx"{
"enabled": true,
"deposit_usd": 5.00,
"credit_mad": 49.65,
"networks": ["base", "tempo"],
"permissions": ["send", "status", "balance", "verify"]
}تحدي الدفع (HTTP 402)
يُعيد أي نقطة نهاية مدفوعة تُستدعى بدون مفتاح API استجابة 402 مع ترويسة WWW-Authenticate: Payment تحمل تحدياً موقّعاً وعنوان إيداع USDC. يودع الوكيل قيمة deposit_usd بالضبط USDC في أحد العناوين، ثم يعيد الطلب مع بيانات اعتماد Payment.
- حقل "request" هو JSON قانوني (RFC 8785) مُرمَّز بـ base64url بدون حشو. يحتوي على: amount وcurrency وnetworks[] وrecipients{} وpaymentIntent وresource وcredit{}.
- تقليص التكرار بالعنوان IP: إذا كان يوجد تحدٍّ نشط لنفس العنوان IP، يُعاد نفس التحدي بدلاً من إنشاء عنوان إيداع جديد.
- حد المعدل: 5 تحديات في الدقيقة لكل عنوان IP. بعد ذلك، يُعاد 402 بدون عنوان إيداع.
curl -X POST "https://api.envoisms.ma/v1/messages" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+212612345678",
"message": "Votre code de validation est 849204",
"from": "MaBoutique",
"channel": "whatsapp"
}'HTTP/1.1 402 Payment Required
WWW-Authenticate: Payment id="chal_01jxyz", realm="envoisms",
method="stripe", intent="session",
request="<base64url-JCS-encoded JSON>",
expires="2026-09-25T21:45:00.000Z",
description="EnvoiSMS pay-per-use API access."
{
"type": "https://paymentauth.org/problems/payment-required",
"title": "Payment Required",
"status": 402,
"detail": "Payment is required.",
"challengeId": "chal_01jxyz"
}استرداد بيانات اعتماد الدفع
بعد إيداع أموال USDC، يُعيد الوكيل محاولة النقطة المدفوعة الأصلية (مثل POST /v1/messages) مع استبدال Authorization: Bearer بـ Authorization: Payment <credential>. يتحقق الـ worker من إيداع Stripe من جهة الخادم، ويُضيف رصيداً إلى حساب الجهاز، ويُعيد مفتاح API محدود النطاق في ترويسة X-Machine-Session-Key.
- بيانات الاعتماد هي JSON قانونية base64url: {"challenge":{"id":"chal_01jxyz","method":"stripe","intent":"session"},"source":"<wallet-address>","payload":{}}.
- المفتاح المُعاد يُعرض مرة واحدة فقط. الطلب متكامل: إذا فقد الوكيل مفتاحه يمكنه الاتصال مجدداً — نفس الإيداع يُعيد مفتاحاً جديداً لنفس الحساب.
- يُعيد 402 إذا لم يصل إيداع Stripe بعد إلى حالة "succeeded". يجب على الوكيل انتظار التأكيد على السلسلة (عادةً 1-2 دقائق) قبل إعادة المحاولة.
curl -X POST "https://api.envoisms.ma/v1/messages (+ /v1/verify, /v1/waba)" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{}'{
"key": "smr_live_xxxxxxxxxxxxxxxxxxxx",
"permissions": ["send", "status", "balance", "verify"],
"credit_mad": 49.65,
"receipt": "<base64url-encoded receipt>",
"account": {
"id": "acct_01jxyz",
"plan": "starter",
"balance_mad": 49.65
}
}إحصائيات الاستخدام
يسترجع مقاييس أساسية حول إرسالياتك (الأحجام الإجمالية، معدل التسليم، والتكاليف المفوترة).
curl -X GET "https://api.envoisms.ma/v1/analytics" \
-H "Authorization: Bearer smr_xxx"{
"summary": {
"total": 12840,
"delivered": 12570,
"delivery_rate": 97.9,
"cost_mad": 2663.1
}
}قائمة مفاتيح API
يسترجع قائمة جميع مفاتيح API الخاصة بك، النشطة منها والملغاة.
curl -X GET "https://api.envoisms.ma/v1/api-keys" \
-H "Authorization: Bearer smr_xxx"{
"data": [
{
"id": "key_e84c...",
"name": "Production Server",
"key_prefix": "smr_a8f7d6c5",
"sandbox": false,
"ip_whitelist": [
"196.200.1.4"
],
"rate_limit": 100,
"permissions": [
"send",
"verify",
"status"
],
"active": true,
"last_used_at": "2026-06-15T10:30:00Z",
"created_at": "2026-05-01T08:00:00Z"
}
]
}إنشاء مفتاح API
يولّد رمز API آمناً جديداً بصلاحيات وقيود محددة.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | اختياري | تسمية لتمييز المفتاح (الافتراضي: "API key"). |
| permissions | array | اختياري | الصلاحيات الممنوحة (send, verify, status, balance, contacts, campaigns, webhooks, billing, analytics, api_keys, optouts, sender_id). |
| ip_whitelist | array | اختياري | قائمة عناوين IP المسموح لها بتنفيذ طلبات بهذا المفتاح. |
| rate_limit | integer | اختياري | الحد الأقصى للطلبات في الدقيقة (من 10 إلى 2000). الافتراضي حسب الباقة: Starter 60، Business 180، Pro 500، Enterprise 1200. |
| sandbox | boolean | اختياري | القيمة true تولّد مفتاح اختبار يبدأ بـ env_test_. تُتحقَّق الطلبات وتُسجَّل، لكن لا تُرسَل أي رسالة فعلياً ولا يُفوتَر شيء. وضع المفتاح نهائي: للتغيير، أنشئ مفتاحاً جديداً. |
curl -X POST "https://api.envoisms.ma/v1/api-keys" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Server",
"permissions": [
"send",
"verify",
"status"
],
"ip_whitelist": [
"196.200.1.4"
],
"rate_limit": 100
}'{
"id": "key_e84c...",
"name": "Production Server",
"key_prefix": "smr_a8f7d6c5",
"api_key": "smr_a8f7d6c5b4a3...",
"sandbox": false,
"permissions": [
"send",
"verify",
"status"
],
"rate_limit": 100,
"warning": "The full API key is shown once. Store it securely."
}تعديل مفتاح API
يحدّث صلاحيات مفتاح API أو قيود IP أو حالة تفعيله.
| الحقل | النوع | الحالة | الوصف |
|---|---|---|---|
| name | string | اختياري | اسم جديد. |
| permissions | array | اختياري | قائمة صلاحيات جديدة. |
| ip_whitelist | array | اختياري | قائمة جديدة بعناوين IP المسموح بها. |
| rate_limit | integer | اختياري | حد جديد لعدد الطلبات في الدقيقة. |
| active | boolean | اختياري | تفعيل المفتاح أو تعليقه. |
curl -X PATCH "https://api.envoisms.ma/v1/api-keys/:id" \
-H "Authorization: Bearer smr_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Backup Server",
"active": true
}'{
"updated": true,
"id": "key_e84c..."
}إلغاء مفتاح API
يلغي مفتاح API نهائياً لمنعه من مصادقة الطلبات.
curl -X DELETE "https://api.envoisms.ma/v1/api-keys/:id" \
-H "Authorization: Bearer smr_xxx"{
"revoked": true,
"id": "key_e84c..."
}دليل ويب هوكس
تأكيدات تسليم موقعة وآمنة.
يقوم EnvoiSMS.ma بإرسال أحداث JSON إلى عنوان HTTPS الخاص بخادمك مع ترويسة X-EnvoiSMS.ma-Signature للتحقق من المرسل.
message.sentتم قبول الرسالة من قبل شبكة المشغّل.
message.deliveredتم تسليم الرسالة بنجاح إلى المستلم (SMS أو واتساب).
message.readتم فتح وقراءة رسالة واتساب من قِبل المستلم (علامتا الصح الزرقاوان).
message.failedفشل التسليم في مرحلة التوجيه أو الإرسال (رفض أو خطأ في التوجيه).
message.undeliverableأكدت الشبكة تعذر تسليم الرسالة (رقم غير موجود، أو انتهت صلاحيتها في قائمة انتظار المشغّل).
message.fallbackالتسلسل (cascade: true): تنتقل الرسالة إلى القناة التالية (مثل واتساب ← SMS) لأن القناة الأولى رفضت الرسالة أو أبلغت بفشلها، أو لم ترسل إشعار تسليم خلال cascade_timeout. يحدد channel القناة الجديدة وprevious_channel القناة السابقة، ويبيّن error_code وerror_message السبب.
message.inboundردّ أحد المستلمين على إحدى رسائل SMS أو واتساب الخاصة بك (رسالة واردة).
message.flow_responseأكمل المستخدم وأرسل استمارة WhatsApp Flow الأصلية داخل المحادثة.
message.locationشارك المستخدم موقعه الجغرافي GPS على واتساب.
lead.qualifiedأكمل محرك AtlasAI™ تأهيل العميل المحتمل عبر واتساب بنجاح وفق معايير BANT.
contact.optoutألغى أحد المستلمين اشتراكه (بكلمة STOP أو ما يعادلها).
import crypto from 'node:crypto';
// La signature arrive dans le header X-EnvoiSMS-Signature
// (format "sha256=<hex>"), l'événement dans X-EnvoiSMS-Event.
// Corps livré : { "event": "...", "data": { ... }, "timestamp": "..." }
export function verifySignature(body: string, sig: string, secret: string) {
const hmac = crypto.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from('sha256=' + hmac));
} OpenAPI Spec الأخطاء
هيكل استجابات أخطاء واجهة البرمجة (API).
ترجع جميع أخطاء واجهة برمجة التطبيقات رمز استجابة HTTP مناسبًا (4xx أو 5xx) بالإضافة إلى ترويسة JSON متوقعة تحتوي على رمز الخطأ ووصفه.
{
"error": {
"code": "INVALID_PHONE",
"message": "to must be E.164 format, for example +212612345678",
"docs": "https://envoisms.ma/docs#errors"
}
}UNAUTHORIZEDمفتاح API مفقود أو غير صالح.
INSUFFICIENT_BALANCEالرصيد غير كافٍ لإتمام الإرسال.
INVALID_PHONEرقم الهاتف ليس بصيغة E.164.
WHATSAPP_NOT_CONNECTEDلا يوجد رقم واتساب للأعمال متصل: اربط رقمك في لوحة التحكم للإرسال عبر واتساب. للنص العادي احذف channel (SMS هو الافتراضي) — لم يُخصم أي مبلغ.
OUT_OF_24H_WINDOWرسالة واتساب حرة إلى جهة اتصال لم تراسلك خلال آخر 24 ساعة. أرسل نموذجاً معتمداً. لم يُخصم أي مبلغ.
WHATSAPP_ONLY_FIELDأُرسل حقل خاص بواتساب (reaction أو contacts أو location أو sticker أو context) على قناة أخرى.
CONFLICTING_MESSAGE_TYPESتحمل الرسالة نوع محتوى واحداً: لا تُجمع reaction أو contacts أو location أو sticker مع أي نوع آخر.
CASCADE_NOT_SUPPORTEDلا يمكن استخدام cascade مع تفاعل أو جهات اتصال أو موقع أو ملصق: لا يوجد مقابل عبر SMS.
INVALID_REACTIONيتطلب reaction معرّف الرسالة المستهدفة message_id (wamid) ورمزاً تعبيرياً واحداً (أو سلسلة فارغة لإزالة التفاعل).
INVALID_CONTEXTيتطلب context معرّف الرسالة المقتبسة message_id (wamid)، ولا يُجمع مع reaction.
INVALID_CONTACTSيجب أن يكون contacts مصفوفة من 1 إلى 20 بطاقة، لكل منها name.formatted_name؛ وتحدد الرسالة البطاقة الخاطئة.
INVALID_LOCATIONيتطلب location قيماً رقمية لـ latitude (من -90 إلى 90) وlongitude (من -180 إلى 180)؛ وname وaddress اختياريان.
INVALID_MEDIAتأخذ وسائط واتساب إما "id" أو "link" (رابط https) وليس الاثنين؛ ولا شرح للصوت والملصق.
META_WINDOW_EXPIREDفشل واتساب (131047): كانت نافذة الخدمة (24 ساعة) مغلقة. أرسل نموذجاً معتمداً أو رسالة SMS.
META_UNDELIVERABLEفشل واتساب (131026): الرقم غير قابل للوصول عبر واتساب. لا إعادة محاولة تلقائية.
META_MARKETING_LIMITفشل واتساب (131049): حد الرسائل التسويقية لكل مستلم. لا تُعد الإرسال فوراً.
META_RATE_LIMITEDفشل واتساب (130429 سعة الرقم، أو 131056 باسم META_PAIR_RATE_LIMITED: رسائل كثيرة لهذا الرقم) بعد 3 محاولات تلقائية.
META_POLICY_BLOCKEDفشل واتساب (368؛ وأيضاً META_ACCOUNT_LOCKED 131031 وMETA_PAYMENT_ISSUE 131042 وMETA_PHONE_NOT_REGISTERED 133010): الرقم أو الحساب المُرسِل مقيّد. تحقّق من WhatsApp Manager.
META_TEMPLATE_NOT_FOUNDفشل واتساب (132001؛ وأيضاً META_TEMPLATE_PARAM_MISMATCH 132000 وMETA_TEMPLATE_PARAM_FORMAT 132012): النموذج غير موجود بهذه اللغة أو المتغيرات غير صحيحة.
RATE_LIMITEDتم تجاوز حد الطلبات في الدقيقة. التزم بترويسة Retry-After.
INVALID_IDEMPOTENCY_KEYتتجاوز ترويسة Idempotency-Key حد 255 حرفاً.
IDEMPOTENCY_IN_FLIGHTالطلب الأصلي الذي يحمل مفتاح Idempotency-Key هذا لا يزال قيد التنفيذ. أعد المحاولة بعد لحظات.
IDEMPOTENCY_KEY_REUSEDاستُخدم مفتاح Idempotency-Key هذا من قبل مع نص طلب مختلف. استخدم مفتاحاً جديداً.
INVALID_CHANNELالقناة المطلوبة غير موجودة. القنوات الصالحة: sms, whatsapp, telegram, voice, rcs.
CHANNEL_NOT_CONFIGUREDالقناة المطلوبة غير متاحة حالياً على المنصة.
CHANNEL_DISABLEDالقناة المطلوبة معطّلة على المنصة.
FORBIDDENمفتاح API لا يملك الصلاحية المطلوبة لهذا الإجراء، أو الحساب معلّق.
SENDER_ID_TOO_LONGيتجاوز مُعرّف المرسل (Sender ID) حد 11 حرفاً.
SENDER_ID_INVALIDيحتوي مُعرّف المرسل (Sender ID) على أحرف غير مسموح بها.
SENDER_ID_NOT_APPROVEDلم يُعتمد مُعرّف المرسل (Sender ID) بعد من قبل مشغّلي الشبكات.
SENDER_ID_PENDINGمُعرّف المرسل (Sender ID) قيد الاعتماد.
SENDER_ID_REJECTEDرُفض مُعرّف المرسل (Sender ID) من قبل مشغّلي الشبكات.
SENDER_ID_GENERICمُعرّف المرسل عنوان عام (INFO، ALERT، SERVICE…) وليس علامة تجارية. استعمل اسم علامتك أو أزل sender_id.
SENDER_ID_PROTECTED_BRANDمُعرّف المرسل يشير إلى مؤسسة محمية أو يشبهها (بنك، مشغّل، إدارة). مخصّص للحسابات التي تمت الموافقة على تسجيلها لهذا الاسم.
SENDER_ID_NOT_REGISTEREDلم يُسجَّل مُعرّف المرسل على هذا الحساب ولا يوجد شحن مكتمل بعد: الإرسال مقصور على رقمك الموثّق.
TRIAL_RESTRICTED_DESTINATIONحساب في وضع التجربة المجانية: يقتصر إرسال الرسائل التجريبية على رقم هاتفك الموثّق فقط. قم بإجراء أول شحن للإرسال إلى أرقام أخرى.
MISSING_FIELDحقل إلزامي مفقود في الطلب.
CASCADE_TIMEOUTانتهت مهلة القناة الأولى، ويجري التحويل إلى القناة الثانوية (تسلسل).
UPSTREAM_ERRORخطأ في التسليم على مستوى المشغّل أو البوابة.
OPTED_OUTرفض هذا الرقم استقبال رسائلك (STOP). الإرسال ممنوع.
SPAM_OR_PHISHING_DETECTEDتحتوي الرسالة على رابط تصيّد، أو تتحدث باسم بنك أو مشغّل أو إدارة عمومية. رُفض الإرسال وعُلّق الحساب في انتظار المراجعة.
CONTENT_BLOCKEDحُظر محتوى الرسالة بواسطة نظام مكافحة إساءة الاستخدام وعُلّق الحساب في انتظار المراجعة. تواصل مع الدعم.
INVALID_CODEرمز OTP المُدخل غير صحيح. تشير رسالة الخطأ إلى عدد المحاولات المتبقية.
EXPIRED_CODEانتهت صلاحية رمز OTP. اطلب رمزاً جديداً عبر /v1/verify/send.
MAX_ATTEMPTSتم تجاوز الحد الأقصى لمحاولات التحقق. أُغلقت الجلسة.
STRIPE_ERRORتعذّر إنشاء صفحة الدفع من جانبنا. لم يُخصم أي مبلغ — أعد المحاولة بعد لحظات.
INTERNAL_ERRORخطأ داخلي من جانبنا. أعد المحاولة؛ وتواصل مع الدعم إذا استمرت المشكلة.
INVALID_PURPOSEيجب أن يكون purpose إحدى القيم: marketing أو transactional أو otp أو service.
INVALID_STATUSيجب أن يكون status إما granted أو withdrawn.
INVALID_CHANNELيجب أن يكون channel إحدى القيم: whatsapp أو sms أو any.
INVALID_SOURCEيجب أن يكون source إحدى القيم: api أو form أو import أو dashboard.
INVALID_EVIDENCEيجب أن يكون evidence كائن JSON أقل من 4 كيلوبايت.
INVALID_DATEتاريخ ليس بصيغة ISO 8601، أو recorded_at في المستقبل.
الحدود والقيود
الحدود والكوتا في بيئة الإنتاج.
من 60 إلى 1200 طلب / دقيقة لكل مفتاح حسب الباقة (Starter 60، Business 180، Pro 500، Enterprise 1200)، قابل للرفع عند الطلب.
1600 حرف كحد أقصى لكل رسالة.
حتى 10,000 رسالة لكل طلب API.
90 يوماً للتقارير المفصلة.