Vio eSIM
REST API · v1

مرجع واجهة برمجة تطبيقات Vio eSIM

واجهتان REST على نفس الخلفية: واجهة برمجة التطبيقات الموجهة للعملاء التي تشغّل تطبيق الويب وتطبيقي iOS وAndroid، وواجهة برمجة تطبيقات شركاء منفصلة موثّقة بمفتاح API لإعادة بيع Vio eSIM برمجياً.

واجهة الجوال / الويب
https://vioesim.com/api/v1
واجهة الشركاء
https://vioesim.com/api/public/v1

مصادقة تطبيق الجوال

يشترك تطبيق الويب والتطبيق الأصلي في نفس نظام الجلسات — يحتفظ التطبيق الأصلي بالرمز نفسه بدلاً من الاعتماد على مخزن ملفات تعريف الارتباط.

التسجيل أو تسجيل الدخول. تُعيد كلتا نقطتي النهاية حقل token مع كائن المستخدم (بالإضافة إلى ترويسة Set-Cookie التي يستخدمها تطبيق الويب بدلاً منه). خزّن token في Keychain (لنظام iOS) أو مخزن مدعوم بـ Keystore (لنظام Android).

مع كل طلب، أعد إرساله:

Authorization: Bearer <token>

صلاحية الرمز: 30 يوماً من الإصدار، أو حتى استدعاء /api/v1/auth/logout. لا توجد خطوة لرمز التحديث — يُستبدل الرمز القريب من الانتهاء ببساطة بجعل المستخدم يسجّل الدخول مرة أخرى.

تتوقف جلسات الحسابات المعلّقة أو المحظورة أو المحذوفة عن العمل فوراً حتى لو لم ينتهِ الرمز نفسه — يتم التحقق من ذلك من جهة الخادم مع كل طلب.

مصادقة واجهة برمجة تطبيقات الشركاء

مخصصة للشركات الخارجية التي تعيد بيع Vio eSIM عبر موقعها أو تطبيقها الخاص. الشريك هو حساب Vio eSIM عادي: أنشئ مفتاحاً من لوحة التحكم ← مفاتيح API (يُعرض مرة واحدة فقط — احفظه، لن تتمكن من رؤيته مجدداً)، ثم أرسله مع كل طلب:

Authorization: Bearer vio_live_sk_...
# or
X-API-Key: vio_live_sk_...

يؤدي إنشاء مفتاح جديد إلى إبطال المفتاح السابق فوراً.

نموذج الفوترة: يتم خصم طلبات واجهة برمجة تطبيقات الشركاء بشكل متزامن من رصيد محفظة الحساب المدفوعة مسبقاً — وبما أن هذا استدعاء من خادم إلى خادم، فلا توجد إعادة توجيه للدفع. أضف رصيداً عبر لوحة التحكم (بطاقة/عملة رقمية) قبل تقديم الطلبات. عند عدم كفاية الرصيد، يُعيد POST /orders الرمز 402.

البدء السريع — واجهة برمجة تطبيقات الشركاء

تصفّح الكتالوج واشترِ eSIM في استدعاءين اثنين:

curl https://vioesim.com/api/public/v1/destinations \
  -H "Authorization: Bearer vio_live_sk_..."

curl -X POST https://vioesim.com/api/public/v1/orders \
  -H "Authorization: Bearer vio_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "planId": "cus...", "quantity": 1 }'

الأخطاء وحدود المعدل

تُعيد واجهة الجوال/الويب { "error": "رسالة" } (الرسائل حالياً بالتركية). تُعيد واجهة الشركاء تنسيقاً منظماً حتى تتمكن من التفريع بناءً على code:

