v4.1 — 35+ Endpoints تطبيق المشتركين على Google Play

🚀 البداية والتهيئة

توثيق شامل لجميع مسارات واجهة برمجة تطبيقات المشتركين في منظومة FreeNet. يغطي هذا التوثيق 35+ نقطة وصول (Endpoint) تشمل المصادقة، إدارة الباقات، المحفظة، الفواتير، الاستهلاك، الدعم الفني والمجلة الرقمية.

⚙️ تخصيص رابط الـ Base URL المباشر للطلبات

Base URL https://192.168.5.55/api/subscriber/
📄
Content-Type
application/json
🔑
Authentication
Bearer Token
🌐
Protocol
HTTPS (TLS 1.3)
🌍
Language Header
Accept-Language: ar
الترويسات الإلزامية
Headerالقيمةالوصفإلزامي؟
Acceptapplication/jsonدائماً لاستقبال JSONمطلوب
Content-Typeapplication/jsonفي طلبات POST فقطمطلوب مع POST
AuthorizationBearer {token}في المسارات المحمية بعد Loginمطلوب بعد Login
Accept-Languagear / enلغة رسائل الاستجابةاختياري

🔐 إرشادات الأمان للمطورين

⚠️ التزام صارم بهذه المبادئ قبل النشر
  • 🔒
    تخزين التوكن بأمان: لا تحفظ الـ Token في نص صريح (Plaintext) أو SharedPreferences. استخدم Android Keystore أو iOS Keychain حصراً.
  • 🚫
    حظر Hardcoded Keys: لا تضع أي بيانات حساسة ثابتة داخل الكود المصدري. يجب جلبها من endpoint آمن عند الحاجة.
  • 🌐
    فرض HTTPS: يُمنع استخدام HTTP العادي. فعّل SSL Pinning لمنع هجمات MITM (رجل المنتصف).
  • 📱
    فحص كسر الحماية: فعّل Root/Jailbreak Detection لمنع استخراج التوكنز من ذاكرة الجهاز المخترق.
  • ⏱️
    انتهاء الجلسة: نفّذ منطق تسجيل الخروج التلقائي عند عدم النشاط وامسح التوكن المحلي عند الخروج.
  • 🔍
    التحقق من المدخلات: تحقق من جميع المدخلات على جانب العميل قبل إرسالها وعلى جانب الخادم (الخادم يتحقق دائماً بالفعل).

📊 رموز حالة الاستجابة

200 OK 201 Created 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 500 Server Error
الكودالمعنىالحالة الشائعة
200نجاح العمليةأي طلب ناجح
400بيانات خاطئة أو رصيد غير كافٍsubscribe, renew, recharge
401التوكن منتهي أو غير صالحأي endpoint محمي
403الميزة غير مفعّلة في الترخيصlogin, deposit
404العنصر غير موجودplans, invoices/{id}
422بيانات التحقق فاشلة (Validation)كل طلبات POST
500خطأ داخلي في الخادمنادر جداً

🌐 المسارات العامة (بدون مصادقة)

GET /api/subscriber/system-info معلومات النظام العامة — عام، بدون توكن

يُستدعى عند تشغيل التطبيق لأول مرة لجلب اسم الشبكة، الشعار، معلومات التواصل، وآخر إصدار للتطبيق.

