تتيح لك واجهة TurkeySMS API إرسال رسائل SMS ورموز OTP من تطبيقك، وجدولة الإرسال، وإدارة جهات الاتصال، والاستعلام عن الرصيد وأسماء المرسل، والحصول على تقارير الإرسال. تُرسل جميع الطلبات عبر HTTPS بطريقة POST، وتكون الاستجابات بصيغة JSON.
المعلومات في هذه الصفحة مبنية على سلوك الواجهة في النظام الحي. وتتبع الأقسام ترتيب مركز API في اللوحة.
| القسم | نقاط النهاية |
|---|---|
| فحص المفتاح | /auth/post/check/ |
| المراسلة | /sms/send, /group/send, /group/sendMixed, /otp/send, /otp/detailed |
| جهات الاتصال | /groups/create, /groups/edit, /groups/delete, /groups/list, /contacts/add, /blacklist/post/add, /blacklist/post/status |
| الاستعلامات والتقارير | /balance/, /senderid/check, /sms/status, /reports/basic, /reports/detailed |
| Webhook | تُرسل إشعارات الأحداث إلى خادمك |
TS-1030 في معظم نقاط النهاية).title اسم مرسل معتمداً في حسابك. يمكنك عرض أسماء المرسل المعتمدة عبر الاستعلام عن اسم المرسل.sms_lang بالقيمة 1.curl -X POST https://api.turkeysms.com.tr/sms/send \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX", "text": "Siparişiniz kargoya verildi.", "sms_lang": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'title' => 'BASLIGINIZ', 'sentto' => '905XXXXXXXXX', 'text' => 'Siparişiniz kargoya verildi.', 'sms_lang' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/sms/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX", "text": "Siparişiniz kargoya verildi.", "sms_lang": 1, } r = requests.post("https://api.turkeysms.com.tr/sms/send", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', title: 'BASLIGINIZ', sentto: '905XXXXXXXXX', text: 'Siparişiniz kargoya verildi.', sms_lang: 1, }; const r = await fetch('https://api.turkeysms.com.tr/sms/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
في الطلب الناجح تكون قيمة result هي true وقيمة result_code هي TS-1024. للتفاصيل انظر قسم إرسال SMS.
https://api.turkeysms.com.tr. تُضاف مسارات نقاط النهاية إلى هذا العنوان (مثل https://api.turkeysms.com.tr/sms/send). لا يحتوي العنوان على بادئة إصدار.POST فقط.Content-Type: application/json، UTF-8). تُقبل بيانات النماذج (form data) أيضاً، والأمثلة تستخدم JSON. لا تُقرأ سلسلة الاستعلام (query string)./balance/ و/auth/post/check/ بشرطة مائلة في النهاية، ويُكتب /senderid/check والبقية دونها. يؤدي المسار الخاطئ إلى إعادة توجيه (301) أو يعيد 404.أرسل مفتاح API في الحقل api_key داخل جسم كل طلب. المفتاح المرسل في ترويسة HTTP (مثل Authorization) لا يُقرأ.
تستخدم معظم نقاط النهاية الغلاف التالي. وفي الاستجابات الناجحة تُضاف الحقول الخاصة بنقطة النهاية إلى الكائن نفسه.
{ "result": false, "result_code": "TS-1031", "result_message": "Invalid API key. Authentication failed." }
تستخدم نقاط النهاية في التقارير وحظر الأرقام الحقل status ("success" أو "error") بدلاً من result.
result (أو status) وresult_code. نصوص result_message باللغة الإنجليزية وقد تتغير؛ اعتمد في برنامجك على result_code.عند خطأ غير متوقع في الخادم تكون الاستجابة عادةً HTTP 500 مع result_code بالقيمة SRV-ERR (TS-5000 في فحص المفتاح). ونادراً قد لا تكون الاستجابة بصيغة JSON، أو قد تحتوي الحقل error بدلاً من result_code؛ فالتقط في كودك أخطاء تحليل JSON أيضاً. يمكنك إعادة الطلب بعد مدة قصيرة؛ وفي نقاط نهاية الإرسال تحقق قبل الإعادة مما إذا كانت الرسالة قد أُرسلت، عبر الاستعلام عن حالة الرسالة أو التقارير.
قد يُطبَّق على /sms/send حد إرسال في الدقيقة على مستوى الحساب. تحدد TurkeySMS هذا الحد لحسابك. ويُحتسب الحد بعدد الرسائل (المستلمين) المسجلة من حسابك في الدقيقة الأخيرة، لا بعدد الطلبات. عند بلوغ الحد تكون الاستجابة HTTP 429 مع TS-1060؛ انتظر قليلاً ثم أعد المحاولة.
التواريخ بصيغة YYYY-MM-DD، والأوقات بصيغة HH:MM:SS (ساعة:دقيقة:ثانية) أو HH:MM في بعض الحقول. قيم التاريخ والوقت المعادة في الاستجابات لا تتضمن معلومات المنطقة الزمنية.
تُدار مفاتيح API من اللوحة في تبويب مركز API ← مفاتيحي. لكل مفتاح صلاحياته الخاصة؛ وننصحك بإنشاء مفاتيح منفصلة لأنظمتك المختلفة ومنح كل مفتاح الصلاحيات التي يحتاجها فقط.
تظهر المفاتيح في اللوحة بإحدى الحالات «نشط» أو «متوقف مؤقتاً» أو «منتهي» أو «ملغى». المفاتيح في حالة نشط وحدها يمكنها إجراء الطلبات؛ أما الطلبات بمفتاح يظهر في اللوحة بحالة أخرى فتُرفض مع TS-1031 أو TS-1035. وإذا ضُبط للمفتاح تاريخ انتهاء صلاحية، فإن الطلبات المرسلة بعد مرور التاريخ تُرفض مع TS-1035. يمكنك إعادة تفعيل المفتاح المتوقف مؤقتاً؛ أما المفتاح الملغى فلا يمكن استرجاعه.
في تفاصيل المفتاح، يُنشئ منطقة الخطر ← تجديد المفتاح (rotate) مفتاحاً جديداً، وتُنقل الصلاحيات والإعدادات إلى المفتاح الجديد. إذا فعّلت خيار «يبقى المفتاح القديم فعالاً 24 ساعة أخرى» يبقى المفتاح القديم صالحاً 24 ساعة إضافية، تنقل خلالها أنظمتك إلى المفتاح الجديد. وإذا لم تفعّل الخيار يصبح المفتاح القديم غير صالح فوراً. وبعد انتهاء المدة تُرفض الطلبات بالمفتاح القديم مع TS-1035 أو TS-1031. إذا تسرب المفتاح فلا تفعّل هذا الخيار.
تُفعَّل الصلاحيات وتُعطَّل من تبويب الصلاحيات في تفاصيل المفتاح. يبين الجدول التالي نقاط النهاية التي تُفحص فيها كل صلاحية والرمز المعاد عند تعطيلها. «السماح بطلبات POST» ليست طريقة إرسال، بل صلاحية مستقلة تُفحص في نقاط النهاية المذكورة فقط.
| الصلاحية (اللوحة) | نقاط النهاية | عند التعطيل |
|---|---|---|
| السماح بطلبات POST | /sms/send, /sms/status, /otp/detailed, /reports/basic, /reports/detailed | TS-1061 |
| إرسال SMS | /sms/send | TS-1062 |
| الإرسال للمجموعات | /group/send, /group/sendMixed | TS-1067 |
| إرسال OTP | /otp/send | TS-1036 |
| OTP متقدم | /otp/detailed | TS-1037 |
| إنشاء مجموعة | /groups/create | TS-1081 |
| تعديل المجموعة | /groups/edit | TS-1084 |
| حذف مجموعة | /groups/delete | TS-1085 |
| عرض المجموعات | /groups/list | TS-1089 |
| إضافة رقم | /contacts/add | TS-1065 |
| حظر رقم | /blacklist/post/add, /blacklist/post/status | TS-1065 |
| استعلام الرصيد | /balance/ | TS-1065 |
| استعلام حالة SMS | /sms/status, /reports/basic, /reports/detailed | TS-1063 |
| استعلام اسم المرسل | /senderid/check | TS-1038 |
لا تتطلب /auth/post/check/ أي صلاحية. ويمكنك عبرها الاستعلام عن صلاحيات أي مفتاح.
في خطوة «الحدود» في المعالج، وفي تبويبي «الحدود» و«الأمان» في تفاصيل المفتاح، يمكنك ضبط حدود الساعة واليوم والشهر، وقائمة السماح لعناوين IP، وتاريخ انتهاء الصلاحية لكل مفتاح. ولا تُطبَّق هذه القواعد إلا إذا ضُبطت في مركز API. الحد الفارغ أو الذي قيمته 0 يعني عدم وجود حد، والقائمة الفارغة تعني عدم وجود قيد على عناوين IP.
| القاعدة | متى يُرفض الطلب | الرمز (HTTP) |
|---|---|---|
| حد الساعة | عندما يبلغ عدد الطلبات بالمفتاح خلال الساعة الحالية (مثلاً 14:00–14:59) الحد المضبوط. | TS-1068 (429) |
| حد اليوم | عندما يبلغ عدد الطلبات بالمفتاح خلال اليوم الحالي الحد المضبوط. | TS-1069 (429) |
| حد الشهر | عندما يبلغ عدد الطلبات بالمفتاح خلال الشهر الميلادي الحالي الحد المضبوط. | TS-1073 (429) |
| قائمة السماح لعناوين IP | عندما لا يكون عنوان IP الذي جاء منه الطلب في القائمة. إذا كانت للمفتاح قائمة خاصة تُستخدم وحدها؛ وإلا تُستخدم قائمة الحساب. ويمكن أن تحتوي القائمة على عناوين IP مفردة أو نطاقات CIDR (مثل 203.0.113.0/24). | TS-1066 (403) |
| تاريخ انتهاء الصلاحية | بعد مرور التاريخ. يبقى المفتاح صالحاً حتى نهاية اليوم المحدد. | TS-1035 (403) |
TS-1060) الذي تحدده TurkeySMS لحسابك.تعيد ما إذا كان مفتاح API صالحاً، وصلاحياته، وملخص الحساب. يمكنك استخدامها للتحقق من الصلاحيات قبل تشغيل الربط في البيئة الحية.
الصلاحية المطلوبة: لا شيء. يكفي مفتاح API نشط.
/auth/post/check/. العنوان القديم /auth/check لا يُستخدم (404).| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. من 20 إلى 128 حرفاً. |
curl -X POST https://api.turkeysms.com.tr/auth/post/check/ \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', ]; $ch = curl_init('https://api.turkeysms.com.tr/auth/post/check/'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", } r = requests.post("https://api.turkeysms.com.tr/auth/post/check/", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', }; const r = await fetch('https://api.turkeysms.com.tr/auth/post/check/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1000", "result_message": "Authentication audit successful", "key_details": { "status": "Active", "permissions": { "post_request": true, "send_single_sms": true, "send_otp": true, "check_balance": true, "check_senderid": true, "manage_groups": false, "send_group_sms": true, "send_otp_advanced": false, "create_group": false, "edit_group": false, "delete_group": false, "list_groups": false, "add_contact": false, "delete_contact": false, "block_number": false, "check_sms_status": true } }, "account_summary": { "account_status": "Active", "balance": { "main": 1500, "international": 0 }, "global_sending": false }, "audit_info": { "request_ip": "203.0.113.10", "checked_at": "2026-10-01 14:30:00" } }
| الحقل | الوصف |
|---|---|
key_details.status | حالة المفتاح. لأن المفاتيح النشطة وحدها تتلقى استجابة، تكون القيمة Active في الاستجابة الناجحة. |
key_details.permissions | 16 حقلاً للصلاحيات (true/false). مقابلاتها في الجدول التالي. |
account_summary.account_status | حالة الحساب. تكون Active في الاستجابة الناجحة. |
account_summary.balance.main | رصيد رسائل SMS في حسابك (عدد صحيح). |
account_summary.balance.international, account_summary.global_sending | حقول إضافية. |
audit_info.request_ip | عنوان IP الذي ورد منه الطلب. |
audit_info.checked_at | تاريخ الفحص ووقته. |
مقابلات حقول الصلاحيات في اللوحة:
| الحقل | الصلاحية في اللوحة |
|---|---|
post_request | السماح بطلبات POST |
send_single_sms | إرسال SMS |
send_group_sms | الإرسال للمجموعات |
send_otp | إرسال OTP |
send_otp_advanced | OTP متقدم |
create_group | إنشاء مجموعة |
manage_groups | إنشاء مجموعة (اسم قديم؛ يحمل القيمة نفسها التي يحملها create_group، ويُبقى عليه للتوافق مع الإصدارات السابقة) |
edit_group | تعديل المجموعة |
delete_group | حذف مجموعة |
list_groups | عرض المجموعات |
add_contact | إضافة رقم |
delete_contact | لا مقابل له في اللوحة؛ ولا تستخدمه نقاط النهاية الموثقة في هذه الصفحة. |
block_number | حظر رقم |
check_balance | استعلام الرصيد |
check_sms_status | استعلام حالة SMS |
check_senderid | استعلام اسم المرسل |
{ "result": false, "result_code": "TS-1031", "result_message": "Invalid API key" }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1031 | 401 | api_key مفقود، أو ليس نصاً، أو طوله خارج المدى 20–128 حرفاً. |
| TS-1031 | 400 | لم يُعثر على المفتاح أو ليس في حالة «نشط». |
| TS-1030 | 400 | الحساب غير نشط. |
| TS-5000 | 500 | خطأ غير متوقع في الخادم. |
ترسل النص نفسه إلى رقم واحد أو أكثر. عند نجاح الطلب تُقبل الرسائل للمعالجة تمهيداً لتسليمها إلى المشغّل.
الصلاحيات المطلوبة: «السماح بطلبات POST» و«إرسال SMS» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| sentto | string | إلزامي | رقم المستلم. افصل بين الأرقام المتعددة بفاصلة أو فاصلة منقوطة أو سطر جديد. الحد الأقصى في الطلب الواحد 500 رقم مختلف (50000 في الإرسال المجدول). إذا تكرر الرقم يُرسل إليه مرة واحدة. |
| title | string | إلزامي | اسم مرسل معتمد في حسابك. 11 حرفاً كحد أقصى؛ ويُحتسب كل حرف تركي (ç, ğ, ı, ö, ş, ü) بحرفين. |
| text | string | إلزامي | نص الرسالة. 2000 حرف كحد أقصى. تتحول العبارة TS-L في النص إلى سطر جديد. |
| sms_lang | int | اختياري | مجموعة المحارف وطريقة احتساب عدد الرسائل: 0 الإنجليزية، 1 التركية، 2 العربية/Unicode. القيمة الافتراضية 2. للنصوص التركية أرسل 1 (انظر لغة الرسالة وعدد الرسائل). |
| content_type | int | اختياري | تصنيف المحتوى: 0 Transactional، 1 High Quality، 2 Advertising. القيمة الافتراضية 0. يُعاد في الاستجابة كتصنيف فقط، ولا يؤثر في الإرسال. |
| scheduled_date | string | اختياري | إذا أُرسل بقيمة غير فارغة يُجدول الإرسال. انظر الإرسال المجدول. |
| scheduled_time | string | مشروط | إلزامي عند إرسال scheduled_date. |
أرسل الأرقام بالصيغة الدولية دون + في البداية: 905XXXXXXXXX. تحذف الواجهة المسافات و+ و- والأقواس، وتحذف 00 من الأرقام التي تبدأ بـ 00، وتحوّل الأرقام 05… والأرقام المكونة من 10 خانات 5… إلى الصيغة 905…. لا يُتحقق من الأرقام واحداً واحداً؛ فالرقم الخاطئ يُقبل أيضاً ويُضاف إلى عدد الرسائل. تحقق من الأرقام في جهتك قبل الإرسال.
TS-1027).curl -X POST https://api.turkeysms.com.tr/sms/send \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX,905YYYYYYYYY", "text": "Randevunuz yarın 10:00'\''da.TS-LBilgi için bizi arayın.", "sms_lang": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'title' => 'BASLIGINIZ', 'sentto' => '905XXXXXXXXX,905YYYYYYYYY', 'text' => 'Randevunuz yarın 10:00\'da.TS-LBilgi için bizi arayın.', 'sms_lang' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/sms/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX,905YYYYYYYYY", "text": "Randevunuz yarın 10:00'da.TS-LBilgi için bizi arayın.", "sms_lang": 1, } r = requests.post("https://api.turkeysms.com.tr/sms/send", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', title: 'BASLIGINIZ', sentto: '905XXXXXXXXX,905YYYYYYYYY', text: 'Randevunuz yarın 10:00\'da.TS-LBilgi için bizi arayın.', sms_lang: 1, }; const r = await fetch('https://api.turkeysms.com.tr/sms/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1024", "result_message": "SMS dispatched successfully.", "sms_id": 48213377, "number_of_sms": 2, "total_recipients": 2, "success_count": 2, "sms_lang": "Turkish", "content_type": "Transactional", "country": "Turkey-TR" }
| الحقل | الوصف |
|---|---|
sms_id | معرّف رسالة آخر مستلم. في الإرسال إلى مستلم واحد يُستخدم مع الاستعلام عن حالة الرسالة. |
number_of_sms | العدد الإجمالي للرسائل لجميع المستلمين. |
total_recipients | عدد المستلمين بعد حذف المكرر. |
success_count | عدد المستلمين المقبولين للمعالجة. ليس عدد الرسائل المسلَّمة؛ لمعرفة حالة التسليم استخدم Webhook أو الاستعلام عن حالة الرسالة. |
sms_lang, content_type | تصنيف القيم التي أرسلتها. |
country | تصنيف بلد المستلم الأول (مثل Turkey-TR، وGlobalSMS-GL للأرقام الدولية). |
{ "result": false, "result_code": "TS-1027", "result_message": "Insufficient SMS credits. Please top up your account." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب ليس JSON صالحاً أو بيانات نموذج صالحة. |
| TS-1050 | 401 | api_key مفقود أو أقصر من 30 حرفاً. |
| TS-1025 | 400 | sentto مفقود، أو أقصر من 7 أحرف، أو لا يحتوي على رقم. |
| TS-1051 | 400 | title مفقود. |
| TS-1029 | 400 | title أطول من 11 حرفاً. |
| TS-1026 | 400 | text فارغ أو أطول من 2000 حرف. |
| TS-1060 | 400 | تجاوز حد عدد المستلمين: 500 (50000 في الإرسال المجدول). |
| TS-1070 / TS-1071 / TS-1072 | 400 | حقول الجدولة غير صالحة (انظر الإرسال المجدول). |
| TS-1031 | 401 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1061 | 403 | صلاحية «السماح بطلبات POST» معطلة. |
| TS-1062 | 403 | صلاحية «إرسال SMS» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| TS-1028 | 400 | اسم المرسل غير موجود في حسابك أو غير معتمد. |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| TS-1060 | 429 | تجاوز حد الإرسال في الدقيقة. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
sms.sent وsms.delivered وsms.failed. لمعرفة الـ Webhook الذي يتلقى الحدث انظر Webhook ← التوجيه.عند إضافة scheduled_date وscheduled_time إلى طلب /sms/send لا تُرسل الرسائل فوراً، بل توضع في قائمة الانتظار لتُرسل في الوقت المحدد.
الصلاحيات المطلوبة: «السماح بطلبات POST» و«إرسال SMS» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| scheduled_date | string | إلزامي | تاريخ الإرسال، YYYY-MM-DD (مثل 2026-10-15). |
| scheduled_time | string | إلزامي | وقت الإرسال، HH:MM أو HH:MM:ss (مثل 09:30). |
المعاملات الأخرى مماثلة لما في إرسال SMS.
curl -X POST https://api.turkeysms.com.tr/sms/send \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX", "text": "Kampanyamız yarın başlıyor.", "sms_lang": 1, "scheduled_date": "2026-10-15", "scheduled_time": "09:30" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'title' => 'BASLIGINIZ', 'sentto' => '905XXXXXXXXX', 'text' => 'Kampanyamız yarın başlıyor.', 'sms_lang' => 1, 'scheduled_date' => '2026-10-15', 'scheduled_time' => '09:30', ]; $ch = curl_init('https://api.turkeysms.com.tr/sms/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": "905XXXXXXXXX", "text": "Kampanyamız yarın başlıyor.", "sms_lang": 1, "scheduled_date": "2026-10-15", "scheduled_time": "09:30", } r = requests.post("https://api.turkeysms.com.tr/sms/send", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', title: 'BASLIGINIZ', sentto: '905XXXXXXXXX', text: 'Kampanyamız yarın başlıyor.', sms_lang: 1, scheduled_date: '2026-10-15', scheduled_time: '09:30', }; const r = await fetch('https://api.turkeysms.com.tr/sms/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1024", "result_message": "SMS dispatched successfully.", "sms_id": 734129955, "number_of_sms": 1, "total_recipients": 1, "success_count": 1, "sms_lang": "Turkish", "content_type": "Transactional", "country": "Turkey-TR" }
في الإرسال المجدول يكون sms_id هو معرّف التقرير للإرسال. استخدم هذه القيمة بصفة raporid في نقاط نهاية التقارير؛ أما الاستعلام عن حالة الرسالة فلا يتعرف على هذا المعرّف.
{ "result": false, "result_code": "TS-1072", "result_message": "Scheduled time must not be in the past." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1070 | 400 | scheduled_date ليس بصيغة YYYY-MM-DD أو scheduled_time مفقود. |
| TS-1071 | 400 | scheduled_time ليس بصيغة HH:MM أو HH:MM:ss. |
| TS-1072 | 400 | الوقت المحدد في الماضي أو غير صالح (مثل 25:99). |
| TS-1060 | 400 | تجاوز حد 50000 رقم. |
الرموز الأخرى مماثلة لما في إرسال SMS.
ترسل إلى عدد كبير من الأرقام بطلب واحد. توجد نقطتا نهاية:
/group/send: النص نفسه لجميع الأرقام./group/sendMixed: لكل رقم نص خاص به. يكون text مصفوفة يطابق ترتيبها مصفوفة الأرقام.الصلاحية المطلوبة: «الإرسال للمجموعات» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| title | string | إلزامي | اسم مرسل معتمد في حسابك. |
| sentto | array | إلزامي | مصفوفة أرقام (مصفوفة JSON؛ لا يُقبل نص مفصول بفواصل). 50000 عنصر كحد أقصى. يمكن إرسالها أيضاً باسم numbers. |
| text | string / array | إلزامي | /group/send: نص واحد. /group/sendMixed: مصفوفة نصوص بطول مصفوفة الأرقام نفسه؛ يذهب text[i] إلى الرقم sentto[i]. كل نص 2000 حرف كحد أقصى، وتتحول TS-L إلى سطر جديد. |
| sms_lang | int | اختياري | 0 الإنجليزية، 1 التركية، 2 العربية/Unicode. القيمة الافتراضية 2. للنصوص التركية أرسل 1. |
| scheduled_sms | int | اختياري | إذا أُرسلت القيمة 1 يُجدول الإرسال. |
| scheduled_date | string | مشروط | إلزامي إذا كانت scheduled_sms تساوي 1. YYYY-MM-DD. |
| scheduled_time | string | مشروط | إلزامي إذا كانت scheduled_sms تساوي 1. HH:MM أو HH:MM:ss. يُفسَّر التاريخ والوقت وفق توقيت تركيا (Europe/Istanbul). |
/sms/send: تُحذف المسافات و+ و- والأقواس، وتُحذف 00 من الأرقام التي تبدأ بها، وتُحوَّل الأرقام 05… والأرقام المكونة من 10 خانات 5… إلى الصيغة 905…. لا يُتحقق من الأرقام واحداً واحداً./group/send يوضع الرقم المكرر في قائمة الانتظار مرة واحدة. وفي طلب /group/sendMixed يوضع زوج الرقم والنص المتطابق مرة واحدة؛ أما النصوص المختلفة للرقم نفسه فتُرسل كلٌّ على حدة.TS-1027).scheduled_sms: 1.curl -X POST https://api.turkeysms.com.tr/group/send \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": [ "905XXXXXXXXX", "905YYYYYYYYY" ], "text": "Mağazamız bugün 21:00'\''e kadar açıktır.", "sms_lang": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'title' => 'BASLIGINIZ', 'sentto' => ['905XXXXXXXXX', '905YYYYYYYYY'], 'text' => 'Mağazamız bugün 21:00\'e kadar açıktır.', 'sms_lang' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/group/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": ["905XXXXXXXXX", "905YYYYYYYYY"], "text": "Mağazamız bugün 21:00'e kadar açıktır.", "sms_lang": 1, } r = requests.post("https://api.turkeysms.com.tr/group/send", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', title: 'BASLIGINIZ', sentto: ['905XXXXXXXXX', '905YYYYYYYYY'], text: 'Mağazamız bugün 21:00\'e kadar açıktır.', sms_lang: 1, }; const r = await fetch('https://api.turkeysms.com.tr/group/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
curl -X POST https://api.turkeysms.com.tr/group/sendMixed \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": [ "905XXXXXXXXX", "905YYYYYYYYY" ], "text": [ "Sayın Ayşe Hanım, siparişiniz hazır.", "Sayın Mehmet Bey, siparişiniz hazır." ], "sms_lang": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'title' => 'BASLIGINIZ', 'sentto' => ['905XXXXXXXXX', '905YYYYYYYYY'], 'text' => ['Sayın Ayşe Hanım, siparişiniz hazır.', 'Sayın Mehmet Bey, siparişiniz hazır.'], 'sms_lang' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/group/sendMixed'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "title": "BASLIGINIZ", "sentto": ["905XXXXXXXXX", "905YYYYYYYYY"], "text": ["Sayın Ayşe Hanım, siparişiniz hazır.", "Sayın Mehmet Bey, siparişiniz hazır."], "sms_lang": 1, } r = requests.post("https://api.turkeysms.com.tr/group/sendMixed", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', title: 'BASLIGINIZ', sentto: ['905XXXXXXXXX', '905YYYYYYYYY'], text: ['Sayın Ayşe Hanım, siparişiniz hazır.', 'Sayın Mehmet Bey, siparişiniz hazır.'], sms_lang: 1, }; const r = await fetch('https://api.turkeysms.com.tr/group/sendMixed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1024", "result_message": "Bulk SMS dispatched successfully.", "rapor_id": 482913377, "total_numbers": 2, "total_sms_cost": 2, "scheduled": false }
| الحقل | الوصف |
|---|---|
rapor_id | معرّف تقرير الإرسال. يُستخدم بصفة raporid في نقاط نهاية التقارير. |
total_numbers | عدد الأرقام الموضوعة في قائمة الانتظار بعد التحويل وحذف المكرر. |
total_sms_cost | العدد الإجمالي للرسائل. |
scheduled | true إذا جُدول الإرسال. |
{ "result": false, "result_code": "TS-1028", "result_message": "Sender ID was not found in your account or is not approved." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح، أو text فارغ، أو نوع text خاطئ، أو في /group/sendMixed عدد النصوص لا يساوي عدد الأرقام. |
| TS-1025 | 400 | api_key مفقود أو أقصر من 30 حرفاً. |
| TS-1029 | 400 | title مفقود. |
| TS-1026 | 400 | sentto مفقود أو ليس مصفوفة، أو أحد النصوص أطول من 2000 حرف. |
| TS-1060 | 400 | تجاوز حد 50000 رقم. |
| TS-1070 / TS-1071 / TS-1072 | 400 | حقول الجدولة غير صالحة: صيغة التاريخ أو صيغة الوقت أو وقت في الماضي. |
| TS-1031 | 403 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1067 | 403 | صلاحية «الإرسال للمجموعات» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| TS-1028 | 403 | اسم المرسل غير موجود في حسابك أو غير معتمد. |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
ترسل إلى رقم واحد رمز تحقق (OTP) تولّده TurkeySMS. يأتي النص من قالب جاهز، واسم المرسل يكون دائماً OTPSMS.
الصلاحية المطلوبة: «إرسال OTP» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| mobile | string | إلزامي | رقم مستلم واحد. أرسله بالصيغة 905XXXXXXXXX؛ وتُحوَّل الصيغ 05… و5… و00… أيضاً. |
| digits | int | اختياري | طول الرمز: 4 أو 5 أو 6. القيمة الافتراضية 4؛ ومع أي قيمة أخرى يُستخدم 4. |
| sms_lang | int | اختياري | لغة القالب: 0 الإنجليزية، 1 التركية، 2 العربية. القيمة الافتراضية 2. يمكن إرسالها أيضاً باسم lang؛ وإذا أُرسل الاثنان يُستخدم sms_lang. |
MARKA هو اسم علامة OTP المعرّف في حسابك. الرمز في المثال هو 4821.
4821 Aktivasyon kodunuz OTP MARKA
Your activation code is:4821 MARKA
4821 هو رمز التفعيل الخاص بك MARKA
curl -X POST https://api.turkeysms.com.tr/otp/send \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "mobile": "905XXXXXXXXX", "digits": 6, "sms_lang": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'mobile' => '905XXXXXXXXX', 'digits' => 6, 'sms_lang' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/otp/send'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "mobile": "905XXXXXXXXX", "digits": 6, "sms_lang": 1, } r = requests.post("https://api.turkeysms.com.tr/otp/send", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', mobile: '905XXXXXXXXX', digits: 6, sms_lang: 1, }; const r = await fetch('https://api.turkeysms.com.tr/otp/send', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1024", "result_message": "OTP dispatched successfully.", "sms_id": 48213390, "otp_code": 482193, "sandbox": false }
| الحقل | الوصف |
|---|---|
sms_id | معرّف الرسالة؛ يمكن استخدامه مع الاستعلام عن حالة الرسالة. |
otp_code | الرمز المرسل. يُعاد عدداً صحيحاً ولا يبدأ بـ 0. |
sandbox | false في الطلبات الحية. |
otp_code على خادمك بمدة صلاحية قصيرة (مثل 3–5 دقائق)، وقارنها بالرمز الذي يدخله المستخدم، واحذفها بعد الاستخدام. لا ترسل الرمز إلى جهة العميل (المتصفح أو تطبيق الجوال). وحدّد في جهتك عدد الطلبات المسموح بها للرقم نفسه خلال وقت قصير.{ "result": false, "result_code": "TS-1036", "result_message": "OTP sending privilege is disabled for this API key." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 401 | api_key مفقود أو أقصر من 30 حرفاً. |
| TS-1025 | 400 | mobile مفقود أو أقصر من 7 أحرف. |
| TS-1034 | 403 | صيغة الرقم غير صالحة (يجب أن يكون من 11 إلى 15 خانة بعد التنظيف). |
| TS-1031 | 403 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1036 | 403 | صلاحية «إرسال OTP» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| TS-5000 | 403 | تعذر حفظ الرسالة؛ أعد إرسال الطلب. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
ترسل OTP باسم المرسل الخاص بك وبنصك الخاص. تولّد TurkeySMS الرمز وتضعه مكان العبارة TS-CODE في النص.
الصلاحيات المطلوبة: «السماح بطلبات POST» و«OTP متقدم» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| mobile | string | إلزامي | رقم مستلم واحد، 905XXXXXXXXX. |
| title | string | إلزامي | اسم مرسل في حسابك. 11 حرفاً كحد أقصى؛ ويُحتسب كل حرف تركي بحرفين. يجب أن يكون اسم المرسل معتمداً، وأن تكون وثيقته معتمدة، وأن تكتمل موافقة المشغّل. |
| text | string | إلزامي | نص الرسالة؛ ويجب أن يحتوي على العبارة TS-CODE (بأحرف كبيرة). 2000 حرف كحد أقصى. تتحول TS-L إلى سطر جديد. |
| lang | int | اختياري | 0 الإنجليزية، 1 التركية، 2 العربية/Unicode. القيمة الافتراضية 2. لا تقرأ نقطة النهاية هذه sms_lang؛ استخدم lang. |
| digits | int | اختياري | طول الرمز: 4 أو 5 أو 6. القيمة الافتراضية 4. |
test، api، apikey، api_key، test123، 123، 0000، 123456789، senderid، sender، title، text، content.curl -X POST https://api.turkeysms.com.tr/otp/detailed \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "mobile": "905XXXXXXXXX", "title": "BASLIGINIZ", "text": "Giriş kodunuz: TS-CODE. Kodu kimseyle paylaşmayın.", "lang": 1, "digits": 6 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'mobile' => '905XXXXXXXXX', 'title' => 'BASLIGINIZ', 'text' => 'Giriş kodunuz: TS-CODE. Kodu kimseyle paylaşmayın.', 'lang' => 1, 'digits' => 6, ]; $ch = curl_init('https://api.turkeysms.com.tr/otp/detailed'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "mobile": "905XXXXXXXXX", "title": "BASLIGINIZ", "text": "Giriş kodunuz: TS-CODE. Kodu kimseyle paylaşmayın.", "lang": 1, "digits": 6, } r = requests.post("https://api.turkeysms.com.tr/otp/detailed", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', mobile: '905XXXXXXXXX', title: 'BASLIGINIZ', text: 'Giriş kodunuz: TS-CODE. Kodu kimseyle paylaşmayın.', lang: 1, digits: 6, }; const r = await fetch('https://api.turkeysms.com.tr/otp/detailed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1024", "result_message": "OTP dispatched successfully.", "sms_id": 48213391, "otp_code": 482193, "number_of_sms": 1, "sms_lang": "Turkish", "sandbox": false }
| الحقل | الوصف |
|---|---|
sms_id | معرّف الرسالة. |
otp_code | الرمز المرسل. يُعاد عدداً صحيحاً ولا يبدأ بـ 0. |
number_of_sms | عدد رسائل SMS المحتسبة لهذه الرسالة. |
sms_lang | تصنيف قيمة lang. |
sandbox | false في الطلبات الحية. |
TS-1024. يمكنك التحقق من حالة الرسالة عبر الاستعلام عن حالة الرسالة؛ وعند خطأ التسليم تُعاد TS-1022 مع وصف الخطأ في الحقل details. وينطبق هنا أيضاً التنبيه الوارد في قسم إرسال OTP بشأن التحقق من الرمز.{ "result": false, "result_code": "TS-1028", "result_message": "Sender ID is not approved for OTP (approval, document and network approval are required)." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح، أو أحد الحقول ليس نصاً، أو اسم المرسل ضمن قائمة الأسماء غير المقبولة. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1025 | 400 | mobile مفقود. |
| TS-1051 | 400 | title مفقود. |
| TS-1026 | 400 | text فارغ، أو لا يحتوي على TS-CODE، أو أطول من 2000 حرف. |
| TS-1031 | 400 403 | 400: المفتاح أقصر من 30 حرفاً. 403: لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1034 | 400 | صيغة الرقم غير صالحة. |
| TS-1029 | 400 403 | 400: اسم المرسل أطول من 11 حرفاً. 403: اسم المرسل غير موجود في حسابك. |
| TS-1061 | 403 | صلاحية «السماح بطلبات POST» معطلة. |
| TS-1037 | 403 | صلاحية «OTP متقدم» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| TS-1028 | 403 | اسم المرسل غير معتمد لرسائل OTP (الاعتماد أو الوثيقة أو موافقة المشغّل ناقصة). |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| TS-5000 | 403 | تعذر حفظ الرسالة؛ أعد إرسال الطلب. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
يحدد sms_lang (lang في OTP المتقدم) مجموعة محارف الرسالة وعدد الرسائل التي تُحتسب لها. القيمة الخاطئة قد تؤدي إلى تقسيم النص على عدد أكبر من الرسائل.
| القيمة | الاستخدام |
|---|---|
0 | الإنجليزية؛ أحرف لاتينية ورموز قياسية فقط (دون أحرف تركية). |
1 | التركية؛ النصوص التي تحتوي على ç, ğ, ı, İ, ö, ş, ü. |
2 | العربية ونصوص Unicode الأخرى. وهي القيمة الافتراضية. |
الأرقام في الجدول هي أكبر عدد من الأحرف يتسع له عدد الرسائل المذكور. ويُحتسب عدد الأحرف بعد تحويل TS-L إلى سطر جديد.
| طول النص حتى | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
أرقام تركيا، sms_lang 0 | 160 | 305 | 455 | 610 | 760 | 910 | 1070 |
أرقام تركيا، sms_lang 1 | 155 | 245 | 445 | 595 | 740 | 890 | 1040 |
أرقام تركيا، sms_lang 2 | 65 | 127 | 190 | 250 | 315 | 380 | 445 |
| الأرقام الدولية (جميع القيم) | 70 | 130 | 195 | 260 | 325 | 390 | 450 |
/sms/send و/otp/detailed الأرقام التي لا تبدأ بـ 905 أرقاماً دولية. أما /group/send و/group/sendMixed فتستخدمان جدول تركيا لجميع الأرقام.القيمة content_type في طلب /sms/send (0 Transactional، 1 High Quality، 2 Advertising) تُعاد في الاستجابة كتصنيف فقط؛ ولا تغيّر مسار الإرسال ولا السعر.
تنشئ المجموعات في جهات الاتصال وتعيد تسميتها وتحذفها وتعرضها. لكل عملية صلاحية مستقلة.
TS-1082 وTS-1086). قيّم النتيجة دائماً عبر result وresult_code.الصلاحية المطلوبة: «إنشاء مجموعة» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| group_name | string | إلزامي | اسم المجموعة. من 2 إلى 50 حرفاً؛ ويُحتسب كل حرف تركي بحرفين. يجب أن يكون فريداً بين مجموعاتك النشطة. |
curl -X POST https://api.turkeysms.com.tr/groups/create \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "group_name": "Müşteriler" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'group_name' => 'Müşteriler', ]; $ch = curl_init('https://api.turkeysms.com.tr/groups/create'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "group_name": "Müşteriler", } r = requests.post("https://api.turkeysms.com.tr/groups/create", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', group_name: 'Müşteriler', }; const r = await fetch('https://api.turkeysms.com.tr/groups/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1080", "result_message": "Group created successfully.", "group": { "id": 5412, "name": "Müşteriler", "created_at": "2026-10-01" } }
استخدم قيمة group.id بصفة group_id عند إضافة الأرقام.
الصلاحية المطلوبة: «تعديل المجموعة» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| group_id | int | إلزامي | معرّف المجموعة. |
| new_name | string | إلزامي | الاسم الجديد. لا تتحقق نقطة النهاية هذه من الطول ولا من التفرد؛ وننصحك بإبقاء الاسم بين 2 و50 حرفاً وفريداً. |
curl -X POST https://api.turkeysms.com.tr/groups/edit \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "group_id": 5412, "new_name": "VIP Müşteriler" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'group_id' => 5412, 'new_name' => 'VIP Müşteriler', ]; $ch = curl_init('https://api.turkeysms.com.tr/groups/edit'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "group_id": 5412, "new_name": "VIP Müşteriler", } r = requests.post("https://api.turkeysms.com.tr/groups/edit", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', group_id: 5412, new_name: 'VIP Müşteriler', }; const r = await fetch('https://api.turkeysms.com.tr/groups/edit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1087", "result_message": "Group name updated successfully.", "new_name": "VIP Müşteriler" }
الصلاحية المطلوبة: «حذف مجموعة» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| group_id | int | إلزامي | معرّف المجموعة. |
تُزال المجموعة المحذوفة من القوائم ولا يمكن استخدامها مجدداً. ولا تُحذف الأرقام المضافة إليها.
curl -X POST https://api.turkeysms.com.tr/groups/delete \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "group_id": 5412 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'group_id' => 5412, ]; $ch = curl_init('https://api.turkeysms.com.tr/groups/delete'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "group_id": 5412, } r = requests.post("https://api.turkeysms.com.tr/groups/delete", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', group_id: 5412, }; const r = await fetch('https://api.turkeysms.com.tr/groups/delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1088", "result_message": "Group deleted successfully." }
الصلاحية المطلوبة: «عرض المجموعات» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| search | string | اختياري | البحث داخل الاسم. إذا كان فارغاً تُعاد جميع المجموعات. |
curl -X POST https://api.turkeysms.com.tr/groups/list \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "search": "Müşteri" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'search' => 'Müşteri', ]; $ch = curl_init('https://api.turkeysms.com.tr/groups/list'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "search": "Müşteri", } r = requests.post("https://api.turkeysms.com.tr/groups/list", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', search: 'Müşteri', }; const r = await fetch('https://api.turkeysms.com.tr/groups/list', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1090", "result_message": "Group list retrieved successfully.", "groups_count": 2, "groups": [ { "id": 5413, "name": "VIP Müşteriler", "date": "2026-10-01" }, { "id": 5398, "name": "Müşteriler 2025", "date": "2026-04-02" } ] }
تُعاد المجموعات غير المحذوفة فقط، من الأحدث إلى الأقدم. ولا يوجد تقسيم إلى صفحات.
{ "result": false, "result_code": "TS-1082", "result_message": "Group name already exists." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1080 / TS-1087 / TS-1088 / TS-1090 | 200 | أُنشئت / حُدّثت / حُذفت / عُرضت. |
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1031 | 400 | المفتاح أقصر من 30 حرفاً، أو لم يُعثر عليه، أو غير نشط. |
| TS-1081 / TS-1084 / TS-1085 / TS-1089 | 400 | الصلاحية المعنية معطلة: إنشاء / تعديل / حذف / عرض. |
| TS-1030 | 400 | الحساب غير نشط. |
| TS-1082 | 200 | توجد مجموعة نشطة بهذا الاسم. |
| TS-1083 | 400 200 | اسم المجموعة فارغ أو خارج المدى 2–50 حرفاً. وفي التعديل يُعاد أيضاً مع 200 عند group_id غير صالح. |
| TS-1086 | 400 200 | 400: group_id مفقود. 200: لم يُعثر على المجموعة، أو لا تخصك، أو محذوفة. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
تضيف رقماً إلى مجموعة. يُحفظ الرقم في جهات الاتصال مع الاسم وثلاثة حقول إضافية.
الصلاحية المطلوبة: «إضافة رقم» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| group_id | int | إلزامي | معرّف المجموعة التي يُضاف إليها الرقم (انظر المجموعات). |
| gsm_number | string | إلزامي | رقم جوال تركي. تُقبل الصيغ 905XXXXXXXXX و05XXXXXXXXX و5XXXXXXXXX و+905… و00905…؛ ويُحفظ بالصيغة 905XXXXXXXXX. |
| name | string | اختياري | اسم جهة الاتصال. |
| f_01, f_02, f_03 | string | اختياري | حقول إضافية؛ نص حر للتخصيص. |
curl -X POST https://api.turkeysms.com.tr/contacts/add \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "group_id": 5412, "gsm_number": "905XXXXXXXXX", "name": "Ayşe Yılmaz", "f_01": "İstanbul" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'group_id' => 5412, 'gsm_number' => '905XXXXXXXXX', 'name' => 'Ayşe Yılmaz', 'f_01' => 'İstanbul', ]; $ch = curl_init('https://api.turkeysms.com.tr/contacts/add'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "group_id": 5412, "gsm_number": "905XXXXXXXXX", "name": "Ayşe Yılmaz", "f_01": "İstanbul", } r = requests.post("https://api.turkeysms.com.tr/contacts/add", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', group_id: 5412, gsm_number: '905XXXXXXXXX', name: 'Ayşe Yılmaz', f_01: 'İstanbul', }; const r = await fetch('https://api.turkeysms.com.tr/contacts/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1100", "result_message": "Contact added successfully.", "group_id": 5412, "total_sent": 1, "total_added": 1, "total_failed": 0, "mobile": "905XXXXXXXXX" }
mobile هو الرقم المحفوظ. أما total_sent وtotal_added وtotal_failed فهي ملخص هذه العملية ذات الرقم الواحد.
{ "result": false, "result_code": "TS-1101", "result_message": "Failed to add contact." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1025 | 400 | gsm_number مفقود. |
| TS-1086 | 400 200 | 400: group_id مفقود، أو لم يُعثر على المجموعة، أو لا تخصك. 200: group_id ليس عدداً أو ليس أكبر من صفر. |
| TS-1031 | 400 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1065 | 400 | صلاحية «إضافة رقم» معطلة. |
| TS-1030 | 400 | الحساب غير نشط. |
| TS-1101 | 200 | الرقم ليس رقم جوال تركياً صالحاً. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
تضيف أرقاماً إلى قائمة حظر الأرقام، وتستعلم عمّا إذا كان رقم ما موجوداً في القائمة. القائمة على مستوى الحساب.
/sms/send و/otp/* و/group/*؛ إذا كنت ترسل عبر API فاستبعد الأرقام المحظورة في جهتك.الصلاحية المطلوبة: «حظر رقم» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
الصلاحية مطلوبة لنقطتي النهاية كلتيهما. العنوانان القديمان /blacklist/add و/blacklist/status لا يُستخدمان (404).
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| number | string | إلزامي | رقم جوال تركي. تُقبل الصيغ 905XXXXXXXXX و+90 5XX… و0090 5XX… و05XX… و5XX…، وتُحوَّل إلى الصيغة 905XXXXXXXXX. |
905XXXXXXXXX بالقاعدة نفسها المستخدمة في اللوحة. وعند الإضافة والاستعلام تُقارن آخر 10 خانات من الرقم، لذلك يُعدّ 05321234567 و905321234567 رقماً واحداً. ولا تُقبل الأرقام الأرضية ولا الأرقام الأجنبية (TS-1144).فرق في صيغة الاستجابة: تستخدم نقطتا النهاية هاتان الحقل status ("success" أو "error") بدلاً من result.
curl -X POST https://api.turkeysms.com.tr/blacklist/post/add \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "number": "905XXXXXXXXX" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'number' => '905XXXXXXXXX', ]; $ch = curl_init('https://api.turkeysms.com.tr/blacklist/post/add'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['status'] ?? '') === 'success') { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "number": "905XXXXXXXXX", } r = requests.post("https://api.turkeysms.com.tr/blacklist/post/add", json=payload, timeout=30) data = r.json() if data.get("status") == "success": print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', number: '905XXXXXXXXX', }; const r = await fetch('https://api.turkeysms.com.tr/blacklist/post/add', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.status === 'success') { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "status": "success", "result_code": "TS-1141", "result_message": "Number added to blacklist successfully" }
curl -X POST https://api.turkeysms.com.tr/blacklist/post/status \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "number": "905XXXXXXXXX" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'number' => '905XXXXXXXXX', ]; $ch = curl_init('https://api.turkeysms.com.tr/blacklist/post/status'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['status'] ?? '') === 'success') { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "number": "905XXXXXXXXX", } r = requests.post("https://api.turkeysms.com.tr/blacklist/post/status", json=payload, timeout=30) data = r.json() if data.get("status") == "success": print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', number: '905XXXXXXXXX', }; const r = await fetch('https://api.turkeysms.com.tr/blacklist/post/status', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.status === 'success') { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "status": "success", "result_code": "TS-1143", "result_message": "The phone number is currently in the blacklist.", "is_blocked": true, "block_date": "2026-10-01", "block_time": "14:30" }
{ "status": "success", "result_code": "TS-1142", "result_message": "The phone number is NOT in the blacklist.", "is_blocked": false }
block_date وblock_time هما تاريخ إضافة الرقم إلى القائمة ووقتها. لعرض القائمة وإزالة الأرقام استخدم صفحة حجب الأرقام في اللوحة؛ فلا توجد في API نقطة نهاية للإزالة.
{ "status": "error", "result_code": "TS-1065", "result_message": "Number blocking privilege is disabled for this API key." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1141 | 200 | أُضيف الرقم إلى القائمة. |
| TS-1143 / TS-1142 | 200 | الرقم في القائمة / ليس في القائمة. |
| TS-1050 | 403 | api_key مفقود أو جسم الطلب غير صالح. |
| TS-1031 | 401 | المفتاح أقصر من 20 حرفاً، أو لم يُعثر عليه، أو غير نشط، أو الحساب غير نشط. |
| TS-1025 | 400 | number مفقود. |
| TS-1144 | 400 | الرقم ليس رقم جوال تركياً صالحاً. |
| TS-1065 | 403 | صلاحية «حظر رقم» معطلة. |
| TS-1140 | 400 | الرقم موجود في قائمتك مسبقاً. |
| TS-1033 | 400 | حدث خطأ أثناء الحفظ؛ أعد المحاولة. |
| TS-404 | 404 | المسار خاطئ. |
تعيد رصيد رسائل SMS في حسابك.
الصلاحية المطلوبة: «استعلام الرصيد» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
/balance/. يؤدي العنوان دون الشرطة إلى إعادة توجيه (301)؛ وبعض مكتبات عميل HTTP تحوّل طلب POST إلى GET عند إعادة التوجيه فيفشل الطلب.| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
curl -X POST https://api.turkeysms.com.tr/balance/ \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', ]; $ch = curl_init('https://api.turkeysms.com.tr/balance/'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", } r = requests.post("https://api.turkeysms.com.tr/balance/", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', }; const r = await fetch('https://api.turkeysms.com.tr/balance/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1040", "result_message": "Balance retrieved successfully.", "balance_main": 1500 }
balance_main: رصيد رسائل SMS (عدد صحيح).
{ "result": false, "result_code": "TS-1065", "result_message": "Balance inquiry privilege is disabled for this key." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1025 | 400 | api_key أقصر من 30 حرفاً. |
| TS-1031 | 403 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1065 | 403 | صلاحية «استعلام الرصيد» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| SRV-ERR | 403 500 | خطأ غير متوقع في الخادم. |
تعرض أسماء المرسل المعتمدة في حسابك. في الإرسال اكتب في الحقل title اسماً من هذه القائمة.
الصلاحية المطلوبة: «استعلام اسم المرسل» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
curl -X POST https://api.turkeysms.com.tr/senderid/check \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ" }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', ]; $ch = curl_init('https://api.turkeysms.com.tr/senderid/check'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", } r = requests.post("https://api.turkeysms.com.tr/senderid/check", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', }; const r = await fetch('https://api.turkeysms.com.tr/senderid/check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1040", "result_message": "Operation success.", "sender_ids_count": 2, "sender_ids": [ { "id": 1288, "title": "BASLIGINIZ", "status": 1, "network_stat": 1 }, { "id": 1102, "title": "MAGAZA", "status": 1, "network_stat": 1 } ] }
| الحقل | الوصف |
|---|---|
sender_ids_count | عدد أسماء المرسل في القائمة. |
sender_ids[].id | معرّف سجل اسم المرسل. |
sender_ids[].title | اسم المرسل؛ يُستخدم بصفة title في الإرسال. |
sender_ids[].status | دائماً 1، لأن الأسماء المعتمدة وحدها تُعرض. |
sender_ids[].network_stat | قيمه غير معرّفة بعد؛ لا تستخدمه في الربط. |
تبدأ القائمة بأحدث اسم مرسل. الأسماء التي تنتظر الاعتماد أو المرفوضة لا تُعرض؛ وإذا لم يوجد اسم معتمد يكون sender_ids مصفوفة فارغة.
{ "result": false, "result_code": "TS-1038", "result_message": "Sender ID inquiry privilege is disabled for this key." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1031 | 400 403 | 400: المفتاح أقصر من 30 حرفاً. 403: لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1038 | 403 | صلاحية «استعلام اسم المرسل» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| SRV-ERR | 403 500 | خطأ غير متوقع في الخادم. |
تعيد حالة تسليم رسالة واحدة. لا يمكن الاستعلام إلا عن الرسائل المرسلة من حسابك.
الصلاحيات المطلوبة: «السماح بطلبات POST» و«استعلام حالة SMS» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| sms_id | int | إلزامي | معرّف الرسالة: قيمة sms_id في استجابة /sms/send الفوري (مستلم واحد) أو /otp/send أو /otp/detailed. |
curl -X POST https://api.turkeysms.com.tr/sms/status \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "sms_id": 48213377 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'sms_id' => 48213377, ]; $ch = curl_init('https://api.turkeysms.com.tr/sms/status'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['result'] ?? false) === true) { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "sms_id": 48213377, } r = requests.post("https://api.turkeysms.com.tr/sms/status", json=payload, timeout=30) data = r.json() if data.get("result") is True: print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', sms_id: 48213377, }; const r = await fetch('https://api.turkeysms.com.tr/sms/status', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.result === true) { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "result": true, "result_code": "TS-1064", "result_message": "Number received the message.", "sender_id": "BASLIGINIZ", "date_of_sending": "2026-10-01", "time_of_sending": "14:27:12", "sms_status": "Number received the message", "sms_balance": "1 SMS", "details": "OK", "operator": "Turkcell" }
| الحقل | الوصف |
|---|---|
result_code | TS-1064: سُلّمت الرسالة. TS-1022: لا يوجد تأكيد تسليم (لم تُسلَّم الرسالة أو لم يصل تقرير التسليم بعد). كلاهما يُعاد مع result: true وHTTP 200. |
sms_status | Number received the message أو The number did not receive the message. |
sender_id | اسم المرسل الذي أُرسلت به الرسالة. |
date_of_sending, time_of_sending | تاريخ تسجيل الرسالة ووقته. |
sms_balance | عدد رسائل SMS المحتسبة لهذه الرسالة (ليس رصيد الحساب). |
details | نتيجة العملية؛ وعند خطأ التسليم وصف الخطأ. |
operator | مشغّل المستلم؛ وقد يكون فارغاً إذا لم تتوفر المعلومة. |
{ "result": false, "result_code": "TS-1020", "result_message": "The data sent is incorrect." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1033 | 400 | جسم الطلب غير صالح. |
| TS-1050 | 403 | api_key مفقود. |
| TS-1052 | 403 | sms_id مفقود، أو ليس عدداً، أو ليس أكبر من صفر. |
| TS-1031 | 403 | لم يُعثر على المفتاح أو المفتاح غير نشط. |
| TS-1061 | 403 | صلاحية «السماح بطلبات POST» معطلة. |
| TS-1063 | 403 | صلاحية «استعلام حالة SMS» معطلة. |
| TS-1030 | 403 | الحساب غير نشط. |
| TS-1020 | 403 | لم يُعثر على رسالة تخصك بهذا المعرّف. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
تعيد تقارير الإرسال الجماعي والإرسال المجدول. توجد نقطتا نهاية: التقرير الموجز يعطي عدادات الإرسال، والتقرير المفصل يعطي حالة التسليم لكل رقم.
الصلاحيات المطلوبة: «السماح بطلبات POST» و«استعلام حالة SMS» (مركز API ← مفاتيحي ← المفتاح ← الصلاحيات)
raporid هي rapor_id في استجابة /group/send و/group/sendMixed، أو sms_id في استجابة /sms/send المجدول. تستخدم نقطتا النهاية هاتان الحقل status بدلاً من result؛ ولا يوجد result_message في الاستجابة الناجحة.| المعامل | النوع | الحالة | الوصف |
|---|---|---|---|
| api_key | string | إلزامي | مفتاح API الخاص بك. |
| raporid | int | إلزامي | معرّف التقرير. |
| page | int | اختياري | للتقرير المفصل فقط: رقم الصفحة، 1 أو أكبر. القيمة الافتراضية 1. تعيد كل صفحة 500 سجل كحد أقصى. |
curl -X POST https://api.turkeysms.com.tr/reports/basic \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "raporid": 482913377 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'raporid' => 482913377, ]; $ch = curl_init('https://api.turkeysms.com.tr/reports/basic'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['status'] ?? '') === 'success') { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "raporid": 482913377, } r = requests.post("https://api.turkeysms.com.tr/reports/basic", json=payload, timeout=30) data = r.json() if data.get("status") == "success": print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', raporid: 482913377, }; const r = await fetch('https://api.turkeysms.com.tr/reports/basic', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.status === 'success') { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "status": "success", "result_code": "TS-1064", "rapor_id": 482913377, "total_numbers": 100, "success_count": 90, "failed_count": 5, "pending_count": 5, "details": { "sending_date": "2026-10-01", "sending_time": "14:22:10", "report_status": "Currently in the process of being sent.", "sms_sender_id": "BASLIGINIZ", "invalid_numbers": 2, "blocked_numbers": 1, "last_update": "2026-10-01 14:30:00" } }
| الحقل | الوصف |
|---|---|
total_numbers | عدد الأرقام في الإرسال. |
success_count | عدد الرسائل الناجحة. |
failed_count | الرسائل الفاشلة، بما فيها الأرقام غير الصالحة والمحظورة. |
pending_count | الرسائل التي لم تتضح نتيجتها بعد. |
details.sending_date, details.sending_time | تاريخ إنشاء التقرير ووقته (في الإرسال المجدول ليس وقت الإرسال). |
details.report_status | نص يبين حالة معالجة التقرير. |
details.sms_sender_id | اسم المرسل المستخدم في الإرسال. |
details.invalid_numbers, details.blocked_numbers | عدد الأرقام غير الصالحة وعدد الأرقام المحظورة. |
details.last_update | وقت آخر تحديث للعدادات. |
تتغير العدادات مع تقدّم عمليتي الإرسال وتقارير التسليم.
curl -X POST https://api.turkeysms.com.tr/reports/detailed \ -H "Content-Type: application/json" \ -d '{ "api_key": "API_ANAHTARINIZ", "raporid": 482913377, "page": 1 }'
$payload = [ 'api_key' => 'API_ANAHTARINIZ', 'raporid' => 482913377, 'page' => 1, ]; $ch = curl_init('https://api.turkeysms.com.tr/reports/detailed'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 30, ]); $body = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $res = $body !== false ? json_decode($body, true) : null; if (($res['status'] ?? '') === 'success') { // نجح الطلب } else { error_log('TurkeySMS: ' . $http . ' ' . ($res['result_code'] ?? 'لا استجابة')); }
import requests payload = { "api_key": "API_ANAHTARINIZ", "raporid": 482913377, "page": 1, } r = requests.post("https://api.turkeysms.com.tr/reports/detailed", json=payload, timeout=30) data = r.json() if data.get("status") == "success": print("نجاح", data) else: print("خطأ", r.status_code, data.get("result_code"))
// Node.js 18+ (fetch مدمجة) (async () => { const payload = { api_key: 'API_ANAHTARINIZ', raporid: 482913377, page: 1, }; const r = await fetch('https://api.turkeysms.com.tr/reports/detailed', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await r.json(); if (data.status === 'success') { console.log('نجاح', data); } else { console.error('خطأ', r.status, data.result_code); } })();
{ "status": "success", "result_code": "TS-1064", "data": [ { "phone_number": "905XXXXXXXXX", "sent_at": "2026-10-01 14:22:10", "sms_status": "Number received the message", "details": { "done_at": "2026-10-01 14:22:15", "status_code": 1, "operator": "TURKCELL" } } ], "pagination": { "current_page": 1, "total_pages": 3, "total_records": 1203, "records_per_page": 500 } }
| details.status_code | sms_status | المعنى |
|---|---|---|
1 | Number received the message | سُلّمت. |
2 | Expiration time | انتهت مدة الصلاحية؛ لم تُسلَّم. |
0 | Number didn't receive the message | لم تُسلَّم، أو لم يصل تقرير التسليم بعد. |
قيم details.operator: TURKCELL، VODAFONE، TURKTELEKOM، KKTCELL، TELSIM، UNKNOWN. إذا لم توجد سجلات بعد (مثلاً إذا لم يبدأ الإرسال المجدول) يكون data مصفوفة فارغة. وتُعاد مصفوفة فارغة أيضاً للصفحات التي تلي الصفحة الأخيرة.
{ "status": "error", "result_code": "TS-1029", "result_message": "The Report ID is invalid or missing." }
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1064 | 200 | أُعيد التقرير. |
| TS-1029 | 400 200 | 400: raporid مفقود أو ليس عدداً. 200: لم يُعثر على التقرير أو لا يخصك. |
| TS-1033 | 400 404 | 400: جسم الطلب أو page غير صالح. 404: المسار خاطئ. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1031 | 400 | المفتاح أقصر من 30 حرفاً، أو لم يُعثر عليه، أو غير نشط. |
| TS-1061 | 400 | صلاحية «السماح بطلبات POST» معطلة. |
| TS-1063 | 400 | صلاحية «استعلام حالة SMS» معطلة. |
| TS-1030 | 400 | الحساب غير نشط. |
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. |
عبر Webhook تُبلغ TurkeySMS عنواناً تحدده أنت بالأحداث التي تقع في حسابك (تسليم الرسالة إلى المشغّل، وتقرير التسليم، والرسائل الواردة وغيرها) بطلب HTTP POST. وبذلك لا تحتاج إلى الاستعلام المتكرر من API (polling) لمعرفة حالة الرسالة.
أمثلة الطلبات والأجسام في هذا القسم مطابقة تماماً للصيغة التي يرسلها النظام الحي؛ والقيم فيها (الأرقام والمعرّفات والأوقات) أمثلة.
| القديم | الجديد |
|---|---|
| X-TurkeySMS-Webhook-Id / event_id | X-TurkeySMS-Delivery / id |
| X-TurkeySMS-Webhook-Version / version | أُزيل |
| X-TurkeySms-Signature (الجسم فقط) | X-TurkeySMS-Signature-V2 (بختم زمني)؛ ويستمر إرسال الترويسة القديمة للتوافق |
| timestamp (نص ISO) | timestamp (ثوانٍ Unix، عدد) وcreated_at (ISO 8601) |
| generated_at | أُزيل |
| data.sms_id | data.message_id |
| data.mobile | data.to |
| data.delivered_at | data.done_at |
| data.failure_reason | data.reason |
| data.operator | أُزيل (operator_status هو نص الحالة لدى المشغّل) |
id.POST.2xx خلال 10 ثوانٍ يُعدّ الحدث مسلَّماً. وعند الأخطاء المؤقتة (خطأ اتصال، انتهاء المهلة، 408، 429، 5xx) يُعاد إرسال الحدث بعدد المحاولات الذي ضبطته.المدد المعتادة لإبلاغ الأحداث:
| الحدث | متى يُرسل | التأخير المعتاد |
|---|---|---|
| sms.sent | عند تسليم الرسالة إلى المشغّل | نحو 1.5–2 دقيقة (ينتظر النظام 90 ثانية لاكتمال سجل الرسالة) |
| sms.delivered | عند وصول تقرير تسليم ناجح من المشغّل | خلال 30–60 ثانية بعد وصول التقرير (وإذا وصل التقرير بسرعة كبيرة فمع sms.sent، بعد 1.5–2 دقيقة من الإرسال) |
| sms.failed | عند تعذر تسليم الرسالة إلى المشغّل أو تعذر تسليمها إلى المستلم | عند فشل التسليم 30–60 ثانية بعد وصول التقرير؛ وللرسالة التي لم تُسلَّم إلى المشغّل نحو 6–7 دقائق بعد تسجيلها |
| sms.received | عند وصول رسالة إلى رقم الرسائل الواردة الخاص بك (0850) | عادةً خلال 30 ثانية |
| inbound.matched | عند تنفيذ إجراء «استدعاء Webhook» في قاعدة أتمتة | عادةً خلال 30 ثانية |
| key.test | عند الضغط على زر اختبار في اللوحة | لحظة الضغط على الزر (متزامن) |
sms.delivered ولا sms.failed لتلك الرسالة. ويمكنك دائماً الاستعلام عن الحالة النهائية للرسالة عبر الاستعلام عن حالة الرسالة. يظهر الحدث otp.verified في اللوحة بعبارة «قريباً» ولا يُرسل حالياً.تُدار Webhooks من تبويب حسابي ← مركز API ← الأمان و IP ← Webhook. حقول نموذج «إضافة webhook جديد»:
| الحقل | الوصف |
|---|---|
| المفتاح | مفتاح API المرتبط به الـ Webhook. لكل مفتاح API Webhook واحد؛ والحفظ مجدداً للمفتاح نفسه يستبدل الـ Webhook الحالي. |
| URL | العنوان الذي تُرسل إليه الأحداث. استخدم عنوان https:// عاماً (انظر الأمان). |
| مفتاح التوقيع (Secret) | القيمة السرية المستخدمة في التوقيع. لا تُعرض في اللوحة بعد حفظها. عند التعديل يحتفظ ترك الحقل فارغاً بالـ secret الحالي؛ ولتغييره أدخل قيمة جديدة، ولإزالته فعّل خانة «إزالة المفتاح الحالي (إرسال بلا توقيع)». إذا لم يوجد secret تُرسل الطلبات دون توقيع (لا ننصح بذلك). |
| خوارزمية التوقيع | sha256 (افتراضية) أو sha512. |
| الحد الأقصى للمحاولات | من 0 إلى 10. القيمة الافتراضية 3. أقصى عدد لإعادة المحاولة بعد المحاولة الأولى. |
| الفاصل الزمني بين المحاولات (ثانية) | من 1 إلى 3600. القيمة الافتراضية 30. يتضاعف مع كل محاولة (انظر إعادة المحاولة). |
| الأحداث المحفزة | الأحداث التي تريد استقبالها. إذا لم تختر شيئاً تُرسل جميع الأحداث عدا sms.received. ولأن sms.received يحمل محتوى الرسالة فلا يُرسل إلا إذا اخترته صراحةً. |
| webhook نشط | أثناء التعطيل تُسجَّل الأحداث ولا تُرسل، وتُلغى المحاولات المعلقة أيضاً. وعند إعادة التفعيل لا تُرسل أحداث فترة التعطيل. وتُحفظ الإعدادات. |
sms.sent وsms.delivered وsms.failed، وفي الثاني sms.received فقط.| الحالة | الـ Webhook الذي يتلقى الحدث |
|---|---|
| رسالة أُرسلت بمفتاح API | Webhook ذلك المفتاح فقط. وفي الجسم يكون key_id رقم هذا المفتاح. |
| رسالة أُرسلت من اللوحة أو عبر الأتمتة | جميع Webhooks المفعّلة في حسابك التي اختارت الحدث. وفي الجسم key_id = null. |
sms.received | جميع Webhooks المفعّلة في حسابك التي اختارت الحدث sms.received صراحةً. ويجب أن تصل الرسالة إلى رقم 0850 معرّف في حسابك. |
inbound.matched | أول Webhook مفعّل في حسابك (ذو أصغر رقم مفتاح). ولا يعتمد ذلك على اختيار الأحداث. |
key.test | Webhook المفتاح الذي ضغطت زر الاختبار الخاص به. |
الرسائل المرسلة بمفتاح API الرئيسي لحسابك تُعامل معاملة الإرسال من اللوحة (جميع Webhooks، key_id = null). وإذا استخدم اثنان من Webhooks حسابك العنوان نفسه يُرسل كل حدث إلى هذا العنوان مرة واحدة فقط.
يُرسل كل طلب بطريقة POST وجسم JSON بترميز UTF-8. الترويسات:
| الترويسة | الوصف |
|---|---|
| Content-Type | دائماً application/json. |
| User-Agent | قيمة ثابتة: TurkeySMS-Webhook/1.0. |
| X-TurkeySMS-Event | اسم الحدث؛ وهو نفسه event في الجسم. |
| X-TurkeySMS-Delivery | معرّف التسليم (32 محرفاً ست عشرياً). وهو نفسه id في الجسم، ولا يتغير في إعادة المحاولات. |
| X-TurkeySMS-Attempt | رقم المحاولة: 1 في الإرسال الأول، ويزيد بواحد مع كل إعادة محاولة. |
| X-TurkeySMS-Timestamp | لحظة إرسال هذه المحاولة (ثوانٍ Unix). يتجدد في كل محاولة. |
| X-TurkeySMS-Signature | التوقيع القديم: <algo>=hex(HMAC(secret, body)). لا يشمل الختم الزمني؛ ويُرسل للتوافق مع الإصدارات السابقة فقط. |
| X-TurkeySMS-Signature-V2 | التوقيع الموصى به: t=<time>,v1=hex(HMAC(secret, "<time>.<body>")). إذا لم يُعرَّف secret فلا تُرسل ترويسات التوقيع. |
POST /turkeysms/webhook HTTP/1.1 Host: ornek.com Content-Type: application/json User-Agent: TurkeySMS-Webhook/1.0 X-TurkeySMS-Event: sms.delivered X-TurkeySMS-Delivery: 27f38025030d060f3e3b760b318b406e X-TurkeySMS-Attempt: 1 X-TurkeySMS-Timestamp: 1790857803 X-TurkeySMS-Signature: sha256=776ebd61c3789873d7851a30e868ff8e73dbc586bccd67d49e50b3498e827e44 X-TurkeySMS-Signature-V2: t=1790857803,v1=660a71ff372d5921231c4871913b030476acfdad1dafee4eb6f3117126837b11
يستخدم الجسم الغلاف نفسه في كل حدث:
| الحقل | النوع | الوصف |
|---|---|---|
| id | string | المعرّف الفريد للحدث (32 محرفاً ست عشرياً) = X-TurkeySMS-Delivery. استبعد التكرار بهذه القيمة. |
| event | string | اسم الحدث (مثل sms.delivered). |
| created_at | string | وقت إنشاء الحدث، ISO 8601. |
| timestamp | int | وقت إنشاء الحدث، ثوانٍ Unix. لا يتغير في إعادة المحاولات؛ ولنافذة الوقت في التوقيع استخدم قيمة t= في التوقيع لا هذه القيمة. |
| data | object | الحقول الخاصة بالحدث (أدناه). |
في الأحداث sms.sent وsms.delivered وsms.failed يحتوي data على الحقول المشتركة التالية. ولا يُرسل نص الرسالة في هذه الأحداث.
| الحقل | النوع | الوصف |
|---|---|---|
| message_id | int | رقم الرسالة. وهو نفسه sms_id في استجابة /sms/send؛ ويمكن استخدامه مع الاستعلام عن حالة الرسالة. |
| bulk_id | string | رقم العملية الجماعية (الحملة) للإرسال. |
| to | string | رقم المستلم بالصيغة الدولية (905xxxxxxxxx). |
| sender_id | string | اسم المرسل الذي أُرسلت به الرسالة. |
| parts | int | عدد أجزاء SMS التي تتكون منها الرسالة. |
| source | string | مصدر الرسالة. أمثلة: api (عبر API)، Web (من اللوحة). |
| key_id | int | null | رقم مفتاح API الذي أُرسلت به الرسالة. null للرسائل المرسلة من اللوحة أو عبر الأتمتة. |
| sent_at | string | وقت الإرسال، ISO 8601 (2026-10-01T15:28:31+03:00). |
sms.sent — سُلّمت الرسالة إلى المشغّل. تُرسل الحقول المشتركة فقط.
{ "id": "353272ae3ae66d3233cd5ebe30faadcf", "event": "sms.sent", "created_at": "2026-10-01T15:30:02+03:00", "timestamp": 1790857802, "data": { "message_id": 518431556, "bulk_id": "1259383818", "to": "905xxxxxxxxx", "sender_id": "BASLIGIM", "parts": 1, "source": "api", "key_id": 4804, "sent_at": "2026-10-01T15:28:31+03:00" } }
sms.delivered — سُلّمت الرسالة إلى المستلم. إضافةً إلى الحقول المشتركة:
| الحقل | النوع | الوصف |
|---|---|---|
| status | string | دائماً delivered. |
| done_at | string | null | وقت التسليم لدى المشغّل، ISO 8601. null إذا لم يُبلِغ المشغّل عن الوقت. |
| operator_status | string | نص الحالة الذي أعاده المشغّل (مثل Message delivered to handset). |
{ "id": "27f38025030d060f3e3b760b318b406e", "event": "sms.delivered", "created_at": "2026-10-01T15:30:03+03:00", "timestamp": 1790857803, "data": { "message_id": 518431556, "bulk_id": "1259383818", "to": "905xxxxxxxxx", "sender_id": "BASLIGIM", "parts": 1, "source": "api", "key_id": 4804, "sent_at": "2026-10-01T15:28:31+03:00", "done_at": "2026-10-01T15:28:33+03:00", "operator_status": "Message delivered to handset", "status": "delivered" } }
sms.failed — تعذر تسليم الرسالة إلى المشغّل أو تعذر تسليمها إلى المستلم. إضافةً إلى الحقول المشتركة:
| الحقل | النوع | الوصف |
|---|---|---|
| stage | string | submit: لم تُسلَّم الرسالة إلى المشغّل بعد نحو 6–7 دقائق من تسجيلها (وفي هذه الحالة يكون bulk_id هو "0" وقد يكون reason فارغاً). delivery: أعاد المشغّل تقريراً بتعذر التسليم. |
| status | string | في مرحلة submit: rejected؛ وفي مرحلة delivery: undelivered أو expired أو canceled. |
| reason | string | سبب الخطأ (200 حرف كحد أقصى). |
| done_at | string | null | في مرحلة delivery فقط: وقت التقرير لدى المشغّل. |
| operator_status | string | في مرحلة delivery فقط: نص الحالة لدى المشغّل. |
{ "id": "9755ae0b22863732063111ea35e2e1f4", "event": "sms.failed", "created_at": "2026-10-01T15:35:44+03:00", "timestamp": 1790858144, "data": { "message_id": 518431601, "bulk_id": "1259383818", "to": "905xxxxxxxxx", "sender_id": "BASLIGIM", "parts": 1, "source": "api", "key_id": 4804, "sent_at": "2026-10-01T15:28:31+03:00", "done_at": "2026-10-01T15:35:40+03:00", "operator_status": "Unknown Subscriber", "stage": "delivery", "status": "undelivered", "reason": "Unknown Subscriber" } }
{ "id": "b1c2d3e4f5a60718293a4b5c6d7e8f90", "event": "sms.failed", "created_at": "2026-10-01T15:40:31+03:00", "timestamp": 1790858431, "data": { "message_id": 518431620, "bulk_id": "0", "to": "905xxxxxxxxx", "sender_id": "BASLIGIM", "parts": 1, "source": "api", "key_id": 4804, "sent_at": "2026-10-01T15:28:31+03:00", "stage": "submit", "status": "rejected", "reason": "" } }
sms.received — وصلت رسالة SMS إلى رقم 0850 المعرّف في حسابك. ولأنه يحتوي على نص الرسالة فلا يُرسل إلا إذا اخترته صراحةً في إعدادات الـ Webhook.
| الحقل | النوع | الوصف |
|---|---|---|
| message_id | int | رقم الرسالة الواردة. تُرقَّم الرسائل الواردة بشكل مستقل عن الرسائل الصادرة. |
| from | string | رقم المرسِل. |
| to | string | رقم 0850 الخاص بك الذي وصلت إليه الرسالة (908509xxxxxx). |
| text | string | نص الرسالة (UTF-8). |
| network | string | مشغّل المرسِل (مثل TURKCELL-TR). |
| received_at | string | وقت استلام الرسالة، ISO 8601. |
{ "id": "9262804e8760b90e1c0714d0ca78ac02", "event": "sms.received", "created_at": "2026-10-01T15:49:02+03:00", "timestamp": 1790858942, "data": { "message_id": 436956, "from": "905xxxxxxxxx", "to": "908509444004", "text": "BANK", "network": "TURKCELL-TR", "received_at": "2026-10-01T15:48:48+03:00" } }
inbound.matched — نُفّذ إجراء «استدعاء Webhook» في قاعدة على صفحة الرسائل الواردة ← الأتمتة. يحتوي على الحقول نفسها التي في sms.received، إضافةً إلى rule_id (int) وrule_name (string).
inbound.matched يُرسل received_at حالياً بالصيغة YYYY-MM-DD HH:MM:SS (بتوقيت إسطنبول، دون معلومات المنطقة الزمنية). اقبل في المستقبِل لديك هذه الصيغة وصيغة ISO 8601 كلتيهما.{ "id": "4be0f6d1c2a3958e7f60a1b2c3d4e5f6", "event": "inbound.matched", "created_at": "2026-10-01T15:52:31+03:00", "timestamp": 1790859151, "data": { "message_id": 436957, "from": "905xxxxxxxxx", "to": "908509444004", "text": "HOOK", "network": "TURKCELL-TR", "received_at": "2026-10-01 15:52:24", "rule_id": 12, "rule_name": "Webhook'a ilet" } }
key.test — يُرسل بزر الاختبار في اللوحة؛ ولا يُعاد إرساله. تختلف قيمة message بحسب علامتك التجارية.
{ "id": "5d0e3c9a7b1f42e68c0d9a1b2c3e4f50", "event": "key.test", "created_at": "2026-10-01T15:01:06+03:00", "timestamp": 1790856066, "data": { "key_id": 4804, "message": "TurkeySMS test fire", "test": true } }
"simulated": true داخل data. والقيمة message_id وأرقام الهواتف فيها ليست حقيقية، ولا يوجد فيها الحقل key_id؛ فتحقق من هذا الحقل كي لا تخلطها ببياناتك الحية.إذا عُرّف secret يصل كل طلب بترويستي توقيع. تحقق من الترويسة X-TurkeySMS-Signature-V2؛ فلأنها تشمل الختم الزمني أيضاً تمنع إعادة إرسال طلب مُعترَض (replay).
X-TurkeySMS-Signature-V2: t=<unix>,v1=<hex>. والبادئة v1 هنا هي وسم إصدار مخطط التوقيع.sha256، و128 محرفاً = sha512 (أو استخدم ما اخترته في اللوحة).HMAC(algorithm, secret, t + "." + raw_body) بصيغة ست عشرية.hash_equals، crypto.timingSafeEqual، hmac.compare_digest).|now − t| أكبر من 300 ثانية فارفض الطلب. وتأكد من مزامنة ساعة خادمك عبر NTP.401 ولا تعالج الجسم.timestamp في الجسم. فهذا الحقل وقت إنشاء الحدث ولا يتغير في إعادة المحاولات؛ وقد يجعلك ترفض إعادة محاولة صالحة تصل بعد ساعات. كل محاولة تُوقَّع من جديد بقيمة t= جديدة.التوقيع القديم (X-TurkeySMS-Signature): بصيغة sha256=<hex> ويوقّع الجسم فقط. ولأنه لا يحتوي على ختم زمني فلا يحمي وحده من هجمات إعادة الإرسال. لا تستخدمه في عمليات الربط الجديدة.
تغيير الـ secret: بمجرد حفظ الـ secret الجديد في اللوحة تُوقَّع جميع المحاولات التالية به. ولتجنب الانقطاع اجعل المستقبِل لديك يقبل الـ secret القديم والجديد معاً أولاً، ثم غيّر الـ secret في اللوحة، وبعد بضع ساعات أزل الـ secret القديم من المستقبِل.
| استجابة خادمك | سلوك TurkeySMS |
|---|---|
| 2xx | سُلّم الحدث؛ ولا يُعاد إرساله. |
| 408, 429, 5xx | خطأ مؤقت؛ تُعاد المحاولة. |
| خطأ اتصال، خطأ DNS، خطأ TLS، انتهاء مهلة 10 ثوانٍ | خطأ مؤقت؛ تُعاد المحاولة. |
| 3xx (إعادة توجيه) | لا تُتبع إعادة التوجيه؛ خطأ دائم، ولا تُعاد المحاولة. استخدم العنوان النهائي للـ URL. |
| 4xx أخرى (400, 401, 403, 404 …) | خطأ دائم؛ ولا تُعاد المحاولة. |
مدة إنشاء الاتصال 5 ثوانٍ كحد أقصى، والمدة الإجمالية للطلب 10 ثوانٍ كحد أقصى. ويتضاعف وقت الانتظار مع كل محاولة: interval × 2(attempt − 1)، بحد أقصى 6 ساعات. مع الإعدادات الافتراضية (3 محاولات، 30 ثانية):
| المحاولة | متى | ملاحظة |
|---|---|---|
| 1 | عند إنشاء الحدث | |
| 2 | بعد نحو 30 ثانية من المحاولة 1 | |
| 3 | بعد نحو 60 ثانية من المحاولة 2 | |
| 4 | بعد نحو 120 ثانية من المحاولة 3 | المحاولة الأخيرة؛ وإذا فشلت يُعلَّم الحدث بأن محاولاته استُنفدت. |
تعمل إعادة المحاولات بدورة معالجة مدتها 30 ثانية؛ وقد تزيد المدة الفعلية على ما في الجدول بنحو 30 ثانية كحد أقصى. تظهر جميع المحاولات (الطلب، ورمز الاستجابة، وأول 8000 حرف من جسم الاستجابة، والمدة) في صفحة مركز الـ Webhook ← سجلات التسليم. لذلك لا تُعِد معلومات سرية في جسم الاستجابة؛ فقيمة قصيرة (ok) تكفي.
200 فوراً. ونفّذ العمليات الطويلة (البريد الإلكتروني، واستدعاء API خارجية وغيرها) بعد الاستجابة. الاستجابة التي تتجاوز 10 ثوانٍ تُعدّ انتهاءً للمهلة حتى لو عالج خادمك الحدث، ويُعاد إرسال الحدث.id من الجسم، وإذا وصل id عالجته من قبل فأعِد 200 دون معالجته.sms.delivered قبل sms.sent. احفظ حالة الرسالة على مستوى message_id؛ فـ delivered وfailed حالتان نهائيتان، ويجب ألا يغيّرهما sms.sent الذي يصل لاحقاً.id وأعِد 500؛ فتُعاد المحاولة للحدث.200 أيضاً عند وصول حدث لا تعالجه؛ وإلا فستنشأ إعادة محاولات غير ضرورية.localhost ولا الشبكات الخاصة (10.x، 172.16–31.x، 192.168.x) ولا CGNAT ولا العناوين المحجوزة. عناوين URL التي تحتوي على عنوان IP خاص أو محجوز أو اسم محلي (localhost، .local، .lan، .internal) تُرفض عند الحفظ؛ أما أسماء النطاقات التي تُحلّ إلى عنوان خاص فتُرفض لحظة الإرسال، ولا تُعاد المحاولة لهذا الخطأ. يُحلّ اسم النطاق في كل إرسال، ويتم الاتصال بعنوان IP الذي جرى التحقق منه.http → https أو إضافة / في النهاية؛ أدخل العنوان النهائي مباشرة.401 كل طلب بلا ترويسة توقيع أو يتعذر التحقق منه.sms.received وinbound.matched على نص الرسالة ورقم الهاتف؛ احفظ هذه البيانات وفق KVKK (قانون حماية البيانات الشخصية التركي) وقيّد الوصول إليها.| الأداة | المكان | الوظيفة |
|---|---|---|
| زر الاختبار | الأمان و IP ← Webhook ← webhooks المعرفة | يرسل الحدث key.test ويعرض النتيجة (رمز HTTP، المدة) فوراً. ولا تُعاد المحاولة. |
| محاكي Webhook | بطاقة «Sandbox» أسفل الصفحة نفسها | يرسل الحدث الذي تختاره (sms.sent، sms.delivered، sms.failed، sms.received، key.test) بتوقيع حقيقي وإعادة محاولة حقيقية؛ ويحتوي الجسم على "simulated": true. إذا لم يختر الـ Webhook ذلك الحدث أو لم يكن نشطاً فلا يُرسل شيء. وعند تفعيل «تجربة بدون إرسال» لا يُرسل الطلب، بل يُعرض الجسم والتوقيع فقط. |
| سجلات التسليم | مركز API ← مركز الـ Webhook | تعرض طلب كل محاولة واستجابتها، ورقم المحاولة، والمدة، وسبب الخطأ؛ ويمكن تصفيتها حسب المفتاح والحدث والحالة، وتنزيلها بصيغة CSV. |
| الصحة والتنبيهات | مركز API ← مركز الـ Webhook | عدد الأخطاء المتتالية، ونسبة النجاح في آخر 24 ساعة، ووقت آخر نجاح/خطأ، وWebhooks المعرّضة للخطر، وحالة إعادة المحاولة. |
localhost) مباشرة. اختبر عبر خادم اختبار عام أو خدمة نفق HTTPS.تؤدي الأمثلة الثلاثة العمل نفسه: تتحقق من توقيع V2 ونافذة الوقت، وتستبعد التكرار بقيمة id، وتعيد 200 بسرعة. وقد اختُبرت الأمثلة بسيناريوهات الطلب الصالح، وإعادة المحاولة، والـ secret الخاطئ، والختم الزمني القديم، والجسم المعدَّل، وsha512. ولفحص التكرار يمكنك أيضاً استخدام عمود فريد (UNIQUE) في قاعدة بيانات بدلاً من الملف؛ وفي العمليات الحرجة احفظ id في معاملة قاعدة البيانات (transaction) نفسها مع الحدث.
<?php
// مستقبِل Webhook من TurkeySMS (PHP 7.4+)
$secret = getenv('TURKEYSMS_WEBHOOK_SECRET') ?: ''; // الـ secret الذي عرّفته في اللوحة (من متغير بيئة)
$seenDir = '/var/lib/myapp/webhook-seen'; // مجلد قابل للكتابة خارج جذر الموقع
$body = file_get_contents('php://input'); // يُحسب التوقيع على الجسم الخام
if ($secret === '') { // الإعدادات ناقصة: لتُعِد TurkeySMS المحاولة
http_response_code(500);
exit;
}
// 1) التحقق من X-TurkeySMS-Signature-V2: t=<unix>,v1=<hex HMAC("<t>.<body>")>
$sig = $_SERVER['HTTP_X_TURKEYSMS_SIGNATURE_V2'] ?? '';
if (!preg_match('/^t=(\d+),v1=([0-9a-f]{64}|[0-9a-f]{128})$/D', $sig, $m)) {
http_response_code(401);
exit;
}
$algo = strlen($m[2]) === 64 ? 'sha256' : 'sha512'; // الخوارزمية التي اخترتها في اللوحة
$expected = hash_hmac($algo, $m[1] . '.' . $body, $secret);
// تُقاس نافذة الوقت بقيمة t= في التوقيع (كل محاولة تُوقَّع من جديد)، لا بالحقل "timestamp" في الجسم.
if (!hash_equals($expected, $m[2]) || abs(time() - (int)$m[1]) > 300) {
http_response_code(401);
exit;
}
// 2) استبعد التكرار: "id" = X-TurkeySMS-Delivery، وهو نفسه في جميع المحاولات.
$evt = json_decode($body, true);
$id = is_array($evt) && preg_match('/^[0-9a-f]{32}$/D', (string)($evt['id'] ?? '')) ? $evt['id'] : '';
if ($id === '') {
http_response_code(400);
exit;
}
if (!is_dir($seenDir)) @mkdir($seenDir, 0750, true);
$marker = @fopen($seenDir . '/' . $id, 'x'); // يفشل إذا وصل الـ id نفسه من قبل
if ($marker === false) {
http_response_code(is_file($seenDir . '/' . $id) ? 200 : 500); // 500 → تعيد TurkeySMS المحاولة
exit;
}
fclose($marker);
// 3) احفظ الحدث أو ضعه في قائمة انتظار بسرعة (تنتظر TurkeySMS 10 ثوانٍ كحد أقصى).
// إذا فشل الحفظ فاحذف ملف العلامة وأعِد 500؛ فتُعاد المحاولة للحدث.
$d = $evt['data'];
switch ($evt['event']) {
case 'sms.sent': /* $d['message_id'], $d['to'], $d['sender_id'] */ break;
case 'sms.delivered': /* $d['message_id'], $d['done_at'] */ break;
case 'sms.failed': /* $d['message_id'], $d['stage'], $d['status'], $d['reason'] */ break;
case 'sms.received': /* $d['from'], $d['to'], $d['text'] */ break;
case 'inbound.matched': /* $d['from'], $d['text'], $d['rule_id'] */ break;
case 'key.test': break;
}
http_response_code(200);
echo 'ok';// مستقبِل Webhook من TurkeySMS (Node.js 18+ · Express 4)
const express = require('express');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const SECRET = process.env.TURKEYSMS_WEBHOOK_SECRET; // الـ secret الذي عرّفته في اللوحة
const SEEN_DIR = '/var/lib/myapp/webhook-seen'; // مجلد دائم قابل للكتابة
fs.mkdirSync(SEEN_DIR, { recursive: true });
const app = express();
// يُحسب التوقيع على الجسم الخام: لا تستخدم محلل JSON في هذا المسار.
app.post('/turkeysms/webhook', express.raw({ type: '*/*', limit: '256kb' }), (req, res) => {
if (!SECRET) return res.sendStatus(500); // الإعدادات ناقصة: لتُعِد TurkeySMS المحاولة
const body = req.body; // Buffer
const m = /^t=(\d+),v1=([0-9a-f]{64}|[0-9a-f]{128})$/.exec(req.get('X-TurkeySMS-Signature-V2') || '');
if (!m) return res.sendStatus(401);
const algo = m[2].length === 64 ? 'sha256' : 'sha512';
const expected = crypto.createHmac(algo, SECRET).update(m[1] + '.').update(body).digest('hex');
const fresh = Math.abs(Date.now() / 1000 - Number(m[1])) <= 300;
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2])) || !fresh) {
return res.sendStatus(401);
}
let evt;
try { evt = JSON.parse(body.toString('utf8')); } catch { return res.sendStatus(400); }
if (!/^[0-9a-f]{32}$/.test(evt.id || '')) return res.sendStatus(400);
// استبعد التكرار: "id" هو نفسه في جميع المحاولات.
try {
fs.writeFileSync(path.join(SEEN_DIR, evt.id), '', { flag: 'wx' });
} catch (e) {
return res.sendStatus(e.code === 'EEXIST' ? 200 : 500);
}
// احفظ الحدث أو ضعه في قائمة انتظار بسرعة (10 ثوانٍ كحد أقصى).
const d = evt.data;
switch (evt.event) {
case 'sms.sent': /* d.message_id, d.to */ break;
case 'sms.delivered': /* d.message_id, d.done_at */ break;
case 'sms.failed': /* d.stage, d.status, d.reason */ break;
case 'sms.received': /* d.from, d.to, d.text */ break;
case 'inbound.matched': /* d.text, d.rule_id */ break;
case 'key.test': break;
}
res.status(200).send('ok');
});
app.listen(3000);# مستقبِل Webhook من TurkeySMS (Python 3.8+ · Flask 2+)
import hashlib, hmac, json, os, re, time
from flask import Flask, request
SECRET = os.environ["TURKEYSMS_WEBHOOK_SECRET"].encode() # الـ secret الذي عرّفته في اللوحة
SEEN_DIR = "/var/lib/myapp/webhook-seen" # مجلد دائم قابل للكتابة
os.makedirs(SEEN_DIR, exist_ok=True)
SIG_RE = re.compile(r"t=(\d+),v1=([0-9a-f]{64}|[0-9a-f]{128})")
app = Flask(__name__)
@app.post("/turkeysms/webhook")
def turkeysms_webhook():
body = request.get_data() # الجسم الخام (bytes)
m = SIG_RE.fullmatch(request.headers.get("X-TurkeySMS-Signature-V2", ""))
if not m:
return "", 401
ts, sig = m.group(1), m.group(2)
algo = hashlib.sha256 if len(sig) == 64 else hashlib.sha512
expected = hmac.new(SECRET, ts.encode() + b"." + body, algo).hexdigest()
if not hmac.compare_digest(expected, sig) or abs(time.time() - int(ts)) > 300:
return "", 401
try:
evt = json.loads(body)
except ValueError:
return "", 400
eid = evt.get("id", "") if isinstance(evt, dict) else ""
if not re.fullmatch(r"[0-9a-f]{32}", eid):
return "", 400
# استبعد التكرار: "id" هو نفسه في جميع المحاولات.
try:
os.close(os.open(os.path.join(SEEN_DIR, eid), os.O_CREAT | os.O_EXCL | os.O_WRONLY))
except FileExistsError:
return "duplicate", 200
except OSError:
return "", 500 # تعيد TurkeySMS المحاولة
# احفظ الحدث أو ضعه في قائمة انتظار بسرعة (10 ثوانٍ كحد أقصى).
d = evt["data"]
if evt["event"] == "sms.delivered":
pass # d["message_id"], d["done_at"]
elif evt["event"] == "sms.failed":
pass # d["stage"], d["status"], d["reason"]
elif evt["event"] == "sms.received":
pass # d["from"], d["to"], d["text"]
return "ok", 200| العَرَض | السبب المحتمل | الحل |
|---|---|---|
| 401 في سجلات التسليم | الـ secret مختلف عما في المستقبِل؛ أو عُدّل الجسم قبل التحقق من التوقيع (حُلّل JSON ثم أُعيد بناؤه)؛ أو ساعة الخادم منحرفة. | أدخل الـ secret من جديد في الطرفين؛ واحسب التوقيع على الجسم الخام؛ وزامن الساعة عبر NTP. |
| «انتهاء المهلة» | لا يستجيب المستقبِل خلال 10 ثوانٍ. | أعِد 200 أولاً ونفّذ العمل بعد ذلك. يُعاد إرسال الحدث؛ فاستبعد التكرار بقيمة id. |
| 3xx ولا إعادة محاولة | الـ URL يعيد التوجيه (مثل http → https، أو / في النهاية). | اكتب في URL الخاص بالـ Webhook العنوان النهائي دون إعادة توجيه. |
| لا تصل أي أحداث | الـ Webhook غير نشط؛ أو الحدث غير مختار؛ أو أُرسلت الرسالة بمفتاح API آخر؛ أو الـ URL في شبكة خاصة. | تحقق من الإعدادات وقواعد التوجيه؛ وتحقق من الاتصال بزر الاختبار. |
لا يصل sms.received | لم يُختر الحدث صراحةً (الاختيار الفارغ لا يشمل هذا الحدث)، أو وصلت الرسالة إلى رقم غير معرّف في حسابك. | فعّل الحدث sms.received في الـ Webhook؛ وأرسل الرسالة إلى رقم من صفحة الرسائل الواردة ← أرقامي. |
وصل inbound.matched إلى URL غير متوقع | هذا الحدث يذهب دائماً إلى أول Webhook مفعّل في حسابك. | تأكد أن أول Webhook لديك قادر على معالجة هذا الحدث (وإن لم يعالجه فليُعِد 200 مع ذلك). |
| وصل الحدث نفسه مرتين | التسليم مرة واحدة على الأقل؛ إعادة محاولة بعد انتهاء المهلة. | هذا طبيعي. استبعد التكرار بقيمة id. |
لم يصل sms.delivered | الحدث غير مختار، أو لم يُعِد المشغّل تقريراً خلال 72 ساعة. | تحقق من أحداث الـ Webhook؛ واستعلم عن الحالة عبر الاستعلام عن حالة الرسالة. |
| تصل الأحداث متأخرة | عندما تعيد نقطة النهاية لديك خطأ اتصال أو 429 أو 5xx تؤجَّل جميع الأحداث المعلقة لذلك الـ Webhook 60 ثانية؛ وإذا استمر الخطأ تُستنفد المحاولات. | افحص الخطأ في صفحتي سجلات التسليم والصحة والتنبيهات، وأصلح نقطة النهاية لديك. |
https:// عام بشهادة صالحة، ولا يعيد التوجيه.X-TurkeySMS-Signature-V2 على الجسم الخام وبمقارنة ثابتة الزمن.t= في التوقيع (300 ثانية)، وساعة الخادم متزامنة عبر NTP.id؛ وتُحفظ الحالة على مستوى message_id مع الحفاظ على الحالات النهائية.2xx في أقل من 10 ثوانٍ؛ والأعمال الطويلة في قائمة انتظار.200 أيضاً للأحداث غير المعروفة.sms.received مفعّل صراحةً إذا كان مطلوباً.هل يمكنني إرسال الأحداث إلى أكثر من URL؟
نعم. لكل مفتاح API Webhook واحد؛ فاستخدم مفاتيح مختلفة لعناوين مختلفة. وأحداث الرسائل المرسلة من اللوحة تذهب إلى جميع Webhooks المفعّلة.
بأي منطقة زمنية تكون الأحداث؟
تُرسل حقول التاريخ بصيغة ISO 8601 مع معلومات المنطقة الزمنية (+03:00)؛ وبالنسبة إلى received_at في inbound.matched انظر الملاحظة أعلاه. أما timestamp وX-TurkeySMS-Timestamp فبالثواني وفق Unix.
هل يصل نص الرسالة في الـ Webhook؟
لا يصل في أحداث الرسائل الصادرة (sms.sent، sms.delivered، sms.failed). ويصل في الرسائل الواردة (sms.received، inbound.matched).
هل يمكنني استلام أحداث الفترة التي كان فيها الـ Webhook معطلاً؟
لا. لا تُرسل أحداث فترة التعطيل؛ فاستعلم عن حالات رسائل تلك الفترة عبر التقارير.
ماذا يحدث إذا استُنفدت محاولات الإعادة؟
يُعلَّم الحدث بأن محاولاته استُنفدت ولا يُرسل مرة أخرى. ويمكنك رؤيته في سجلات التسليم.
يمكنك مراقبة استخدامك لـ API من اللوحة:
| اللوحة | المحتوى |
|---|---|
| مركز API ← الإحصائيات | إجمالي الطلبات، ونسبة النجاح، والتوزيع حسب نقطة النهاية، والمفاتيح الأكثر استخداماً. |
| مركز API ← سجلات الاتصال | سجلات الطلبات؛ ويمكن تصفيتها حسب الحالة ونقطة النهاية والمفتاح وعنوان IP ورمز الاستجابة. |
| Webhook / السجلات ← سجلات التسليم | سجلات تسليم طلبات Webhook واستجاباتها. |
بعض الطلبات المرفوضة أثناء التحقق من المعاملات (مثل حقل مفقود) قد لا تظهر في سجلات الاتصال. أثناء تتبع الأخطاء ننصحك بتسجيل الطلبات والاستجابات في جهتك أيضاً (دون مفتاح API).
قد تُعاد الرموز مع حالات HTTP مختلفة بحسب نقطة النهاية. الشروح المفصلة في قسم نقطة النهاية المعنية؛ وهذا الجدول للرجوع السريع.
| الرمز | HTTP | المعنى |
|---|---|---|
| SRV-ERR | 500 | خطأ غير متوقع في الخادم. وقد يعيد الاستعلام عن الرصيد والاستعلام عن اسم المرسل هذا الرمز مع 403 أيضاً. |
| TS-1033 | 400 404 | جسم الطلب غير صالح؛ وفي المجموعات والأرقام والتقارير مسار خاطئ مع 404. |
| TS-1030 | 400 403 | الحساب غير نشط. |
| TS-1031 | 400 401 403 | مفتاح API غير صالح، أو لم يُعثر عليه، أو غير نشط. |
| TS-1035 | 403 | المفتاح متوقف مؤقتاً أو منتهي الصلاحية أو ملغى. |
| TS-1066 | 403 | عنوان IP الذي جاء منه الطلب ليس في قائمة السماح للمفتاح. |
| TS-1068 | 429 | بلغ المفتاح حد الطلبات في الساعة. |
| TS-1069 | 429 | بلغ المفتاح حد الطلبات في اليوم. |
| TS-1073 | 429 | بلغ المفتاح حد الطلبات في الشهر. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1000 | 200 | المفتاح صالح؛ أُعيدت الصلاحيات وملخص الحساب. |
| TS-5000 | 500 | خطأ غير متوقع في الخادم. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1024 | 200 | قُبل الإرسال للمعالجة. |
| TS-1050 | 401 | api_key مفقود أو قصير. |
| TS-1025 | 400 | المستلم مفقود. |
| TS-1051 | 400 | اسم المرسل مفقود. |
| TS-1029 | 400 | اسم المرسل أطول من 11 حرفاً. |
| TS-1026 | 400 | النص فارغ أو أطول من 2000 حرف. |
| TS-1028 | 400 | اسم المرسل غير موجود في الحساب أو غير معتمد. |
| TS-1060 | 400 429 | 400: حد عدد المستلمين. 429: حد الإرسال في الدقيقة. |
| TS-1061 | 403 | «السماح بطلبات POST» معطلة. |
| TS-1062 | 403 | «إرسال SMS» معطلة. |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| TS-1070 / TS-1071 / TS-1072 | 400 | تاريخ الجدولة أو وقتها أو وقت في الماضي. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1024 | 200 | وُضع الإرسال في قائمة الانتظار. |
| TS-1025 | 400 | api_key مفقود أو قصير. |
| TS-1029 | 400 | اسم المرسل مفقود. |
| TS-1026 | 400 | قائمة الأرقام مفقودة أو أحد النصوص أطول من 2000 حرف. |
| TS-1060 | 400 | حد 50000 رقم. |
| TS-1070 / TS-1071 / TS-1072 | 400 | حقول الجدولة غير صالحة. |
| TS-1067 | 403 | «الإرسال للمجموعات» معطلة. |
| TS-1028 | 403 | اسم المرسل غير موجود في الحساب أو غير معتمد. |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1024 | 200 | أُرسل رمز OTP. |
| TS-1050 | 400 401 | api_key مفقود. |
| TS-1025 | 400 | الرقم مفقود. |
| TS-1034 | 400 403 | صيغة الرقم غير صالحة. |
| TS-1051 | 400 | اسم المرسل مفقود (OTP المتقدم). |
| TS-1026 | 400 | النص فارغ، أو بلا TS-CODE، أو طويل جداً (OTP المتقدم). |
| TS-1029 | 400 403 | اسم المرسل أطول من 11 حرفاً أو غير موجود في الحساب (OTP المتقدم). |
| TS-1028 | 403 | اسم المرسل غير معتمد لرسائل OTP (OTP المتقدم). |
| TS-1036 | 403 | «إرسال OTP» معطلة. |
| TS-1037 | 403 | «OTP متقدم» معطلة. |
| TS-1061 | 403 | «السماح بطلبات POST» معطلة (OTP المتقدم). |
| TS-1027 | 403 | الرصيد غير كافٍ. |
| TS-5000 | 403 | تعذر حفظ الرسالة؛ أعد المحاولة. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1080 / TS-1087 / TS-1088 / TS-1090 | 200 | أُنشئت / حُدّثت / حُذفت / عُرضت. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1081 / TS-1084 / TS-1085 / TS-1089 | 400 | الصلاحية المعنية معطلة. |
| TS-1082 | 200 | اسم المجموعة موجود مسبقاً (نتيجة فاشلة). |
| TS-1083 | 400 200 | اسم المجموعة غير صالح. |
| TS-1086 | 400 200 | لم يُعثر على المجموعة أو group_id مفقود. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1100 | 200 | أُضيف الرقم. |
| TS-1101 | 200 | الرقم غير صالح (نتيجة فاشلة). |
| TS-1050 | 400 | api_key مفقود. |
| TS-1025 | 400 | gsm_number مفقود. |
| TS-1065 | 400 | «إضافة رقم» معطلة. |
| TS-1086 | 400 200 | لم يُعثر على المجموعة أو group_id غير صالح. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1141 | 200 | أُضيف الرقم إلى القائمة. |
| TS-1142 / TS-1143 | 200 | الرقم ليس في القائمة / في القائمة. |
| TS-1050 | 403 | api_key مفقود. |
| TS-1025 | 400 | number مفقود. |
| TS-1144 | 400 | الرقم ليس رقم جوال تركياً صالحاً. |
| TS-1140 | 400 | الرقم في القائمة مسبقاً. |
| TS-1065 | 403 | «حظر رقم» معطلة. |
| TS-404 | 404 | المسار خاطئ. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1040 | 200 | نجح الاستعلام. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1025 | 400 | api_key قصير (الاستعلام عن الرصيد). |
| TS-1065 | 403 | «استعلام الرصيد» معطلة. |
| TS-1038 | 403 | «استعلام اسم المرسل» معطلة. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1064 | 200 | سُلّمت الرسالة. |
| TS-1022 | 200 | لا يوجد تأكيد تسليم (لم تُسلَّم أو لم يصل التقرير بعد). |
| TS-1050 | 403 | api_key مفقود. |
| TS-1052 | 403 | sms_id مفقود أو غير صالح. |
| TS-1061 | 403 | «السماح بطلبات POST» معطلة. |
| TS-1063 | 403 | «استعلام حالة SMS» معطلة. |
| TS-1020 | 403 | لم يُعثر على الرسالة. |
| الرمز | HTTP | المعنى |
|---|---|---|
| TS-1064 | 200 | أُعيد التقرير. |
| TS-1029 | 400 200 | معرّف التقرير مفقود أو لم يُعثر على التقرير. |
| TS-1050 | 400 | api_key مفقود. |
| TS-1061 | 400 | «السماح بطلبات POST» معطلة. |
| TS-1063 | 400 | «استعلام حالة SMS» معطلة. |
لا تحتاج الأمثلة في هذه الصفحة إلى أي مكتبة؛ فهي تعمل بعميل HTTP القياسي في كل لغة. عرّف مهلة انتظار في كودك، وقيّم النتيجة حسب الحقلين result (أو status) وresult_code.
لتجربة API من المتصفح يمكنك استخدام التوثيق التفاعلي (Swagger، OpenAPI 3.1). التوثيق التفاعلي متاح باللغة الإنجليزية فقط.
result_code وتاريخ الطلب ووقته؛ ولا تشارك مفتاح API.