{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Insufficient wallet balance." } }
الحالةالمعنى
401الرمز أو مفتاح API مفقود أو غير صالح أو منتهي الصلاحية
402واجهة الشركاء فقط — رصيد المحفظة غير كافٍ
404المورد غير موجود، أو لا يملكه المستدعي
409تعارض في الحالة (مثل حذف حساب برصيد غير صفري)
429تم بلوغ حد المعدل — راجع ترويسة Retry-After (بالثواني)
502تم تحصيل الرسوم لكن فشل تزويد eSIM — لا تُعِد التحصيل

حدود المعدل (واجهة الشركاء): القراءة 120 طلباً في الدقيقة لكل مفتاح، وPOST /orders بحد 30 طلباً في الدقيقة.

واجهة الجوال / الويب

المصادقة

POST/api/v1/auth/registerلا حاجة للمصادقة

التسجيل

ينشئ حساباً وجلسة نشطة.

Request body
{
  "firstName": "Ada",
  "lastName": "Lovelace",
  "email": "[email protected]",
  "password": "min 8 chars"
}
200 OK
{
  "success": true,
  "user": {
    "id", "firstName", "lastName", "fullName", "email",
    "emailVerified", "walletBalance", "currency", "locale", "createdAt"
  },
  "token": "..."
}
POST/api/v1/auth/loginلا حاجة للمصادقة

تسجيل الدخول

النص: { email, password }. نفس تنسيق استجابة التسجيل. الرمز 401 عند بيانات اعتماد خاطئة، و403 عند تعليق الحساب.

POST/api/v1/auth/logoutرمز الجلسة

تسجيل الخروج

بلا نص. يحذف الجلسة من جهة الخادم — استدعِه عند تسجيل الخروج الفعلي، وليس مجرد "نسيان الرمز محلياً"، حتى لا يستمر عمل رمز مسروق.

GET/api/v1/auth/meرمز الجلسة · اختياري

المستخدم الحالي

يُعيد { "user": null } عند تسجيل الخروج (وهذا ليس خطأ أبداً) — استخدمه لتحديد ما إذا كان سيتم عرض شاشة تسجيل الدخول عند بدء التطبيق.

POST/api/v1/auth/forgot-passwordلا حاجة للمصادقة

نسيت كلمة المرور

النص: { email, locale }. يُعيد دائماً { success: true } بغض النظر عن وجود العنوان، لمنع تعداد الحسابات. يُرسل بريداً إلكترونياً برابط/رمز إعادة تعيين (صالح لمدة ساعة).

POST/api/v1/auth/reset-passwordلا حاجة للمصادقة

إعادة تعيين كلمة المرور

النص: { token, newPassword }. يمكن لطلب GET مع ?token= التحقق من الصلاحية قبل عرض النموذج ({ "valid": true|false }).

POST/api/v1/auth/change-passwordرمز الجلسة

تغيير كلمة المرور

النص: { currentPassword, newPassword }. currentPassword مطلوب ما لم يكن الحساب بلا كلمة مرور بعد (مثل تسجيل الدخول الاجتماعي).

الحساب

PATCH/api/v1/user/profileرمز الجلسة

تحديث الملف الشخصي

أرسل فقط الحقول التي تريد تغييرها.

FieldNotes
firstName, lastNameاختياري · نص
preferredCurrencyاختياري · واحدة من USD أو EUR أو GBP أو TRY
localeاختياري · رمز من حرفين، مثل ar
200 OK
{ "success": true, "user": { ...same shape as /auth/me } }
POST/api/v1/user/avatarرمز الجلسة

تحديث الصورة الرمزية

النص: { "avatarUrl": "data:image/..." } — عنوان بيانات base64، بحد أقصى ~1.5 ميغابايت.

POST/api/v1/user/api-key/generateرمز الجلسة

إنشاء مفتاح API

يصدر مفتاح واجهة شركاء جديداً لهذا الحساب، ليحل محل المفتاح السابق. يُعرض المفتاح الأصلي مرة واحدة فقط في هذه الاستجابة — لاحقاً يمكن استرجاع بادئته فقط.

200 OK
{
  "success": true,
  "key": "vio_live_sk_...",
  "apiKeyPrefix": "vio_live_sk_ab12…9f8e",
  "apiKeyGeneratedAt": "2026-08-22T17:00:00.781Z"
}
DELETE/api/v1/user/accountرمز الجلسة

حذف الحساب

مطلوب لمراجعة App Store (يجب على التطبيقات التي توفر إنشاء حسابات أن توفر حذفاً داخل التطبيق). يُخفي هوية الحساب (يُخلط البريد الإلكتروني ويُترك متاحاً لإعادة التسجيل، وتُمسح الاسم/الصورة الرمزية/كلمة المرور) بدلاً من حذف السجلات نهائياً، حتى تبقى الطلبات السابقة لأغراض السجلات الضريبية/المحاسبية. يُتلف جميع جلسات المستخدم وأجهزة الإشعارات الفورية المسجّلة.

يُعيد 409 إذا كان walletBalance أكبر من 0 — يجب على التطبيق توجيه المستخدم للسحب أولاً أو التواصل مع الدعم بدلاً من فقدان الأموال بصمت.

الكتالوج

GET/api/v1/destinationsلا حاجة للمصادقة

جلب قائمة الوجهات

الدول والمناطق ذات الباقات الصالحة، مُسعّرة ومُنسّقة لواجهة المستخدم (وهذا بالضبط ما يستدعيه المتجر نفسه). اختياري ?filter=popular|regional|global|<نص بحث>.

GET/api/v1/destinations/:codeلا حاجة للمصادقة

تفاصيل الوجهة

التفاصيل الكاملة لدولة واحدة بواسطة رمز ISO (الوصف، الباقات)، مثل /api/v1/destinations/jp.

المشتريات

POST/api/v1/checkoutرمز الجلسة

الدفع

يشتري باقة مباشرة بدلاً من إضافة رصيد للمحفظة أولاً.

FieldNotes
planId*
quantityاختياري · 1–10، الافتراضي 1
paymentMethod*wallet | stripe | crypto
successUrl, cancelUrlاختياري · لإعادة توجيه stripe/crypto. استخدم رابطاً عالمياً/رابط تطبيق بدلاً من عنوان ويب عادي حتى تعيد إعادة التوجيه فتح التطبيق.
200 OK — wallet (synchronous)
{ "success": true, "orderId": "..." }
200 OK — stripe / crypto (redirect required)
{ "success": true, "orderId": "...", "url": "https://checkout.stripe.com/..." }
افتح url في متصفح داخل التطبيق (SFSafariViewController / Chrome Custom Tabs) وليس في WebView عادي — يتطلب كل من Stripe وCryptomus سياق متصفح حقيقي.
POST/api/v1/payments/stripe/create-sessionرمز الجلسة

إيداع في المحفظة عبر Stripe

يضيف رصيداً إلى المحفظة عبر البطاقة — تدفق منفصل عن الدفع. النص: { amount (بالسنت، الحد الأدنى 200)، currency، successUrl، cancelUrl }. يُعيد { sessionId، url }.

POST/api/v1/payments/cryptomus/create-invoiceرمز الجلسة

إيداع في المحفظة عبر العملات الرقمية

النص: { amount (نص عشري، الحد الأدنى 2$)، currency، url_return }. يُعيد كائن فاتورة Cryptomus يحتوي على url.

GET/api/v1/user/ordersرمز الجلسة

قائمة الطلبات

جميع طلبات المستدعي، من الأحدث إلى الأقدم.

GET/api/v1/user/orders/:idرمز الجلسة

تفاصيل الطلب

طلب واحد يحتوي على esimIds — استخدم GET /api/v1/user/esims لجلب تفاصيل eSIM الكاملة (رمز QR، رمز التفعيل) والمطابقة بواسطة id.

GET/api/v1/user/esimsرمز الجلسة

شرائح eSIM الخاصة بي

كل eSIM يملكه المستدعي: iccid، activationCode، qrCodeUrl، smdpAddress، status، dataUsage/totalVolume (ميغابايت)، activatedAt، expiresAt. هذه هي البيانات التي تشغّل شاشة "شرائحي" وعرض رمز QR.

GET/api/v1/user/wallet/transactionsرمز الجلسة

سجل المحفظة

سجل الإيداعات/السحوبات/المشتريات/المبالغ المستردة وراء رصيد المحفظة المعروض في /auth/me.

الدعم

GET/api/v1/support/ticketsرمز الجلسة

قائمة التذاكر

تذاكر المستدعي وسلاسل رسائلها الكاملة، من الأحدث إلى الأقدم.

POST/api/v1/support/ticketsرمز الجلسة

تذكرة جديدة

النص: { subject، category، message } (category اختياري).

POST/api/v1/support/tickets/:id/messagesرمز الجلسة

الرد على تذكرة

النص: { message }. الرد على تذكرة بحالة RESOLVED/CLOSED يعيد فتحها تلقائياً.

أجهزة الإشعارات الفورية

يتعامل هذا فقط مع تسجيل رمز الجهاز — يتطلب الإرسال الفعلي بيانات اعتماد APNs/FCM. راجع الملاحظة أدناه.

POST/api/v1/user/push-devicesرمز الجلسة

تسجيل جهاز

استدعِ هذا بعد الحصول على رمز APNs أو FCM. النص: { platform: "IOS"|"ANDROID"، pushToken، appVersion }. يتم التحديث أو الإدراج بحسب الرمز، لذا فإن استدعاءه مجدداً مع كل بدء تشغيل للتطبيق آمن ومُوصى به (قد تتغير الرموز).

DELETE/api/v1/user/push-devicesرمز الجلسة

إلغاء تسجيل جهاز

النص: { pushToken }. استدعِه عند تسجيل الخروج لمنع الأجهزة المشتركة/المعاد ضبطها من الاستمرار في تلقي إشعارات مستخدمين آخرين.

واجهة الشركاء

تتطلب جميع نقاط النهاية أدناه ترويسة مفتاح API الموضحة أعلاه — لا تُطبَّق ملفات تعريف ارتباط الجلسة هنا.

الكتالوج

GET/api/public/v1/destinationsمفتاح API

جلب قائمة الوجهات

الكتالوج الكامل بتنسيق موجّه للشركاء وليس بتنسيق واجهة المتجر.

200 OK
{
  "countries": [
    {
      "code": "JP",
      "name": { "en": "Japan", "tr": "Japonya", "...": "..." },
      "flagEmoji": "🇯🇵",
      "continent": "Asia",
      "plans": [
        { "id": "cus...", "dataAmountMb": 1024, "durationDays": 7, "priceUsd": 4.25, "isTopUp": false }
      ]
    }
  ],
  "regions": [ { "code": "...", "name": {...}, "countryCount": 15, "plans": [...] } ]
}
GET/api/public/v1/destinations/:codeمفتاح API

تفاصيل الوجهة

دولة واحدة بواسطة رمز ISO (مثل /api/public/v1/destinations/JP)، بنفس تنسيق الباقات أعلاه.

الطلبات

POST/api/public/v1/ordersمفتاح API

إنشاء طلب

يشتري باقة من رصيد محفظة المستدعي ويزوّد eSIM بشكل متزامن — تحتوي الاستجابة بالفعل على بيانات QR/التفعيل الجاهزة لتسليمها للعميل النهائي. لا حاجة للاستقصاء في الحالة الطبيعية.

Request body
{ "planId": "cus...", "quantity": 1 }
201 Created
{
  "id": "...", "orderNumber": "VIO-API-...", "status": "COMPLETED", "amountUsd": 4.25,
  "esims": [
    { "id": "...", "iccid": "...", "activationCode": "...",
      "qrCodeUrl": "https://...", "smdpAddress": "...", "status": "PENDING" }
  ]
}
أنماط الفشل: 402 INSUFFICIENT_BALANCE (أضف رصيداً أولاً)، 404 PLAN_NOT_FOUND، أو 502 FULFILLMENT_FAILED (تم التحصيل لكن فشل المزوّد في إصدار eSIM — يتضمن معرّف الطلب، ويُخطر الدعم تلقائياً. لا تُعِد التحصيل، استقصِ GET /orders/:id).
GET/api/public/v1/ordersمفتاح API

قائمة الطلبات

?limit= اختياري (الافتراضي 25، الحد الأقصى 100). هذا تنسيق موجز — استخدم نقطة نهاية التفاصيل لبيانات eSIM.

GET/api/public/v1/orders/:idمفتاح API

تفاصيل الطلب

تفاصيل الطلب الكاملة مع بيانات QR/التفعيل لكل eSIM والاستخدام الفوري (dataUsageMb / totalVolumeMb) — استقصِ هذا لعرض البيانات المتبقية للعميل.

المحفظة

GET/api/public/v1/walletمفتاح API

رصيد المحفظة

تحقق منه قبل تقديم دفعة كبيرة من الطلبات، أو استخدمه لتنبيه نفسك عند انخفاض الرصيد.

200 OK
{ "balanceUsd": 128.40, "currency": "USD" }

ما لم يُبنَ بعد

حتى لا يُظَن أن شيئاً غير موجود هنا يعمل.

إرسال الإشعارات الفورية

تسجيل الرمز يعمل؛ يتطلب الإرسال الفعلي بيانات اعتماد APNs/FCM.

تسعير خاص بكل شريك

تفرض واجهة الشركاء حالياً نفس أسعار التجزئة الخاصة بالمتجر. يتطلب التسعير بالجملة/القابل للتفاوض تغييراً في المخطط وقراراً تجارياً.

رمز التحديث

الجلسة رمز واحد طويل الأمد (30 يوماً) بدلاً من زوج رمز وصول قصير الأمد ورمز تحديث. كافٍ حالياً؛ سيُعاد تقييمه لاحقاً إذا تطلب الأمر نظام أمان أكثر صرامة.

شاشة دفع Stripe أصلية

يستخدم تكامل Stripe حالياً صفحة الدفع المستضافة (إعادة توجيه/عرض ويب). ستتطلب واجهة إدخال البطاقة الأصلية استخدام PaymentIntents وحزمة Stripe SDK.

Webhooks للشركاء

يجب على الشركاء حالياً استقصاء GET /orders/:id لمعرفة الحالة. لا توجد بعد webhooks صادرة (مثل "تم تفعيل eSIM").

مرجع واجهة برمجة تطبيقات Vio eSIM ووثائق واجهة الشركاء