الاستجابة الناجحة (200)
{ "app_name": "تك نت", "logo_url": "https://domain.com/storage/logo.png", "license_key": "TKN-XXXX-XXXX", "support_contacts": [ { "name": "الدعم الفني", "phone": "0900000000" } ], "latest_version": { "version_code": 41, "version_name": "4.1.0", "url": "https://...", "force_update": false }, "permissions": { "allow_edit_name": true, "allow_edit_phone": true, "allow_edit_password": true }, "status": "success" }
POST /api/subscriber/login تسجيل الدخول بالاسم وكلمة المرور
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
usernamestringاسم المستخدم أو رقم الهاتفمطلوب
passwordstringكلمة المرورمطلوب
device_namestringاسم أو معرّف الجهاز لفصل جلسات متعددةاختياري
الاستجابة الناجحة (200)
{ "message": "تم تسجيل الدخول بنجاح", "token": "a7f3d...c9e2", // احفظه في Keychain/Keystore "subscriber": { "id": 42, "name": "أحمد محمد", "username": "user123", "phone": "01001234567", "is_active": true } }
⚠️
استخدم الـ token في كل الطلبات التالية عبر ترويسة: Authorization: Bearer {token}
POST /api/subscriber/auto-login دخول تلقائي بالـ IP (الشبكة المحلية فقط)
ℹ️
يعمل فقط عندما يكون المستخدم متصلاً بالشبكة ولديه جلسة RADIUS نشطة. يطابق الخادم الـ IP المرسل مع جلسات NAS الفعالة — لا يمكن تزييفه من الخارج.
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
device_namestringاسم الجهاز للتمييزاختياري
الاستجابة الناجحة (200)
{ "message": "تم تسجيل الدخول تلقائياً", "token": "...", "subscriber": { /* بيانات المشترك */ } }

🔑 المصادقة (Auth)

GET /api/subscriber/me 🔐 Auth بيانات الحساب الكاملة للمشترك المسجّل

يُرجع كائن JSON بجميع بيانات المشترك الحالي بما في ذلك الحقول المخصصة.

POST /api/subscriber/logout 🔐 Auth تسجيل خروج وإلغاء التوكن الحالي

يحذف التوكن من قاعدة البيانات ويُبطل أي طلبات مستقبلية باستخدامه. لا يتطلب Body.

{ "message": "تم تسجيل الخروج بنجاح" }
POST /api/subscriber/hotspot-logout 🔐 Auth قطع اتصال RADIUS وإلغاء تصريح MAC
⚠️
يقطع جلسة RADIUS الحالية ويحذف MAC Address المسجّل ويضع الحساب في وضع Reject. مخصص لبيئات Hotspot.

🏠 لوحة التحكم والتحكم السريع

GET /api/subscriber/dashboard 🔐 Auth الصفحة الرئيسية الكاملة
الاستجابة الناجحة (200)
{ "subscriber": { "id": 42, "name": "أحمد", "balance": 150.00, "currency_symbol": "SYP", "is_paused": false, "allow_manual_pause": true, "has_pause_password": true, "is_dashboard_locked": false, "speed_control": { "allow_speed_customization": true, "max_increase_pct": 50, "max_decrease_pct": 25, "current_percentage": 0 } }, "subscription": { "current_plan": "باقة 4 ميجا الشهرية", "status": "active", "expires_at": "2026-08-01 00:00:00", "remaining_data_bytes": 10737418240, // -1 = غير محدود "total_data_bytes": 53687091200, "used_data_bytes": 42949672960, "usage_percentage": 80, "remaining_days": 31, "download_speed": "4 Mbps", "plan_type": "postpaid", "daily_usage": { "has_daily_limit": true, "used_bytes": 1073741824, "limit_bytes": 5368709120, "percentage": 20 } }, "session": { "is_online": true, "ip_address": "192.168.1.5" } }
POST /api/subscriber/renew 🔐 Auth تجديد الباقة الحالية (مع دعم العروض)
الحقلالنوعالوصفالحالة
cyclesintegerعدد دورات التجديد (افتراضي: 1)اختياري
{ "message": "تم تجديد الباقة بنجاح", "invoice": { "id": 88, "invoice_number": "INV-...", "total_amount": 5000 } }
POST /api/subscriber/voucher/redeem 🔐 Auth استرداد كوبون خصم لتفعيل باقة مجانية أو شحن رصيد الكارت
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
voucher_codestringرمز الكارت / الكوبون (6 أرقام على الأقل)مطلوب
الاستجابة الناجحة (200)
{ "message": "تم استرداد الكوبون وتفعيل الاشتراك بنجاح", "new_balance": 500.00 }
POST /api/subscriber/speed/update 🔐 Auth رفع أو خفض سرعة الخط (إذا مسموح)
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
speed_percentageintegerنسبة تعديل السرعة (مثال: 50 لرفع السرعة بمقدار 50%، أو -25 لخفض السرعة بمقدار 25%)مطلوب
الاستجابة الناجحة (200)
{ "message": "تم تحديث سرعة الاتصال بنجاح." }
POST /api/subscriber/internet/toggle 🔐 Auth إيقاف / تشغيل الإنترنت يدوياً (التحكم الأبوي الفوري)
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
actionstringنوع الإجراء: pause لفصل الخدمة، أو resume لإعادة تشغيلهامطلوب
passwordstringرمز PIN لحماية الفصل والوصل (إلزامي إذا تم تعيين رمز سابق، وإذا كانت هذه أول مرة تقوم بالفصل فسيتم حفظ هذا الرمز كرمز PIN جديد للحساب)اختياري / إلزامي
الاستجابة الناجحة (200)
{ "message": "تم فصل الإنترنت بنجاح.", "is_paused": true, "paused_at": "2026-07-01 21:55:00", "has_pause_password": true }
POST /api/subscriber/internet/verify-password 🔐 Auth التحقق من رمز PIN قبل السماح بالإيقاف/التشغيل
المدخلات (Body JSON)
الحقلالنوعالوصفالحالة
passwordstringرمز PIN المراد التحقق منهمطلوب
الاستجابة الناجحة (200)
{ "success": true }
POST /api/subscriber/internet/schedule 🔐 Auth التحكم الأبوي وجدولة الوصول إلى الإنترنت

قم بإرسال طلب GET لمعرفة حالة الجدول والرقابة الأبوية الحالية، أو طلب POST لتحديث إعدادات الجدولة والتحكم بالإنترنت.

المدخلات لطلب POST (Body JSON)
الحقلالنوعالوصفالحالة
typestringنوع الجدولة: none (إلغاء)، instant (تحكم فوري)، routine (روتيني يومي/أسبوعي)، once (لمرة واحدة فقط)، vacation (فترة إجازة)مطلوب
passwordstringالرمز السري PIN لحماية الإعدادات (إذا تم تعيينه مسبقاً)اختياري
start_timestringوقت بدء القطع بصيغة 24 ساعة (مثال: 22:00)مطلوب للـ routine/once
end_timestringوقت انتهاء القطع بصيغة 24 ساعة (مثال: 07:00)مطلوب للـ routine/once
datestringتاريخ القطع بصيغة YYYY-MM-DDمطلوب للـ once
routine_daysarrayمصفوفة بالأيام المطبق عليها القطع الروتيني (مثال: ["friday", "saturday"])مطلوب للـ routine
vacation_startstringتاريخ ووقت بدء إجازة قطع الاتصال (مثال: 2026-07-01 12:00:00)مطلوب للـ vacation
vacation_endstringتاريخ ووقت انتهاء إجازة قطع الاتصال (مثال: 2026-07-15 12:00:00)مطلوب للـ vacation
مثال استجابة تحديث الجدول (200)
{ "message": "تم حفظ إعدادات الرقابة الأبوية بنجاح.", "mode": "routine", "data": { "type": "routine", "routine_days": ["friday", "saturday"], "start_time": "22:00", "end_time": "07:00" } }

📦 الباقات والاشتراكات

GET /api/subscriber/plans 🔐 Auth كتالوج الباقات المتاحة للمشترك

يُرجع مصفوفة بجميع الباقات المتاحة للمشترك (المرئية، المناسبة لإدارته) مع السعر المحسوب والمدة بالأيام.

[ { "id": 12, "name": "باقة 4 ميجا شهرية", "price": 5000.0, "description": "سرعة 4 ميجا بتنزيل غير محدود مع خفض سرعة بعد الكوتا", "formatted_download_speed": "4 Mbps", "formatted_upload_speed": "1 Mbps", "type_label": "مسبق الدفع", "type_badge_color": "success", "formatted_total_traffic_limit": "50 GB" } ]
GET /api/subscriber/current-plan 🔐 Auth الباقة الحالية المشترك بها مع تفاصيل الاشتراك
{ "plan": { "id": 12, "name": "...", "price": 5000 }, "subscription": { "status": "active", "expires_at": "..." } }
GET /api/subscriber/plans/simulate 🔐 Auth محاكاة تكلفة الترقية قبل الاشتراك الفعلي

يُستخدم لعرض التكلفة المتوقعة للمشترك إذا انتقل لباقة معينة (مع الأخذ بعين الاعتبار الرصيد الحالي والخصومات).

Query Paramالنوعالوصفالحالة
plan_idintegerرقم الباقة المراد المحاكاةمطلوب
POST /api/subscriber/subscribe 🔐 Auth الاشتراك في باقة جديدة أو التغيير للباقة
الحقلالنوعالوصفالحالة
plan_idintegerرقم الباقة من كتالوج الباقاتمطلوب
⚠️
يُخصم التكلفة فوراً من المحفظة وينشئ فاتورة. تأكد من رصيد كافٍ قبل الاستدعاء.

💰 المحفظة والفواتير

GET /api/subscriber/wallet 🔐 Auth رصيد المحفظة وتاريخ المعاملات المالية
{ "balance": 1500.00, "currency_symbol": "SYP", "transactions": { "data": [ { "id": 1, "type": "credit", "amount": 5000, "description": "شحن كارت", "created_at": "..." } ], "current_page": 1, "last_page": 5, "per_page": 20 } }
GET /api/subscriber/wallet/methods 🔐 Auth طرق الدفع والإيداع الإلكتروني المتاحة

يُرجع قائمة بطرق الإيداع المفعّلة (فودافون كاش، بنوك، إلخ) مع أرقام التواصل والحد الأدنى/الأقصى لكل طريقة.

POST /api/subscriber/wallet/recharge 🔐 Auth شحن المحفظة بكارت خدش
الحقلالنوعالوصفالحالة
codestringكود الكارت (أرقام فقط، موجود في جدول vouchers)مطلوب
{ "message": "تم شحن الكارت بنجاح", "new_balance": 6500.00 }
POST /api/subscriber/wallet/deposit 🔐 Auth طلب إيداع إلكتروني (فودافون كاش، إلخ)
ℹ️
يتطلب تفعيل ميزة electronic_payment_services في ترخيص النظام.
الحقلالنوعالوصفالحالة
phonestringرقم المحفظة المحوَّل منها (صيغة مصرية: 01XXXXXXXXX)مطلوب
amountnumericالمبلغ المراد إيداعه (الحد الأدنى 1)مطلوب
GET /api/subscriber/invoices 🔐 Auth قائمة الفواتير الخاصة بالمشترك

يُرجع جميع فواتير المشترك مرتبة من الأحدث للأقدم.

GET /api/subscriber/invoices/{invoice_id} 🔐 Auth تفاصيل فاتورة محددة مع بنودها

استبدل {invoice_id} برقم الفاتورة. يُرجع الفاتورة مع بنودها (items) إذا كانت تتبع للمشترك الحالي.

📊 إحصائيات الاستهلاك (Usage)

GET /api/subscriber/usage/history 🔐 Auth إجمالي الاستهلاك الشهري (آخر 12 شهر)
[ { "year": 2026, "month": 7, "total_upload": 1073741824, "total_download": 5368709120 }, { "year": 2026, "month": 6, "total_upload": 804000000, "total_download": 4100000000 } ]
GET /api/subscriber/usage/daily 🔐 Auth استهلاك يومي تفصيلي لفترة محددة
Query Paramالنوعالوصفالحالة
start_datedateبداية الفترة (YYYY-MM-DD)، الافتراضي: بداية الشهر الحالياختياري
end_datedateنهاية الفترة (YYYY-MM-DD)، الافتراضي: نهاية الشهر الحالياختياري
{ "period": { "start": "2026-07-01", "end": "2026-07-31" }, "daily_usage": [ { "date": "2026-07-01", "upload_bytes": 104857600, "download_bytes": 524288000, "total_bytes": 629145600 } ] }
GET /api/subscriber/usage/summary 🔐 Auth ملخص إجمالي مع عدد الجلسات ومدتها
Query Paramالنوعالوصف
start_datedateاختياري، YYYY-MM-DD
end_datedateاختياري، YYYY-MM-DD
{ "upload": 1073741824, // إجمالي الرفع بالبايت "download": 5368709120, // إجمالي التنزيل بالبايت "duration": 86400, // إجمالي وقت الاتصال بالثانية "sessions_count": 15 // عدد الجلسات }
GET /api/subscriber/usage/sessions 🔐 Auth آخر 50 جلسة RADIUS للمشترك

يُرجع مصفوفة بآخر 50 سجل RADIUS تشمل وقت الاتصال، الانقطاع، البايتات المستهلكة، والـ IP المُعيَّن.

🔌 الخدمات الإضافية (Addons & Loans)

GET /api/subscriber/services 🔐 Auth الإضافات والقروض المتاحة للمشترك
{ "addons": [ { "id": 5, "name": "10 GB إضافية", "price": 2000.0, "loan_amount": 0.0, "description": "صلاحية الباقة الإضافية 7 أيام", "data_limit": 10.0, "duration_days": 7 } ], "loans": [ { "id": 7, "name": "سلفة اليوم", "price": 500.0, "loan_amount": 500.0, "description": "قرض بقيمة 500 يخصم عند أول عملية شحن", "data_limit": null, "duration_days": 1 } ] }
POST /api/subscriber/services/subscribe 🔐 Auth تفعيل إضافة أو طلب قرض
الحقلالنوعالوصفالحالة
package_idintegerمعرّف الإضافة/القرض من قائمة الخدماتمطلوب

👤 الملف الشخصي والإعدادات

POST /api/subscriber/profile/update 🔐 Auth تحديث الاسم أو رقم الهاتف أو كلمة المرور
⚠️
تحديث كلمة المرور يُحدّث كذلك كلمة المرور في قاعدة RADIUS تلقائياً. جميع الحقول اختيارية، أرسل فقط ما تريد تغييره.
الحقلالنوعالوصفالحالة
namestringالاسم الكامل (max: 255)اختياري
phonestringرقم الهاتف (يجب أن يكون فريداً)اختياري
passwordstringكلمة المرور الجديدة (min: 6 أحرف)اختياري
GET /api/subscriber/profile/notifications 🔐 Auth آخر 50 إشعار مرسل للمشترك

يُرجع سجل الرسائل والإشعارات المرسلة للمشترك (SMS، WhatsApp) مرتبة من الأحدث.

GET /api/subscriber/settings/support 🔐 Auth إعدادات خيارات التواصل مع الدعم

يُرجع معلومات خيارات الدعم الفني المتاحة للمشترك (WhatsApp، هاتف، تذاكر إلكترونية).

🎫 الدعم الفني (Support Tickets)

GET /api/subscriber/support/departments 🔐 Auth قائمة أقسام الدعم المتاحة
[ { "id": 1, "name": "الدعم الفني", "icon": "🔧", "color": "#3b82f6" }, { "id": 2, "name": "المبيعات", "icon": "💬", "color": "#10b981" } ]
GET /api/subscriber/support/tickets 🔐 Auth قائمة تذاكر المشترك مع فلترة وبحث
Query Paramالنوعالوصفالحالة
statusstringopen / closed / أي حالة محددةاختياري
searchstringبحث في العنوان أو رقم التذكرةاختياري
POST /api/subscriber/support/tickets 🔐 Auth فتح تذكرة دعم فني جديدة
الحقلالنوعالوصفالحالة
titlestringعنوان المشكلة (5–200 حرف)مطلوب
descriptionstringتفاصيل المشكلة (10 أحرف على الأقل)مطلوب
department_idintegerرقم القسم من قائمة الأقساممطلوب
prioritystringlow / medium / high / criticalاختياري
{ "title": "انقطاع الإنترنت منذ الصباح", "description": "الإنترنت يقطع كل ١٠ دقائق...", "department_id": 1, "priority": "high" }
GET /api/subscriber/support/tickets/{id} 🔐 Auth تفاصيل تذكرة مع جميع الرسائل

يُرجع بيانات التذكرة كاملةً مع مصفوفة الرسائل والردود والأنشطة مرتبة زمنياً.

POST /api/subscriber/support/tickets/{id}/reply 🔐 Auth إرسال رد على تذكرة مفتوحة
الحقلالنوعالوصفالحالة
messagestringنص الرد (10 أحرف على الأقل)مطلوب
POST /api/subscriber/support/tickets/{id}/close 🔐 Auth إغلاق تذكرة وإنهاء طلب الدعم

لا يتطلب Body. يُغيّر حالة التذكرة إلى closed ولا يمكن إعادة فتحها.

📰 المجلة الرقمية (Magazine)

ℹ️
جميع مسارات المجلة تبدأ بـ /api/subscriber/magazine/ وتتطلب مصادقة وتفعيل ميزة المجلة في الترخيص.
GET /api/subscriber/magazine/status 🔐 Auth حالة المجلة الرقمية وتوافر المحتوى

يُرجع ما إذا كانت المجلة مفعّلة لهذا المشترك وإحصائيات عامة.

GET /api/subscriber/magazine/categories 🔐 Auth قائمة فئات المحتوى الرقمي

أفلام، مسلسلات، برامج، أطفال... إلخ.

GET /api/subscriber/magazine/items 🔐 Auth قائمة المحتوى مع تصفية حسب الفئة
Query Paramالنوعالوصف
category_idintegerفلترة حسب الفئة (اختياري)
searchstringبحث في عنوان المحتوى (اختياري)
GET /api/subscriber/magazine/stream 🔐 Auth رابط التشغيل المباشر للمحتوى
Query Paramالنوعالوصف
item_idintegerمعرّف العنصر المراد تشغيله
ℹ️
يمكن إرسال heartbeat دوري عبر POST /api/subscriber/magazine/heartbeat لتسجيل وقت المشاهدة.

🛠️ دليل دمج تطبيقات الهواتف والأنظمة (Integration Guide)

يوفر هذا القسم أمثلة عملية جاهزة للاستخدام في تطبيقات الهواتف الذكية (Android Kotlin) والإطارات الهجينة (Flutter) والأنظمة البرمجية الأخرى لتسهيل عملية الربط بأفضل الممارسات البرمجية والأمنية.

1. إعداد الـ Service Interface (Retrofit)

يتطابق هذا مع الملف ApiService.kt الموجود في تطبيق المشتركين الفعلي:

interface ApiService { @POST("subscriber/login") @FormUrlEncoded suspend fun login( @Field("username") identifier: String, @Field("password") pass: String ): Response<LoginResponse> @GET("subscriber/dashboard") suspend fun getDashboard(): Response<DashboardResponse> }

2. إعداد الـ Interceptor لإضافة التوكن تلقائياً

يستخدم لإرفاق ترويسة المصادقة بجميع الطلبات الصادرة تلقائياً:

class AuthInterceptor(private val context: Context) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() // جلب التوكن من مخزن آمن (EncryptedSharedPreferences أو Android Keystore) val token = getSecureToken(context) val requestBuilder = originalRequest.newBuilder() .header("Accept", "application/json") if (!token.isNullOrEmpty()) { requestBuilder.header("Authorization", "Bearer $token") } val response = chain.proceed(requestBuilder.build()) // التعامل مع انتهاء التوكن (401 Unauthorized) if (response.code == 401) { handleUnauthorized(context) } return response } }

1. إعداد Dio Client مع Interceptor

طريقة احترافية لتهيئة مكتبة Dio وتمرير التوكن في Flutter:

import 'package:dio/dio.dart'; class ApiClient { final Dio dio = Dio(BaseOptions( baseUrl: "https://your-server-ip/api/subscriber/", connectTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10), headers: { "Accept": "application/json", } )); ApiClient() { dio.interceptors.add(InterceptorsWrapper( onRequest: (options, handler) async { // جلب التوكن المحفوظ بأمان final token = await getSecureToken(); if (token != null) { options.headers["Authorization"] = "Bearer $token"; } return handler.next(options); }, onError: (DioException e, handler) { if (e.response?.statusCode == 401) { // توجيه المستخدم لصفحة تسجيل الدخول وإلغاء التوكن triggerLogoutRedirect(); } return handler.next(e); } )); } }

1. هيكلية كلاس الـ PHP SDK (جاهز للنسخ والتشغيل)

يوفر هذا الكلاس تغليفاً (Wrapper) كاملاً للربط الآمن وسهل التنفيذ مع خادم FreeNet:

<?php class FreeNetSubscriberSDK { private $baseUrl; private $token; public function __construct($baseUrl, $token = null) { $this->baseUrl = rtrim($baseUrl, '/') . '/'; $this->token = $token; } public function setToken($token) { $this->token = $token; } public function getToken() { return $this->token; } private function request($method, $endpoint, $data = null) { $ch = curl_init(); $url = $this->baseUrl . ltrim($endpoint, '/'); $headers = ['Accept: application/json']; if ($this->token) { $headers[] = 'Authorization: Bearer ' . $this->token; } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); if ($method !== 'GET' && $data) { $headers[] = 'Content-Type: application/json'; curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $decoded = json_decode($response, true); return [ 'code' => $httpCode, 'success' => ($httpCode >= 200 && $httpCode < 300), 'data' => $decoded ]; } public function login($username, $password, $deviceName = 'PHP SDK') { $res = $this->request('POST', 'login', ['username' => $username, 'password' => $password, 'device_name' => $deviceName]); if ($res['success'] && isset($res['data']['token'])) { $this->setToken($res['data']['token']); } return $res; } public function getDashboard() { return $this->request('GET', 'dashboard'); } public function rechargeCard($code) { return $this->request('POST', 'wallet/recharge', ['code' => $code]); } public function getWallet() { return $this->request('GET', 'wallet'); } public function getUsageHistory() { return $this->request('GET', 'usage/history'); } }

2. مثال التشغيل الفعلي (تسجيل، رصيد، شحن كرت، استهلاك)

مثال توضيحي للربط المتكامل مع الأنظمة الأخرى في بضع أسطر:

// تهيئة الـ SDK برابط السيرفر $sdk = new FreeNetSubscriberSDK("https://192.168.5.55/api/subscriber/"); // 1. تسجيل الدخول بجلب التوكن $login = $sdk->login("ahmed_user", "password123"); if ($login['success']) { echo "تم الاتصال بنجاح!\n"; // 2. قراءة بيانات لوحة التحكم والرصيد $dashboard = $sdk->getDashboard(); $sub = $dashboard['data']['subscriber']; echo "اسم العميل: " . $sub['name'] . "\n"; echo "الرصيد الحالي: " . $sub['balance'] . " " . $sub['currency_symbol'] . "\n"; // 3. شحن كارت خدش مباشرة $recharge = $sdk->rechargeCard("8877665544"); if ($recharge['success']) { echo "تم شحن الكارت! الرصيد الجديد: " . $recharge['data']['new_balance'] . "\n"; } // 4. استخراج الاستهلاك التاريخي $history = $sdk->getUsageHistory(); foreach ($history['data'] as $usage) { echo "الشهر: " . $usage['month'] . " -> استهلاك: " . ($usage['total_download'] / (1024*1024)) . " MB\n"; } } else { echo "فشل الربط: " . $login['data']['message'] . "\n"; }

Python Integration Example

import requests BASE_URL = "https://your-server-ip/api/subscriber" TOKEN = "your_bearer_token_here" headers = { "Accept": "application/json", "Authorization": f"Bearer {TOKEN}" } # طلب بيانات الصفحة الرئيسية response = requests.get(f"{BASE_URL}/dashboard", headers=headers) if response.status_code == 200: data = response.json() print(f"Subscriber Name: {data['subscriber']['name']}") else: print(f"Error: {response.status_code} - {response.text}")

Node.js (Axios) Example

const axios = require('axios'); const client = axios.create({ baseURL: 'https://your-server-ip/api/subscriber', headers: { 'Accept': 'application/json', 'Authorization': 'Bearer your_bearer_token_here' } }); client.get('/dashboard') .then(res => console.log('Data:', res.data)) .catch(err => console.error('Error:', err.response ? err.response.data : err.message));