> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# الهجرة من v2 إلى v3

> دليل ترقية بسيط للانتقال من API الإصدار v2 إلى v3

<div dir="rtl">
  ## نظرة عامة

  يُوضِّح هذا الدليل بالضبط ما يجب تغييره عند الانتقال من OneClickDz Flexy API الإصدار v2 إلى v3. يعرض كل مثال الكود الحالي في v2 ويسرد التغييرات المطلوبة ويُظهر النتيجة في v3.

  **متاح بعدة لغات**: أمثلة JavaScript/Node.js وPHP وPython متضمَّنة.

  <Warning>
    **إيقاف API v2**: سيُوقَف API v2 في **30 أكتوبر 2026**.
    يرجى الانتقال قبل هذا التاريخ لتجنب انقطاع الخدمة.
  </Warning>

  ## الجديد في v3

  <CardGroup cols={2}>
    <Card title="استجابات موحّدة" icon="layer-group">
      جميع الاستجابات مُغلَّفة في هيكل `{(success, data, meta, requestId)}`
    </Card>

    <Card title="معالجة أخطاء أفضل" icon="shield-check">
      أخطاء منظّمة مع أكواد ورسائل وتفاصيل لتصحيح أسهل
    </Card>

    <Card title="تصحيح أخطاء محسَّن" icon="info-circle">
      كل استجابة تتضمن طوابع زمنية ومعرّفات طلب فريدة
    </Card>

    <Card title="endpoints أوضح" icon="route">
      تجميع منطقي: `/mobile/*` و`/internet/*` و`/gift-cards/*` و`/account/*`
    </Card>

    <Card title="مفاتيح API منفصلة" icon="key">
      أنشئ مفاتيح sandbox مخصصة للاختبار مع الحفاظ على مفتاح الإنتاج
    </Card>

    <Card title="القائمة البيضاء لعناوين IP" icon="shield-halved">
      أضف قيود IP مباشرة من صفحة الإعدادات لأمان معزّز
    </Card>
  </CardGroup>

  ## قائمة التحقق السريع للهجرة

  <Steps>
    <Step title="إنشاء مفتاح API للـ sandbox (اختياري)">
      أنشئ مفتاح API للـ sandbox من صفحة إعدادات لوحة التحكم لاختبار v3 قبل نقل الإنتاج
    </Step>

    <Step title="تهيئة القائمة البيضاء لعناوين IP (اختياري)">
      أضف قيود IP لأمان معزّز مباشرة من الإعدادات
    </Step>

    <Step title="تحديث رأس المصادقة">
      غيِّر من `authorization` إلى `X-Access-Token` في جميع طلبات API
    </Step>

    <Step title="تحديث معالجة الاستجابة">
      ادخل إلى البيانات عبر `result.data` بدلاً من الوصول المباشر
    </Step>

    <Step title="تحديث معالجة الأخطاء">
      تحقق من القيمة المنطقية `result.success` وتعامل مع كائن `result.error` المنظّم
    </Step>

    <Step title="تحديث مسارات الـ endpoints">
      رسِّم مسارات v2 على المسارات الجديدة في v3 (راجع جدول المرجع الكامل أدناه)
    </Step>

    <Step title="تحديث منطق ترقيم الصفحات">
      ادخل إلى معلومات الترقيم من `result.data.pagination` بدلاً من المستوى الجذري
    </Step>
  </Steps>

  ## اختر استراتيجية الهجرة الخاصة بك

  <Info>
    **خبر جيد**: كلا API الإصداريْن v2 وv3 يعملان في آنٍ واحد حتى إيقاف v2.
    مفتاح API الإنتاجي الحالي يعمل مع endpoints كلٍّ من v2 وv3، مما يمنحك مرونة في كيفية الانتقال.
  </Info>

  <Note>
    **تغيير عنوان URL الأساسي**: يستخدم v3 عنوان URL أساسياً جديداً: - v2:
    `https://flexy-api.oneclickdz.com/v2` - v3: `https://api.oneclickdz.com/v3`
  </Note>

  اختر النهج الذي يناسب احتياجاتك:

  <CardGroup cols={2}>
    <Card title="🆕 بداية جديدة" icon="rocket">
      **الأنسب لـ**: إعادة البناء الكاملة أو المشاريع الجديدة

      * أنشئ مفتاح sandbox للاختبار من الإعدادات
      * هيِّئ القائمة البيضاء لعناوين IP لمفتاح الإنتاج
      * اختبر كل شيء في sandbox مع v3
      * استخدم مفتاح الإنتاج عند الاستعداد

      ✅ صفحة بيضاء، لا كود موروث
      ✅ أمان معزّز مع قيود IP
    </Card>

    <Card title="🔄 هجرة تدريجية" icon="arrows-rotate">
      **الأنسب لـ**: أنظمة الإنتاج الحالية

      * استمر في استخدام مفتاح الإنتاج الحالي لـ endpoints v2
      * أنشئ مفتاح sandbox لاختبار v3 بأمان
      * انقل الـ endpoints واحداً تلو الآخر إلى v3
      * شغِّل v2 وv3 جنباً إلى جنب بنفس مفتاح الإنتاج

      ✅ صفر توقف، مخاطر أقل
      ✅ انتقل بالسرعة التي تناسبك
    </Card>
  </CardGroup>

  **موصى به**: معظم الفرق تختار **الهجرة التدريجية** لتقليل المخاطر. يمكنك تحديث الـ endpoints الحرجة أولاً مع إبقاء البقية على v2.

  ### هجرة ذكية: ابدأ ببطاقات الهدايا

  <Info>
    **نصيحة احترافية**: إذا كنت مهتماً ببطاقات الهدايا، ادمجها على v3 أولاً! لا تحتاج إلى نقل شحنات الجوال والإنترنت الحالية لتبدأ استخدام بطاقات الهدايا على v3. هذه طريقة منخفضة المخاطر لاختبار v3 مع إبقاء عملياتك الحرجة على v2. استخدم مفتاح sandbox للاختبار، ثم انتقل للإنتاج عند الاستعداد.
  </Info>

  **ترتيب الهجرة المقترح**:

  1. **المرحلة 1**: دمج بطاقات الهدايا على v3 (إذا كان ذلك مناسباً)
     * أنشئ مفتاح sandbox للاختبار
     * استخدم endpoints `/v3/gift-cards/*` في sandbox
     * اختبر بدقة، ثم استخدم مفتاح الإنتاج
     * أبقِ الجوال/الإنترنت على v2

  2. **المرحلة 2**: نقل endpoints الحساب والتحقق
     * `/v3/validate`
     * `/v3/account/balance`
     * `/v3/account/transactions`

  3. **المرحلة 3**: نقل شحنات الجوال تدريجياً
     * اختبر بعمليات منخفضة الحجم أولاً
     * راقب المشكلات
     * وسِّع نطاق الهجرة تدريجياً

  4. **المرحلة 4**: نقل شحنات الإنترنت
     * أكمل قبل الموعد النهائي للإيقاف

  هذا النهج يتيح لك **الانتقال بالسرعة التي تناسبك** حتى تاريخ الإيقاف مع الاستفادة من ميزات v3 الجديدة.

  ***

  ## التغييرات الثلاثة الرئيسية

  ### 1. رأس المصادقة

  **ما يجب تغييره**: أعِد تسمية الرأس من `authorization` إلى `X-Access-Token`

  <Info>
    **إدارة المفاتيح الجديدة**: يتيح لك v3 إنشاء مفتاح API sandbox منفصل للاختبار من إعدادات لوحة التحكم. يمكنك أيضاً إضافة قيود القائمة البيضاء لعناوين IP لأمان معزّز. مفتاح API الإنتاجي الحالي يعمل مع endpoints كلٍّ من v2 وv3.
  </Info>

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Your current v2 code:
      fetch("https://flexy-api.oneclickdz.com/v2/plans/listAll", {
        headers: {
          authorization: "YOUR_API_KEY",
        },
      });
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Your current v2 code:
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/plans/listAll');
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'authorization: YOUR_API_KEY'
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Your current v2 code:
      import requests

      response = requests.get(
      'https://flexy-api.oneclickdz.com/v2/plans/listAll',
      headers={'authorization': 'YOUR_API_KEY'}
      )

      ```
    </Tab>
  </Tabs>

  **Changes needed**:

  * ❌ Remove: `authorization: "YOUR_API_KEY"`
  * ✅ Add: `X-Access-Token: "YOUR_API_KEY"`
  * ✅ Update: Base URL to `https://api.oneclickdz.com/v3`

  <Info>
    The authentication mechanism remains the same - only the header name changes. Your existing API key works with both v2 and v3.
  </Info>

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Updated v3 code:
      fetch("https://api.oneclickdz.com/v3/mobile/plans", {
        headers: {
          "X-Access-Token": "YOUR_API_KEY",
        },
      });
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Updated v3 code:
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/plans');
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'X-Access-Token: YOUR_API_KEY'
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      ```
    </Tab>
  </Tabs>

  **التغييرات المطلوبة**:

  * ❌ احذف: `authorization: "YOUR_API_KEY"`
  * ✅ أضف: `X-Access-Token: "YOUR_API_KEY"`
  * ✅ حدِّث: عنوان URL الأساسي إلى `https://api.oneclickdz.com/v3`

  <Info>
    آلية المصادقة تبقى كما هي - فقط اسم الرأس يتغير. مفتاح API الحالي يعمل مع v2 وv3.
  </Info>

  <Tabs>
    <Tab title="JavaScript">
      ```python theme={null}
      # Updated v3 code:
      import requests

      response = requests.get(
      'https://api.oneclickdz.com/v3/mobile/plans',
      headers={'X-Access-Token': 'YOUR_API_KEY'}
      )

      ```
    </Tab>
  </Tabs>

  ***

  ### 2. Response Structure

  **What to change**: All responses are now wrapped in a standard structure

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Your current v2 code:
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/account/balance", {
        headers: { authorization: API_KEY },
      });
      const data = await response.json();
      console.log("Balance:", data.balance); // Direct access
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Your current v2 code:
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/account/balance');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);
      echo "Balance: " . $data['balance']; // Direct access
      ```
    </Tab>

    <Tab title="PHP">
      ```python theme={null}
      # Your current v2 code:
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/account/balance',
          headers={'authorization': API_KEY}
      )
      data = response.json()
      print(f"Balance: {data['balance']}")  # Direct access
      ```
    </Tab>

    <Tab title="Python">
      ```javascript theme={null}
      // Updated v3 code:
      const response = await fetch("https://api.oneclickdz.com/v3/account/balance", {
        headers: { "X-Access-Token": API_KEY },
      });
      const result = await response.json();

      if (result.success) {
      console.log("Balance:", result.data.balance);
      console.log("Request ID:", result.requestId); // For debugging
      console.log("Timestamp:", result.meta.timestamp); // Response time
      } else {
      console.error("Error:", result.error.message);
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Updated v3 code:
      $ch = curl_init('https://api.oneclickdz.com/v3/account/balance');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Balance: " . $result['data']['balance'] . "\n";
          echo "Request ID: " . $result['requestId'] . "\n";
          echo "Timestamp: " . $result['meta']['timestamp'] . "\n";
      } else {
          error_log("Error: " . $result['error']['message']);
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Updated v3 code:
      response = requests.get(
          'https://api.oneclickdz.com/v3/account/balance',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
      print(f"Balance: {result['data']['balance']}")
      print(f"Request ID: {result['requestId']}") # For debugging
      print(f"Timestamp: {result['meta']['timestamp']}")
      else:
      print(f"Error: {result['error']['message']}")

      ```
    </Tab>
  </Tabs>

  ***

  ### 3. Error Handling

  **What to change**: Errors are now structured objects with codes

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Your current v2 code:
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          authorization: API_KEY,
        },
        body: JSON.stringify(data),
      });

      const result = await response.json();
      if (result.error) {
        console.error("Error:", result.message); // Simple string
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Your current v2 code:
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/sendTopup');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'authorization: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if (isset($result['error'])) {
      error_log("Error: " . $result['message']); // Simple string
      }

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Your current v2 code:
      response = requests.post(
          'https://flexy-api.oneclickdz.com/v2/topup/sendTopup',
          headers={
              'Content-Type': 'application/json',
              'authorization': API_KEY
          },
          json=data
      )
      result = response.json()

      if 'error' in result:
          print(f"Error: {result['message']}")  # Simple string
      ```
    </Tab>
  </Tabs>

  **Changes needed**:

  * ❌ Remove: Checking `result.error` string
  * ✅ Add: Check `result.success === false`
  * ✅ Add: Access `result.error.code` and `result.error.message`
  * ✅ Add: Handle different error codes with switch/if statements
  * ✅ Add: Log `result.requestId` for support tickets

  <Info>
    **Pro Tip**: Always save the `requestId` when logging errors. Our support team
    needs this to trace issues in our system.
  </Info>

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Updated v3 code:
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Access-Token": API_KEY,
        },
        body: JSON.stringify(data),
      });

      const result = await response.json();

      if (!result.success) {
      console.error(`Error [${result.error.code}]: ${result.error.message}`);
      console.log("Request ID:", result.requestId);

      // Handle specific errors
      switch (result.error.code) {
      case "INSUFFICIENT_BALANCE":
      alert("Please top up your account");
      break;
      case "ERR_PHONE":
      alert(`Invalid phone number: ${result.error.message}`);
      if (result.error.details?.pattern) {
      console.log("Expected format:", result.error.details.pattern);
      }
      break;
      case "DUPLICATED_REF":
      alert("This order reference was already used");
      break;
      default:
      alert("An error occurred. Please try again.");
      }
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Updated v3 code:
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/send');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'X-Access-Token: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if (!$result['success']) {
          $errorCode = $result['error']['code'];
          $errorMessage = $result['error']['message'];
          error_log("Error [{$errorCode}]: {$errorMessage}");
          error_log("Request ID: " . $result['requestId']);

          // Handle specific errors
          switch ($errorCode) {
              case 'INSUFFICIENT_BALANCE':
                  echo "Please top up your account\n";
                  break;
              case 'ERR_PHONE':
                  echo "Invalid phone number: {$errorMessage}\n";
                  if (isset($result['error']['details']['pattern'])) {
                      echo "Expected format: " . $result['error']['details']['pattern'] . "\n";
                  }
                  break;
              case 'DUPLICATED_REF':
                  echo "This order reference was already used\n";
                  break;
              default:
                  echo "An error occurred. Please try again\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Updated v3 code:
      response = requests.post(
          'https://api.oneclickdz.com/v3/mobile/send',
          headers={
              'Content-Type': 'application/json',
              'X-Access-Token': API_KEY
          },
          json=data
      )
      result = response.json()

      if not result['success']:
      error_code = result['error']['code']
      error_message = result['error']['message']
      print(f"Error [{error_code}]: {error_message}")
      print(f"Request ID: {result['requestId']}")

          # Handle specific errors
          if error_code == 'INSUFFICIENT_BALANCE':
              print("Please top up your account")
          elif error_code == 'ERR_PHONE':
              print(f"Invalid phone number: {error_message}")
              if 'pattern' in result['error'].get('details', {}):
                  print(f"Expected format: {result['error']['details']['pattern']}")
          elif error_code == 'DUPLICATED_REF':
              print("This order reference was already used")
          else:
              print("An error occurred. Please try again.")

      ```
    </Tab>
  </Tabs>

  ***

  ## Step-by-Step Migration Examples

  ### Example 1: Get Mobile Plans

  **Step 1 - Your current v2 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/plans/listAll", {
        headers: {
          authorization: API_KEY,
        },
      });

      const data = await response.json();
      const dynamicPlans = data.dymanicPlans; // Note: typo in v2
      const fixedPlans = data.fixedPlans;
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/plans/listAll');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      $dynamicPlans = $data['dymanicPlans']; // Note: typo in v2
      $fixedPlans = $data['fixedPlans'];

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/plans/listAll',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      dynamic_plans = data['dymanicPlans']  # Note: typo in v2
      fixed_plans = data['fixedPlans']
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change endpoint: `/v2/plans/listAll` → `/v3/mobile/plans`
  3. Change header: `authorization` → `X-Access-Token`
  4. Add success check: `if (result.success)`
  5. Access through data: `data.dymanicPlans` → `result.data.dynamicPlans` (typo fixed!)

  <Warning>
    **MUST Fix**: v3 fixes the typo in "dymanicPlans" to "dynamicPlans". Update
    your code to use the correct spelling.
  </Warning>

  **Step 3 - Your new v3 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/plans", {
        headers: {
          "X-Access-Token": API_KEY,
        },
      });

      const result = await response.json();
      if (result.success) {
      const dynamicPlans = result.data.dynamicPlans; // Typo fixed!
      const fixedPlans = result.data.fixedPlans;
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/plans');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          $dynamicPlans = $result['data']['dynamicPlans']; // Typo fixed!
          $fixedPlans = $result['data']['fixedPlans'];
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/mobile/plans',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
      dynamic_plans = result['data']['dynamicPlans'] # Typo fixed!
      fixed_plans = result['data']['fixedPlans']

      ```
    </Tab>
  </Tabs>

  ***

  ### Example 2: Send Mobile Top-Up

  **Step 1 - Your current v2 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          authorization: API_KEY,
        },
        body: JSON.stringify({
          plan_code: "PREPAID_DJEZZY",
          MSSIDN: "0778037340",
          amount: 500,
          ref: "order-123",
        }),
      });

      const data = await response.json();
      console.log("Topup ID:", data.topupId);
      console.log("New Balance:", data.newBalance);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $data = [
          'plan_code' => 'PREPAID_DJEZZY',
          'MSSIDN' => '0778037340',
          'amount' => 500,
          'ref' => 'order-123'
      ];

      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/sendTopup');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'authorization: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      echo "Topup ID: " . $result['topupId'] . "\n";
      echo "New Balance: " . $result['newBalance'] . "\n";

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      data = {
          'plan_code': 'PREPAID_DJEZZY',
          'MSSIDN': '0778037340',
          'amount': 500,
          'ref': 'order-123'
      }

      response = requests.post(
          'https://flexy-api.oneclickdz.com/v2/topup/sendTopup',
          headers={
              'Content-Type': 'application/json',
              'authorization': API_KEY
          },
          json=data
      )
      result = response.json()

      print(f"Topup ID: {result['topupId']}")
      print(f"New Balance: {result['newBalance']}")
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change endpoint: `/v2/topup/sendTopup` → `/v3/mobile/send`
  3. Change header: `authorization` → `X-Access-Token`
  4. Add success check: `if (result.success)`
  5. Access through data: `data.topupId` → `result.data.topupId`
  6. Add comprehensive error handling

  <Warning>
    **Important**: Always handle errors when sending top-ups. Network issues,
    insufficient balance, or invalid data can cause failures. Save the `requestId`
    for tracking.
  </Warning>

  **Step 3 - Your new v3 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Access-Token": API_KEY,
        },
        body: JSON.stringify({
          plan_code: "PREPAID_DJEZZY",
          MSSIDN: "0778037340",
          amount: 500,
          ref: "order-123",
        }),
      });

      const result = await response.json();
      if (result.success) {
      console.log("✅ Top-up sent successfully!");
      console.log("Topup ID:", result.data.topupId);
      console.log("New Balance:", result.data.newBalance);
      console.log("Request ID:", result.requestId);
      } else {
      console.error(`❌ Error [${result.error.code}]: ${result.error.message}`);
      console.error("Request ID:", result.requestId);
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // ...existing code...

      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/send');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'X-Access-Token: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "✅ Top-up sent successfully!\n";
          echo "Topup ID: " . $result['data']['topupId'] . "\n";
          echo "New Balance: " . $result['data']['newBalance'] . "\n";
          echo "Request ID: " . $result['requestId'] . "\n";
      } else {
          error_log("❌ Error [{$result['error']['code']}]: {$result['error']['message']}");
          error_log("Request ID: " . $result['requestId']);
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # ...existing code...

      response = requests.post(
      'https://api.oneclickdz.com/v3/mobile/send',
      headers={
      'Content-Type': 'application/json',
      'X-Access-Token': API_KEY
      },
      json=data
      )
      result = response.json()

      if result['success']:
      print("✅ Top-up sent successfully!")
      print(f"Topup ID: {result['data']['topupId']}")
      print(f"New Balance: {result['data']['newBalance']}")
      print(f"Request ID: {result['requestId']}")
      else:
      print(f"❌ Error [{result['error']['code']}]: {result['error']['message']}")
      print(f"Request ID: {result['requestId']}")

      ```
    </Tab>
  </Tabs>

  ***

  ### Example 3: Check Top-Up Status

  **Step 1 - Your current v2 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123",
        {
          headers: { authorization: API_KEY },
        }
      );

      const data = await response.json();
      console.log("Status:", data.topup.status);
      console.log("Phone:", data.topup.MSSIDN);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      echo "Status: " . $data['topup']['status'] . "\n";
      echo "Phone: " . $data['topup']['MSSIDN'] . "\n";

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      print(f"Status: {data['topup']['status']}")
      print(f"Phone: {data['topup']['MSSIDN']}")
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change endpoint: `/v2/topup/checkStatus/REF/:ref` → `/v3/mobile/check-ref/:ref`
  3. Change header: `authorization` → `X-Access-Token`
  4. Add success check: `if (result.success)`
  5. Access directly: `data.topup.status` → `result.data.status` (no more nested `topup` object)
  6. Handle new refund information fields

  <Info>
    **New Feature**: v3 includes detailed refund information with suggested
    alternative offers when a top-up is refunded.
  </Info>

  **Step 3 - Your new v3 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/mobile/check-ref/order-123",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
      console.log("Status:", result.data.status);
      console.log("Phone:", result.data.MSSIDN);

      // New in v3: Enhanced refund information
      if (result.data.status === "REFUNDED") {
      console.log("❌ Top-up was refunded");
      console.log("Reason:", result.data.refund_message);
      if (result.data.suggested_offers) {
      console.log("💡 Try these offers instead:");
      console.log(result.data.suggested_offers);
      }
      } else if (result.data.status === "FULFILLED") {
      console.log("✅ Top-up completed successfully");
      }
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/check-ref/order-123');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Status: " . $result['data']['status'] . "\n";
          echo "Phone: " . $result['data']['MSSIDN'] . "\n";

          // New in v3: Enhanced refund information
          if ($result['data']['status'] === 'REFUNDED') {
              echo "❌ Top-up was refunded\n";
              echo "Reason: " . $result['data']['refund_message'] . "\n";
              if (isset($result['data']['suggested_offers'])) {
                  echo "💡 Try these offers instead:\n";
                  print_r($result['data']['suggested_offers']);
              }
          } elseif ($result['data']['status'] === 'FULFILLED') {
              echo "✅ Top-up completed successfully\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/mobile/check-ref/order-123',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
      print(f"Status: {result['data']['status']}")
      print(f"Phone: {result['data']['MSSIDN']}")

          # New in v3: Enhanced refund information
          if result['data']['status'] == 'REFUNDED':
              print("❌ Top-up was refunded")
              print(f"Reason: {result['data']['refund_message']}")
              if 'suggested_offers' in result['data']:
                  print("💡 Try these offers instead:")
                  print(result['data']['suggested_offers'])
          elif result['data']['status'] == 'FULFILLED':
              print("✅ Top-up completed successfully")

      ```
    </Tab>
  </Tabs>

  ***

  ### Example 4: List Transactions with Pagination

  **Step 1 - Your current v2 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20",
        {
          headers: { authorization: API_KEY },
        }
      );

      const data = await response.json();
      console.log("Transactions:", data.transactions);
      console.log("Total:", data.totalResults);
      console.log("Page:", data.currentPage);
      console.log("Pages:", data.totalPages);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      echo "Transactions: " . count($data['transactions']) . "\n";
      echo "Total: " . $data['totalResults'] . "\n";
      echo "Page: " . $data['currentPage'] . "\n";
      echo "Pages: " . $data['totalPages'] . "\n";

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      print(f"Transactions: {len(data['transactions'])}")
      print(f"Total: {data['totalResults']}")
      print(f"Page: {data['currentPage']}")
      print(f"Pages: {data['totalPages']}")
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change version: `/v2/account/transactions` → `/v3/account/transactions`
  3. Change header: `authorization` → `X-Access-Token`
  4. Add success check: `if (result.success)`
  5. Access items: `data.transactions` → `result.data.items`
  6. Access pagination: Root level fields → `result.data.pagination` object

  <Warning>
    **Breaking Change**: Pagination structure has moved from root level to
    `data.pagination`. Update all list/pagination logic.
  </Warning>

  **Step 3 - Your new v3 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
      console.log("Transactions:", result.data.items);
      console.log("Total:", result.data.pagination.totalResults);
      console.log("Page:", result.data.pagination.page);
      console.log("Pages:", result.data.pagination.totalPages);
      console.log("Page Size:", result.data.pagination.pageSize);
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Transactions: " . count($result['data']['items']) . "\n";
          echo "Total: " . $result['data']['pagination']['totalResults'] . "\n";
          echo "Page: " . $result['data']['pagination']['page'] . "\n";
          echo "Pages: " . $result['data']['pagination']['totalPages'] . "\n";
          echo "Page Size: " . $result['data']['pagination']['pageSize'] . "\n";
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
      print(f"Transactions: {len(result['data']['items'])}")
      print(f"Total: {result['data']['pagination']['totalResults']}")
      print(f"Page: {result['data']['pagination']['page']}")
      print(f"Pages: {result['data']['pagination']['totalPages']}")
      print(f"Page Size: {result['data']['pagination']['pageSize']}")

      ```
    </Tab>
  </Tabs>

  ***

  ### Example 5: Check Internet Products

  **Step 1 - Your current v2 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL",
        {
          headers: { authorization: API_KEY },
        }
      );

      const cards = await response.json(); // Direct array
      cards.forEach((card) => {
        console.log(`${card.value} DA - Available: ${card.available}`);
      });
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $cards = json_decode($response, true); // Direct array

      foreach ($cards as $card) {
      echo $card['value'] . " DA - Available: " . $card['available'] . "\n";
      }

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL',
          headers={'authorization': API_KEY}
      )
      cards = response.json()  # Direct array

      for card in cards:
          print(f"{card['value']} DA - Available: {card['available']}")
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change endpoint: `/v2/internet/checkCards/:type` → `/v3/internet/products?type=:type`
  3. Change from path param to query param: `/ADSL` → `?type=ADSL`
  4. Change header: `authorization` → `X-Access-Token`
  5. Add success check: `if (result.success)`
  6. Access array: Direct array → `result.data.products`

  <Info>
    **API Design**: v3 uses query parameters instead of path parameters for type
    selection, making it easier to add filters in the future.
  </Info>

  **Step 3 - Your new v3 code:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/internet/products?type=ADSL",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
      result.data.products.forEach((card) => {
      console.log(`${card.value} DA - Available: ${card.available}`);
      });
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/internet/products?type=ADSL');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          foreach ($result['data']['products'] as $card) {
              echo $card['value'] . " DA - Available: " . $card['available'] . "\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/internet/products?type=ADSL',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
      for card in result['data']['products']:
      print(f"{card['value']} DA - Available: {card['available']}")

      ```
    </Tab>
  </Tabs>

  ***

  ## Migrate Your API Client

  Here's how to update your API client wrapper:

  **Step 1 - Your current v2 client:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      class FlexyAPI {
        constructor(apiKey) {
          this.apiKey = apiKey;
          this.baseUrl = "https://flexy-api.oneclickdz.com";
        }

        async request(endpoint, options = {}) {
          const response = await fetch(`${this.baseUrl}${endpoint}`, {
            ...options,
            headers: {
              ...options.headers,
              authorization: this.apiKey,
            },
          });
          return response.json();
        }

        async getBalance() {
          const data = await this.request("/v2/account/balance");
          return data.balance;
        }

        async sendTopup(params) {
          return await this.request("/v2/topup/sendTopup", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(params),
          });
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      class FlexyAPI {
          private $apiKey;
          private $baseUrl = 'https://flexy-api.oneclickdz.com';

          public function __construct($apiKey) {
              $this->apiKey = $apiKey;
          }

          private function request($endpoint, $options = []) {
              $ch = curl_init($this->baseUrl . $endpoint);
              curl_setopt($ch, CURLOPT_HTTPHEADER, [
                  'authorization: ' . $this->apiKey
              ]);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

              if (isset($options['method']) && $options['method'] === 'POST') {
                  curl_setopt($ch, CURLOPT_POST, true);
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $options['body']);
              }

              $response = curl_exec($ch);
              return json_decode($response, true);
          }

          public function getBalance() {
              $data = $this->request('/v2/account/balance');
              return $data['balance'];
          }

          public function sendTopup($params) {
              return $this->request('/v2/topup/sendTopup', [
                  'method' => 'POST',
                  'body' => json_encode($params)
              ]);
          }

      }

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      import requests

      class FlexyAPI:
          def __init__(self, api_key):
              self.api_key = api_key
              self.base_url = 'https://flexy-api.oneclickdz.com'

          def request(self, endpoint, method='GET', data=None):
              headers = {'authorization': self.api_key}
              url = f"{self.base_url}{endpoint}"

              if method == 'GET':
                  response = requests.get(url, headers=headers)
              else:
                  headers['Content-Type'] = 'application/json'
                  response = requests.post(url, headers=headers, json=data)

              return response.json()

          def get_balance(self):
              data = self.request('/v2/account/balance')
              return data['balance']

          def send_topup(self, params):
              return self.request('/v2/topup/sendTopup', method='POST', data=params)
      ```
    </Tab>
  </Tabs>

  **Step 2 - What to change:**

  1. Change base URL: `https://flexy-api.oneclickdz.com` → `https://api.oneclickdz.com`
  2. Change header: `authorization` → `X-Access-Token`
  3. Add response wrapper handling in `request()` method
  4. Check `result.success` and handle errors
  5. Update all endpoint paths to v3
  6. Throw structured errors with codes and request IDs

  <Note>
    **Best Practice**: Centralize error handling in your API client. This makes it
    easier to add logging, monitoring, and user notifications.
  </Note>

  **Step 3 - Your new v3 client:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      class FlexyAPI {
        constructor(apiKey) {
          this.apiKey = apiKey;
          this.baseUrl = "https://api.oneclickdz.com";
        }

      async request(endpoint, options = {}) {
      const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
      ...options.headers,
      "X-Access-Token": this.apiKey, // Changed header name
      },
      });

          const result = await response.json();

          // Handle v3 response wrapper
          if (!result.success) {
            const error = new Error(result.error.message);
            error.code = result.error.code;
            error.details = result.error.details;
            error.requestId = result.requestId;
            throw error;
          }

          return result.data; // Return unwrapped data

      }

      async getBalance() {
      const data = await this.request("/v3/account/balance"); // Updated path
      return data.balance;
      }

      async sendTopup(params) {
      return await this.request("/v3/mobile/send", { // Updated path
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(params),
      });
      }
      }

      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      class FlexyAPI {
          private $apiKey;
          private $baseUrl = 'https://api.oneclickdz.com';

          public function __construct($apiKey) {
              $this->apiKey = $apiKey;
          }

          private function request($endpoint, $options = []) {
              $ch = curl_init($this->baseUrl . $endpoint);
              $headers = ['X-Access-Token: ' . $this->apiKey]; // Changed header name

              if (isset($options['method']) && $options['method'] === 'POST') {
                  curl_setopt($ch, CURLOPT_POST, true);
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $options['body']);
                  $headers[] = 'Content-Type: application/json';
              }

              curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
              $response = curl_exec($ch);
              $result = json_decode($response, true);

              // Handle v3 response wrapper
              if (!$result['success']) {
                  $error = [
                      'message' => $result['error']['message'],
                      'code' => $result['error']['code'],
                      'details' => $result['error']['details'] ?? null,
                      'requestId' => $result['requestId']
                  ];
                  throw new Exception(json_encode($error));
              }

              return $result['data']; // Return unwrapped data
          }

          public function getBalance() {
              $data = $this->request('/v3/account/balance'); // Updated path
              return $data['balance'];
          }

          public function sendTopup($params) {
              return $this->request('/v3/mobile/send', [ // Updated path
                  'method' => 'POST',
                  'body' => json_encode($params)
              ]);
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      import requests

      class FlexyAPIError(Exception):
      """Custom exception for API errors"""
      def **init**(self, message, code, details=None, request_id=None):
      super().**init**(message)
      self.code = code
      self.details = details
      self.request_id = request_id

      class FlexyAPI:
      def **init**(self, api_key):
      self.api_key = api_key
      self.base_url = 'https://api.oneclickdz.com'

          def request(self, endpoint, method='GET', data=None):
              headers = {'X-Access-Token': self.api_key}  # Changed header name
              url = f"{self.base_url}{endpoint}"

              if method == 'GET':
                  response = requests.get(url, headers=headers)
              else:
                  headers['Content-Type'] = 'application/json'
                  response = requests.post(url, headers=headers, json=data)

              result = response.json()

              # Handle v3 response wrapper
              if not result['success']:
                  raise FlexyAPIError(
                      result['error']['message'],
                      result['error']['code'],
                      result['error'].get('details'),
                      result['requestId']
                  )

              return result['data']  # Return unwrapped data

          def get_balance(self):
              data = self.request('/v3/account/balance')  # Updated path
              return data['balance']

          def send_topup(self, params):
              return self.request('/v3/mobile/send', method='POST', data=params)  # Updated path

      ```
    </Tab>
  </Tabs>

  ***

  ## Complete Endpoint Reference

  | Service            | v2 Endpoint                             | v3 Endpoint                                   | Notes                                 |
  | ------------------ | --------------------------------------- | --------------------------------------------- | ------------------------------------- |
  | **Authentication** |                                         |                                               |                                       |
  | Header             | `authorization: KEY`                    | `X-Access-Token: KEY`                         | Header name changed                   |
  | Validate           | `GET /v2/validate`                      | `GET /v3/validate`                            | Response wrapped                      |
  | **Mobile**         |                                         |                                               |                                       |
  | List Plans         | `GET /v2/plans/listAll`                 | `GET /v3/mobile/plans`                        | Path changed, typo fixed              |
  | Send Top-Up        | `POST /v2/topup/sendTopup`              | `POST /v3/mobile/send`                        | Path simplified                       |
  | Check by Ref       | `GET /v2/topup/checkStatus/REF/:ref`    | `GET /v3/mobile/check-ref/:ref`               | Path simplified, refund info added    |
  | Check by ID        | `GET /v2/topup/checkStatus/ID/:id`      | `GET /v3/mobile/check-id/:id`                 | Path simplified                       |
  | List Top-Ups       | `GET /v2/topup/list`                    | `GET /v3/mobile/list`                         | Pagination moved to `data.pagination` |
  | **Internet**       |                                         |                                               |                                       |
  | Products           | `GET /v2/internet/checkCards/:type`     | `GET /v3/internet/products?type=`             | Path param → query param              |
  | Check Number       | `GET /v2/internet/checkNumber/:t/:n`    | `GET /v3/internet/check-number?type=&number=` | Path params → query params            |
  | Send               | `POST /v2/internet/sendTopup`           | `POST /v3/internet/send`                      | Path simplified                       |
  | Check by Ref       | `GET /v2/internet/checkStatus/REF/:ref` | `GET /v3/internet/check-ref/:ref`             | Path simplified                       |
  | Check by ID        | `GET /v2/internet/checkStatus/ID/:id`   | `GET /v3/internet/check-id/:id`               | Path simplified                       |
  | List               | `GET /v2/internet/list`                 | `GET /v3/internet/list`                       | Pagination moved                      |
  | **Gift Cards**     |                                         |                                               |                                       |
  | Catalog            | `GET /v2/gift-cards/catalogue`          | `GET /v3/gift-cards/catalog`                  | Spelling fixed                        |
  | Check Product      | `GET /v2/gift-cards/checkProduct/:id`   | `GET /v3/gift-cards/checkProduct/:id`         | Response wrapped                      |
  | Place Order        | `POST /v2/gift-cards/placeOrder`        | `POST /v3/gift-cards/placeOrder`              | Response wrapped                      |
  | Check Order        | `GET /v2/gift-cards/checkOrder/:id`     | `GET /v3/gift-cards/checkOrder/:id`           | Response wrapped                      |
  | List Orders        | `GET /v2/gift-cards/list`               | `GET /v3/gift-cards/list`                     | Pagination moved                      |
  | **Account**        |                                         |                                               |                                       |
  | Balance            | `GET /v2/account/balance`               | `GET /v3/account/balance`                     | Response wrapped                      |
  | Transactions       | `GET /v2/account/transactions`          | `GET /v3/account/transactions`                | Pagination moved                      |

  ***

  ## Error Code Reference

  Common v2 errors and their v3 equivalents:

  | v2 Error                 | v3 Error Code          | What Changed                                   |
  | ------------------------ | ---------------------- | ---------------------------------------------- |
  | `"NO-BALANCE"`           | `INSUFFICIENT_BALANCE` | Now a code with structured message             |
  | `"DUPLICATED-REF"`       | `DUPLICATED_REF`       | Same code, now with details object             |
  | `"ERR_VALIDATION"`       | `ERR_VALIDATION`       | Includes `details.field` and \`details.pattern |
  | `"ERR_PHONE"`            | `ERR_PHONE`            | Includes validation pattern in details         |
  | `"ERR_STOCK"`            | `ERR_STOCK`            | Product availability information               |
  | `"Forbidden"`            | `ERR_AUTH`             | More descriptive, unified auth errors          |
  | `"Access token missing"` | `ERR_AUTH`             | Same code for all auth errors                  |
  | `"NOT_FOUND"`            | `NOT_FOUND`            | Resource not found (order, product, etc.)      |

  **How to handle v3 errors:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // v2 way:
      if (result.error === "NO-BALANCE") {
        // handle
      }

      // v3 way:
      if (!result.success && result.error.code === "INSUFFICIENT_BALANCE") {
        console.log("Request ID:", result.requestId); // Save for support
        // handle with more context
        if (result.error.details?.currentBalance) {
          console.log("Current balance:", result.error.details.currentBalance);
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // v2 way:
      if ($result['error'] === 'NO-BALANCE') {
          // handle
      }

      // v3 way:
      if (!$result['success'] && $result['error']['code'] === 'INSUFFICIENT_BALANCE') {
          error_log("Request ID: " . $result['requestId']); // Save for support
          // handle with more context
          if (isset($result['error']['details']['currentBalance'])) {
      echo "Current balance: " . $result['error']['details']['currentBalance'] . "\n";
      }
      }

      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # v2 way:
      if result.get('error') == 'NO-BALANCE':
          # handle

      # v3 way:
      if not result['success'] and result['error']['code'] == 'INSUFFICIENT_BALANCE':
          print(f"Request ID: {result['requestId']}")  # Save for support
          # handle with more context
          if 'currentBalance' in result['error'].get('details', {}):
              print(f"Current balance: {result['error']['details']['currentBalance']}")
      ```
    </Tab>
  </Tabs>

  ***

  <Warning>
    **Critical Deadline**: After October 30, 2026, all v2 API requests will fail.
    Plan your migration accordingly to avoid service disruption.
  </Warning>

  ***

  ## Common Migration Issues & Solutions

  <AccordionGroup>
    <Accordion title="Issue: Getting 401 Unauthorized Errors" icon="circle-exclamation">
      **Problem**: Changed endpoint but forgot to update header name.

      **Solution**: Replace `authorization` with `X-Access-Token` in ALL requests.

      ```javascript theme={null}
      // ❌ Wrong
      headers: { authorization: API_KEY }

      // ✅ Correct
      headers: { "X-Access-Token": API_KEY }
      ```
    </Accordion>

    {" "}

    <Accordion title="Issue: Getting 'undefined' When Accessing Data" icon="circle-exclamation">
      **Problem**: Trying to access data directly instead of through `result.data`.
      **Solution**: Always access response data through the `data` property.

      ````javascript // ❌ Wrong const balance = result.balance; // ✅ Correct const theme={null}
      balance = result.data.balance; ```
      </Accordion>

      {" "}

      <Accordion title="Issue: Pagination Not Working" icon="circle-exclamation">
      **Problem**: Looking for pagination fields at root level. **Solution**: Access
      pagination through `data.pagination`. ```javascript // ❌ Wrong const total =
      result.totalResults; const page = result.currentPage; // ✅ Correct const
      total = result.data.pagination.totalResults; const page =
      result.data.pagination.page; ```
      </Accordion>

      <Accordion title="Issue: Error Handling Not Working" icon="circle-exclamation">
        **Problem**: Checking for old error format.
        
        **Solution**: Check `success` boolean and access structured error object.
        
        ```javascript
        // ❌ Wrong
        if (result.error) {
          console.log(result.message);
        }
        
        // ✅ Correct
        if (!result.success) {
          console.log(result.error.code, result.error.message);
          console.log("Request ID:", result.requestId);
        }
      ````
    </Accordion>

    <Accordion title="Issue: 404 Not Found Errors" icon="circle-exclamation">
      **Problem**: Using old v2 endpoint paths.

      **Solution**: Update all paths according to the reference table above.

      ```javascript theme={null}
      // ❌ Wrong
      POST /v2/topup/sendTopup
      GET /v2/internet/checkCards/ADSL

      // ✅ Correct
      POST /v3/mobile/send
      GET /v3/internet/products?type=ADSL
      ```
    </Accordion>
  </AccordionGroup>

  **التغييرات المطلوبة**:

  * ❌ احذف: الوصول المباشر إلى `data.balance`
  * ✅ أضف: تحقق من `result.success` أولاً
  * ✅ أضف: الوصول عبر `result.data.balance`
  * ✅ إضافي: استخدم `result.requestId` لأغراض التصحيح
  * ✅ إضافي: استخدم `result.meta.timestamp` لمعلومات التوقيت

  <Warning>
    **تغيير جوهري**: في v3، يجب دائماً التحقق من القيمة المنطقية `success` قبل
    الوصول إلى البيانات. سيُسبِّب الوصول المباشر للحقول أخطاءً إذا فشل الطلب.
  </Warning>

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Updated v3 code:
      const response = await fetch("https://api.oneclickdz.com/v3/account/balance", {
        headers: { "X-Access-Token": API_KEY },
      });
      const result = await response.json();

      if (result.success) {
        console.log("Balance:", result.data.balance);
        console.log("Request ID:", result.requestId);
        console.log("Timestamp:", result.meta.timestamp);
      } else {
        console.error("Error:", result.error.message);
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Updated v3 code:
      $ch = curl_init('https://api.oneclickdz.com/v3/account/balance');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Balance: " . $result['data']['balance'] . "\n";
          echo "Request ID: " . $result['requestId'] . "\n";
          echo "Timestamp: " . $result['meta']['timestamp'] . "\n";
      } else {
          error_log("Error: " . $result['error']['message']);
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Updated v3 code:
      response = requests.get(
          'https://api.oneclickdz.com/v3/account/balance',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
          print(f"Balance: {result['data']['balance']}")
          print(f"Request ID: {result['requestId']}")
          print(f"Timestamp: {result['meta']['timestamp']}")
      else:
          print(f"Error: {result['error']['message']}")
      ```
    </Tab>
  </Tabs>

  ***

  ### 3. معالجة الأخطاء

  **ما يجب تغييره**: الأخطاء الآن عبارة عن كائنات منظّمة مع أكواد

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Your current v2 code:
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          authorization: API_KEY,
        },
        body: JSON.stringify(data),
      });

      const result = await response.json();
      if (result.error) {
        console.error("Error:", result.message); // Simple string
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Your current v2 code:
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/sendTopup');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'authorization: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if (isset($result['error'])) {
          error_log("Error: " . $result['message']); // Simple string
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Your current v2 code:
      response = requests.post(
          'https://flexy-api.oneclickdz.com/v2/topup/sendTopup',
          headers={
              'Content-Type': 'application/json',
              'authorization': API_KEY
          },
          json=data
      )
      result = response.json()

      if 'error' in result:
          print(f"Error: {result['message']}")  # Simple string
      ```
    </Tab>
  </Tabs>

  **التغييرات المطلوبة**:

  * ❌ احذف: التحقق من سلسلة `result.error`
  * ✅ أضف: تحقق من `result.success === false`
  * ✅ أضف: ادخل إلى `result.error.code` و`result.error.message`
  * ✅ أضف: تعامل مع أكواد الخطأ المختلفة باستخدام switch/if
  * ✅ أضف: سجِّل `result.requestId` لتذاكر الدعم

  <Info>
    **نصيحة احترافية**: احفظ دائماً `requestId` عند تسجيل الأخطاء. يحتاج فريق الدعم لدينا إليه لتتبع المشكلات في نظامنا.
  </Info>

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // Updated v3 code:
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Access-Token": API_KEY,
        },
        body: JSON.stringify(data),
      });

      const result = await response.json();

      if (!result.success) {
        console.error(`Error [${result.error.code}]: ${result.error.message}`);
        console.log("Request ID:", result.requestId);

        switch (result.error.code) {
          case "INSUFFICIENT_BALANCE":
            alert("Please top up your account");
            break;
          case "ERR_PHONE":
            alert(`Invalid phone number: ${result.error.message}`);
            if (result.error.details?.pattern) {
              console.log("Expected format:", result.error.details.pattern);
            }
            break;
          case "DUPLICATED_REF":
            alert("This order reference was already used");
            break;
          default:
            alert("Something went wrong. Please try again.");
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // Updated v3 code:
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/send');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'X-Access-Token: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if (!$result['success']) {
          $errorCode = $result['error']['code'];
          $errorMessage = $result['error']['message'];
          error_log("Error [{$errorCode}]: {$errorMessage}");
          error_log("Request ID: " . $result['requestId']);

          switch ($errorCode) {
              case 'INSUFFICIENT_BALANCE':
                  echo "Please top up your account\n";
                  break;
              case 'ERR_PHONE':
                  echo "Invalid phone number: {$errorMessage}\n";
                  if (isset($result['error']['details']['pattern'])) {
                      echo "Expected format: " . $result['error']['details']['pattern'] . "\n";
                  }
                  break;
              case 'DUPLICATED_REF':
                  echo "This order reference was already used\n";
                  break;
              default:
                  echo "An error occurred. Please try again\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # Updated v3 code:
      response = requests.post(
          'https://api.oneclickdz.com/v3/mobile/send',
          headers={
              'Content-Type': 'application/json',
              'X-Access-Token': API_KEY
          },
          json=data
      )
      result = response.json()

      if not result['success']:
          error_code = result['error']['code']
          error_message = result['error']['message']
          print(f"Error [{error_code}]: {error_message}")
          print(f"Request ID: {result['requestId']}")

          if error_code == 'INSUFFICIENT_BALANCE':
              print("Please top up your account")
          elif error_code == 'ERR_PHONE':
              print(f"Invalid phone number: {error_message}")
              if 'pattern' in result['error'].get('details', {}):
                  print(f"Expected format: {result['error']['details']['pattern']}")
          elif error_code == 'DUPLICATED_REF':
              print("This order reference was already used")
          else:
              print("An error occurred. Please try again.")
      ```
    </Tab>
  </Tabs>

  ***

  ## أمثلة الهجرة خطوة بخطوة

  ### المثال 1: الحصول على الخطط المتنقلة

  **الخطوة 1 - كودك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/plans/listAll", {
        headers: {
          authorization: API_KEY,
        },
      });

      const data = await response.json();
      const dynamicPlans = data.dymanicPlans; // Note: typo in v2
      const fixedPlans = data.fixedPlans;
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/plans/listAll');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      $dynamicPlans = $data['dymanicPlans']; // Note: typo in v2
      $fixedPlans = $data['fixedPlans'];
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/plans/listAll',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      dynamic_plans = data['dymanicPlans']  # Note: typo in v2
      fixed_plans = data['fixedPlans']
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الـ endpoint: `/v2/plans/listAll` ← `/v3/mobile/plans`
  3. غيّر الرأس: `authorization` ← `X-Access-Token`
  4. أضف فحص النجاح: `if (result.success)`
  5. الوصول عبر data: `data.dymanicPlans` ← `result.data.dynamicPlans` (تم تصحيح الخطأ المطبعي!)

  <Warning>
    **إلزامي**: يصحح v3 الخطأ المطبعي في "dymanicPlans" إلى "dynamicPlans". قم بتحديث كودك لاستخدام الإملاء الصحيح.
  </Warning>

  **الخطوة 3 - كودك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/plans", {
        headers: {
          "X-Access-Token": API_KEY,
        },
      });

      const result = await response.json();
      if (result.success) {
        const dynamicPlans = result.data.dynamicPlans; // Typo fixed!
        const fixedPlans = result.data.fixedPlans;
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/plans');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          $dynamicPlans = $result['data']['dynamicPlans']; // Typo fixed!
          $fixedPlans = $result['data']['fixedPlans'];
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/mobile/plans',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
          dynamic_plans = result['data']['dynamicPlans']  # Typo fixed!
          fixed_plans = result['data']['fixedPlans']
      ```
    </Tab>
  </Tabs>

  ***

  ### المثال 2: إرسال شحن متنقل

  **الخطوة 1 - كودك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://flexy-api.oneclickdz.com/v2/topup/sendTopup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          authorization: API_KEY,
        },
        body: JSON.stringify({
          plan_code: "PREPAID_DJEZZY",
          MSSIDN: "0778037340",
          amount: 500,
          ref: "order-123",
        }),
      });

      const data = await response.json();
      console.log("Topup ID:", data.topupId);
      console.log("New Balance:", data.newBalance);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $data = [
          'plan_code' => 'PREPAID_DJEZZY',
          'MSSIDN' => '0778037340',
          'amount' => 500,
          'ref' => 'order-123'
      ];

      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/sendTopup');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'authorization: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      echo "Topup ID: " . $result['topupId'] . "\n";
      echo "New Balance: " . $result['newBalance'] . "\n";
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      data = {
          'plan_code': 'PREPAID_DJEZZY',
          'MSSIDN': '0778037340',
          'amount': 500,
          'ref': 'order-123'
      }

      response = requests.post(
          'https://flexy-api.oneclickdz.com/v2/topup/sendTopup',
          headers={
              'Content-Type': 'application/json',
              'authorization': API_KEY
          },
          json=data
      )
      result = response.json()

      print(f"Topup ID: {result['topupId']}")
      print(f"New Balance: {result['newBalance']}")
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الـ endpoint: `/v2/topup/sendTopup` ← `/v3/mobile/send`
  3. غيّر الرأس: `authorization` ← `X-Access-Token`
  4. أضف فحص النجاح: `if (result.success)`
  5. الوصول عبر data: `data.topupId` ← `result.data.topupId`
  6. أضف معالجة شاملة للأخطاء

  <Warning>
    **مهم**: تعامل دائماً مع الأخطاء عند إرسال الشحن. مشاكل الشبكة أو الرصيد غير الكافي أو البيانات غير الصالحة قد تسبب الفشل. احفظ `requestId` للتتبع.
  </Warning>

  **الخطوة 3 - كودك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch("https://api.oneclickdz.com/v3/mobile/send", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Access-Token": API_KEY,
        },
        body: JSON.stringify({
          plan_code: "PREPAID_DJEZZY",
          MSSIDN: "0778037340",
          amount: 500,
          ref: "order-123",
        }),
      });

      const result = await response.json();
      if (result.success) {
        console.log("✅ Top-up sent successfully!");
        console.log("Topup ID:", result.data.topupId);
        console.log("New Balance:", result.data.newBalance);
        console.log("Request ID:", result.requestId);
      } else {
        console.error(`❌ Error [${result.error.code}]: ${result.error.message}`);
        console.error("Request ID:", result.requestId);
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/send');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'X-Access-Token: ' . $apiKey
      ]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "✅ Top-up sent successfully!\n";
          echo "Topup ID: " . $result['data']['topupId'] . "\n";
          echo "New Balance: " . $result['data']['newBalance'] . "\n";
          echo "Request ID: " . $result['requestId'] . "\n";
      } else {
          error_log("❌ Error [{$result['error']['code']}]: {$result['error']['message']}");
          error_log("Request ID: " . $result['requestId']);
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.post(
          'https://api.oneclickdz.com/v3/mobile/send',
          headers={
              'Content-Type': 'application/json',
              'X-Access-Token': API_KEY
          },
          json=data
      )
      result = response.json()

      if result['success']:
          print("✅ Top-up sent successfully!")
          print(f"Topup ID: {result['data']['topupId']}")
          print(f"New Balance: {result['data']['newBalance']}")
          print(f"Request ID: {result['requestId']}")
      else:
          print(f"❌ Error [{result['error']['code']}]: {result['error']['message']}")
          print(f"Request ID: {result['requestId']}")
      ```
    </Tab>
  </Tabs>

  ***

  ### المثال 3: فحص حالة الشحن

  **الخطوة 1 - كودك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123",
        {
          headers: { authorization: API_KEY },
        }
      );

      const data = await response.json();
      console.log("Status:", data.topup.status);
      console.log("Phone:", data.topup.MSSIDN);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      echo "Status: " . $data['topup']['status'] . "\n";
      echo "Phone: " . $data['topup']['MSSIDN'] . "\n";
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/topup/checkStatus/REF/order-123',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      print(f"Status: {data['topup']['status']}")
      print(f"Phone: {data['topup']['MSSIDN']}")
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الـ endpoint: `/v2/topup/checkStatus/REF/:ref` ← `/v3/mobile/check-ref/:ref`
  3. غيّر الرأس: `authorization` ← `X-Access-Token`
  4. أضف فحص النجاح: `if (result.success)`
  5. الوصول المباشر: `data.topup.status` ← `result.data.status` (لا مزيد من كائن `topup` المتداخل)
  6. تعامل مع حقول معلومات الاسترداد الجديدة

  <Info>
    **ميزة جديدة**: يتضمن v3 معلومات مفصلة عن الاسترداد مع عروض بديلة مقترحة عند استرداد الشحن.
  </Info>

  **الخطوة 3 - كودك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/mobile/check-ref/order-123",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
        console.log("Status:", result.data.status);
        console.log("Phone:", result.data.MSSIDN);

        // New in v3: Enhanced refund information
        if (result.data.status === "REFUNDED") {
          console.log("❌ Top-up was refunded");
          console.log("Reason:", result.data.refund_message);
          if (result.data.suggested_offers) {
            console.log("💡 Try these offers instead:");
            console.log(result.data.suggested_offers);
          }
        } else if (result.data.status === "FULFILLED") {
          console.log("✅ Top-up completed successfully");
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/check-ref/order-123');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Status: " . $result['data']['status'] . "\n";
          echo "Phone: " . $result['data']['MSSIDN'] . "\n";

          // New in v3: Enhanced refund information
          if ($result['data']['status'] === 'REFUNDED') {
              echo "❌ Top-up was refunded\n";
              echo "Reason: " . $result['data']['refund_message'] . "\n";
              if (isset($result['data']['suggested_offers'])) {
                  echo "💡 Try these offers instead:\n";
                  print_r($result['data']['suggested_offers']);
              }
          } elseif ($result['data']['status'] === 'FULFILLED') {
              echo "✅ Top-up completed successfully\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/mobile/check-ref/order-123',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
          print(f"Status: {result['data']['status']}")
          print(f"Phone: {result['data']['MSSIDN']}")

          # New in v3: Enhanced refund information
          if result['data']['status'] == 'REFUNDED':
              print("❌ Top-up was refunded")
              print(f"Reason: {result['data']['refund_message']}")
              if 'suggested_offers' in result['data']:
                  print("💡 Try these offers instead:")
                  print(result['data']['suggested_offers'])
          elif result['data']['status'] == 'FULFILLED':
              print("✅ Top-up completed successfully")
      ```
    </Tab>
  </Tabs>

  ***

  ### المثال 4: قائمة المعاملات مع الترقيم

  **الخطوة 1 - كودك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20",
        {
          headers: { authorization: API_KEY },
        }
      );

      const data = await response.json();
      console.log("Transactions:", data.transactions);
      console.log("Total:", data.totalResults);
      console.log("Page:", data.currentPage);
      console.log("Pages:", data.totalPages);
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $data = json_decode($response, true);

      echo "Transactions: " . count($data['transactions']) . "\n";
      echo "Total: " . $data['totalResults'] . "\n";
      echo "Page: " . $data['currentPage'] . "\n";
      echo "Pages: " . $data['totalPages'] . "\n";
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/account/transactions?page=1&pageSize=20',
          headers={'authorization': API_KEY}
      )
      data = response.json()

      print(f"Transactions: {len(data['transactions'])}")
      print(f"Total: {data['totalResults']}")
      print(f"Page: {data['currentPage']}")
      print(f"Pages: {data['totalPages']}")
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الإصدار: `/v2/account/transactions` ← `/v3/account/transactions`
  3. غيّر الرأس: `authorization` ← `X-Access-Token`
  4. أضف فحص النجاح: `if (result.success)`
  5. الوصول للعناصر: `data.transactions` ← `result.data.items`
  6. الوصول للترقيم: الحقول على مستوى الجذر ← كائن `result.data.pagination`

  <Warning>
    **تغيير جذري**: انتقلت بنية الترقيم من المستوى الجذري إلى `data.pagination`. قم بتحديث جميع منطق القوائم/الترقيم.
  </Warning>

  **الخطوة 3 - كودك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
        console.log("Transactions:", result.data.items);
        console.log("Total:", result.data.pagination.totalResults);
        console.log("Page:", result.data.pagination.page);
        console.log("Pages:", result.data.pagination.totalPages);
        console.log("Page Size:", result.data.pagination.pageSize);
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          echo "Transactions: " . count($result['data']['items']) . "\n";
          echo "Total: " . $result['data']['pagination']['totalResults'] . "\n";
          echo "Page: " . $result['data']['pagination']['page'] . "\n";
          echo "Pages: " . $result['data']['pagination']['totalPages'] . "\n";
          echo "Page Size: " . $result['data']['pagination']['pageSize'] . "\n";
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/account/transactions?page=1&pageSize=20',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
          print(f"Transactions: {len(result['data']['items'])}")
          print(f"Total: {result['data']['pagination']['totalResults']}")
          print(f"Page: {result['data']['pagination']['page']}")
          print(f"Pages: {result['data']['pagination']['totalPages']}")
          print(f"Page Size: {result['data']['pagination']['pageSize']}")
      ```
    </Tab>
  </Tabs>

  ***

  ### المثال 5: فحص منتجات الإنترنت

  **الخطوة 1 - كودك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL",
        {
          headers: { authorization: API_KEY },
        }
      );

      const cards = await response.json(); // Direct array
      cards.forEach((card) => {
        console.log(`${card.value} DA - Available: ${card.available}`);
      });
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['authorization: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $cards = json_decode($response, true); // Direct array

      foreach ($cards as $card) {
          echo $card['value'] . " DA - Available: " . $card['available'] . "\n";
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://flexy-api.oneclickdz.com/v2/internet/checkCards/ADSL',
          headers={'authorization': API_KEY}
      )
      cards = response.json()  # Direct array

      for card in cards:
          print(f"{card['value']} DA - Available: {card['available']}")
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الـ endpoint: `/v2/internet/checkCards/:type` ← `/v3/internet/products?type=:type`
  3. من معامل المسار إلى معامل الاستعلام: `/ADSL` ← `?type=ADSL`
  4. غيّر الرأس: `authorization` ← `X-Access-Token`
  5. أضف فحص النجاح: `if (result.success)`
  6. الوصول للمصفوفة: مصفوفة مباشرة ← `result.data.products`

  <Info>
    **تصميم API**: يستخدم v3 معاملات الاستعلام بدلاً من معاملات المسار لاختيار النوع، مما يسهّل إضافة الفلاتر مستقبلاً.
  </Info>

  **الخطوة 3 - كودك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      const response = await fetch(
        "https://api.oneclickdz.com/v3/internet/products?type=ADSL",
        {
          headers: { "X-Access-Token": API_KEY },
        }
      );

      const result = await response.json();
      if (result.success) {
        result.data.products.forEach((card) => {
          console.log(`${card.value} DA - Available: ${card.available}`);
        });
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      $ch = curl_init('https://api.oneclickdz.com/v3/internet/products?type=ADSL');
      curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Access-Token: ' . $apiKey]);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      $response = curl_exec($ch);
      $result = json_decode($response, true);

      if ($result['success']) {
          foreach ($result['data']['products'] as $card) {
              echo $card['value'] . " DA - Available: " . $card['available'] . "\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      response = requests.get(
          'https://api.oneclickdz.com/v3/internet/products?type=ADSL',
          headers={'X-Access-Token': API_KEY}
      )
      result = response.json()

      if result['success']:
          for card in result['data']['products']:
              print(f"{card['value']} DA - Available: {card['available']}")
      ```
    </Tab>
  </Tabs>

  ***

  ## هجرة عميل API الخاص بك

  إليك كيفية تحديث wrapper عميل API الخاص بك:

  **الخطوة 1 - عميلك الحالي في v2:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      class FlexyAPI {
        constructor(apiKey) {
          this.apiKey = apiKey;
          this.baseUrl = "https://flexy-api.oneclickdz.com";
        }

        async request(endpoint, options = {}) {
          const response = await fetch(`${this.baseUrl}${endpoint}`, {
            ...options,
            headers: {
              ...options.headers,
              authorization: this.apiKey,
            },
          });
          return response.json();
        }

        async getBalance() {
          const data = await this.request("/v2/account/balance");
          return data.balance;
        }

        async sendTopup(params) {
          return await this.request("/v2/topup/sendTopup", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(params),
          });
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      class FlexyAPI {
          private $apiKey;
          private $baseUrl = 'https://flexy-api.oneclickdz.com';

          public function __construct($apiKey) {
              $this->apiKey = $apiKey;
          }

          private function request($endpoint, $options = []) {
              $ch = curl_init($this->baseUrl . $endpoint);
              curl_setopt($ch, CURLOPT_HTTPHEADER, [
                  'authorization: ' . $this->apiKey
              ]);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

              if (isset($options['method']) && $options['method'] === 'POST') {
                  curl_setopt($ch, CURLOPT_POST, true);
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $options['body']);
              }

              $response = curl_exec($ch);
              return json_decode($response, true);
          }

          public function getBalance() {
              $data = $this->request('/v2/account/balance');
              return $data['balance'];
          }

          public function sendTopup($params) {
              return $this->request('/v2/topup/sendTopup', [
                  'method' => 'POST',
                  'body' => json_encode($params)
              ]);
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      import requests

      class FlexyAPI:
          def __init__(self, api_key):
              self.api_key = api_key
              self.base_url = 'https://flexy-api.oneclickdz.com'

          def request(self, endpoint, method='GET', data=None):
              headers = {'authorization': self.api_key}
              url = f"{self.base_url}{endpoint}"

              if method == 'GET':
                  response = requests.get(url, headers=headers)
              else:
                  headers['Content-Type'] = 'application/json'
                  response = requests.post(url, headers=headers, json=data)

              return response.json()

          def get_balance(self):
              data = self.request('/v2/account/balance')
              return data['balance']

          def send_topup(self, params):
              return self.request('/v2/topup/sendTopup', method='POST', data=params)
      ```
    </Tab>
  </Tabs>

  **الخطوة 2 - ما الذي يجب تغييره:**

  1. غيّر عنوان URL الأساسي: `https://flexy-api.oneclickdz.com` ← `https://api.oneclickdz.com`
  2. غيّر الرأس: `authorization` ← `X-Access-Token`
  3. أضف معالجة غلاف الاستجابة في الـ method `request()`
  4. تحقق من `result.success` وتعامل مع الأخطاء
  5. حدّث جميع مسارات الـ endpoint إلى v3
  6. ألقِ أخطاء منظّمة مع أكواد ومعرّفات الطلبات

  <Note>
    **أفضل الممارسات**: مركِّز معالجة الأخطاء في عميل API الخاص بك. هذا يسهّل إضافة التسجيل والمراقبة وإشعارات المستخدم.
  </Note>

  **الخطوة 3 - عميلك الجديد في v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      class FlexyAPI {
        constructor(apiKey) {
          this.apiKey = apiKey;
          this.baseUrl = "https://api.oneclickdz.com";
        }

        async request(endpoint, options = {}) {
          const response = await fetch(`${this.baseUrl}${endpoint}`, {
            ...options,
            headers: {
              ...options.headers,
              "X-Access-Token": this.apiKey,
            },
          });

          const result = await response.json();

          if (!result.success) {
            const error = new Error(result.error.message);
            error.code = result.error.code;
            error.details = result.error.details;
            error.requestId = result.requestId;
            throw error;
          }

          return result.data;
        }

        async getBalance() {
          const data = await this.request("/v3/account/balance");
          return data.balance;
        }

        async sendTopup(params) {
          return await this.request("/v3/mobile/send", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(params),
          });
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      class FlexyAPI {
          private $apiKey;
          private $baseUrl = 'https://api.oneclickdz.com';

          public function __construct($apiKey) {
              $this->apiKey = $apiKey;
          }

          private function request($endpoint, $options = []) {
              $ch = curl_init($this->baseUrl . $endpoint);
              $headers = ['X-Access-Token: ' . $this->apiKey];

              if (isset($options['method']) && $options['method'] === 'POST') {
                  curl_setopt($ch, CURLOPT_POST, true);
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $options['body']);
                  $headers[] = 'Content-Type: application/json';
              }

              curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
              curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
              $response = curl_exec($ch);
              $result = json_decode($response, true);

              if (!$result['success']) {
                  throw new Exception(json_encode([
                      'message' => $result['error']['message'],
                      'code' => $result['error']['code'],
                      'details' => $result['error']['details'] ?? null,
                      'requestId' => $result['requestId']
                  ]));
              }

              return $result['data'];
          }

          public function getBalance() {
              $data = $this->request('/v3/account/balance');
              return $data['balance'];
          }

          public function sendTopup($params) {
              return $this->request('/v3/mobile/send', [
                  'method' => 'POST',
                  'body' => json_encode($params)
              ]);
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      import requests

      class FlexyAPIError(Exception):
          def __init__(self, message, code, details=None, request_id=None):
              super().__init__(message)
              self.code = code
              self.details = details
              self.request_id = request_id

      class FlexyAPI:
          def __init__(self, api_key):
              self.api_key = api_key
              self.base_url = 'https://api.oneclickdz.com'

          def request(self, endpoint, method='GET', data=None):
              headers = {'X-Access-Token': self.api_key}
              url = f"{self.base_url}{endpoint}"

              if method == 'GET':
                  response = requests.get(url, headers=headers)
              else:
                  headers['Content-Type'] = 'application/json'
                  response = requests.post(url, headers=headers, json=data)

              result = response.json()

              if not result['success']:
                  raise FlexyAPIError(
                      result['error']['message'],
                      result['error']['code'],
                      result['error'].get('details'),
                      result['requestId']
                  )

              return result['data']

          def get_balance(self):
              data = self.request('/v3/account/balance')
              return data['balance']

          def send_topup(self, params):
              return self.request('/v3/mobile/send', method='POST', data=params)
      ```
    </Tab>
  </Tabs>

  ***

  ## مرجع أكواد الخطأ

  أخطاء v2 الشائعة ومكافئاتها في v3:

  | خطأ v2                   | كود خطأ v3             | ما الذي تغيّر                            |
  | ------------------------ | ---------------------- | ---------------------------------------- |
  | `"NO-BALANCE"`           | `INSUFFICIENT_BALANCE` | الآن كود مع رسالة منظّمة                 |
  | `"DUPLICATED-REF"`       | `DUPLICATED_REF`       | نفس الكود، الآن مع كائن details          |
  | `"ERR_VALIDATION"`       | `ERR_VALIDATION`       | يتضمن `details.field` و`details.pattern` |
  | `"ERR_PHONE"`            | `ERR_PHONE`            | يتضمن نمط التحقق في التفاصيل             |
  | `"ERR_STOCK"`            | `ERR_STOCK`            | معلومات توفر المنتج                      |
  | `"Forbidden"`            | `ERR_AUTH`             | أكثر وصفاً، أخطاء مصادقة موحّدة          |
  | `"Access token missing"` | `ERR_AUTH`             | نفس الكود لجميع أخطاء المصادقة           |
  | `"NOT_FOUND"`            | `NOT_FOUND`            | المورد غير موجود (طلب، منتج، إلخ.)       |

  **كيفية التعامل مع أخطاء v3:**

  <Tabs>
    <Tab title="JavaScript">
      ```javascript theme={null}
      // v2 way:
      if (result.error === "NO-BALANCE") {
        // handle
      }

      // v3 way:
      if (!result.success && result.error.code === "INSUFFICIENT_BALANCE") {
        console.log("Request ID:", result.requestId); // Save for support
        if (result.error.details?.currentBalance) {
          console.log("Current balance:", result.error.details.currentBalance);
        }
      }
      ```
    </Tab>

    <Tab title="PHP">
      ```php theme={null}
      // v2 way:
      if ($result['error'] === 'NO-BALANCE') {
          // handle
      }

      // v3 way:
      if (!$result['success'] && $result['error']['code'] === 'INSUFFICIENT_BALANCE') {
          error_log("Request ID: " . $result['requestId']);
          if (isset($result['error']['details']['currentBalance'])) {
              echo "Current balance: " . $result['error']['details']['currentBalance'] . "\n";
          }
      }
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={null}
      # v2 way:
      if result.get('error') == 'NO-BALANCE':
          # handle

      # v3 way:
      if not result['success'] and result['error']['code'] == 'INSUFFICIENT_BALANCE':
          print(f"Request ID: {result['requestId']}")
          if 'currentBalance' in result['error'].get('details', {}):
              print(f"Current balance: {result['error']['details']['currentBalance']}")
      ```
    </Tab>
  </Tabs>

  ***

  <Warning>
    **موعد نهائي حرج**: بعد 30 أكتوبر 2026، ستفشل جميع طلبات API v2. خطّط لهجرتك وفقاً لذلك لتجنب انقطاع الخدمة.
  </Warning>

  ***

  ## مشاكل الهجرة الشائعة وحلولها

  <AccordionGroup>
    <Accordion title="مشكلة: أخطاء 401 غير مصرح به" icon="circle-exclamation">
      **المشكلة**: تم تغيير الـ endpoint لكن لم يتم تحديث اسم الرأس.

      **الحل**: استبدل `authorization` بـ `X-Access-Token` في جميع الطلبات.

      ```javascript theme={null}
      // ❌ Wrong
      headers: { authorization: API_KEY }

      // ✅ Correct
      headers: { "X-Access-Token": API_KEY }
      ```
    </Accordion>

    <Accordion title="مشكلة: الحصول على 'undefined' عند الوصول للبيانات" icon="circle-exclamation">
      **المشكلة**: محاولة الوصول للبيانات مباشرة بدون المرور بـ `result.data`.

      **الحل**: الوصول دائماً لبيانات الاستجابة عبر خاصية `data`.

      ```javascript theme={null}
      // ❌ Wrong
      const balance = result.balance;

      // ✅ Correct
      const balance = result.data.balance;
      ```
    </Accordion>

    <Accordion title="مشكلة: الترقيم لا يعمل" icon="circle-exclamation">
      **المشكلة**: البحث عن حقول الترقيم على المستوى الجذري.

      **الحل**: الوصول للترقيم عبر `data.pagination`.

      ```javascript theme={null}
      // ❌ Wrong
      const total = result.totalResults;
      const page = result.currentPage;

      // ✅ Correct
      const total = result.data.pagination.totalResults;
      const page = result.data.pagination.page;
      ```
    </Accordion>

    <Accordion title="مشكلة: معالجة الأخطاء لا تعمل" icon="circle-exclamation">
      **المشكلة**: التحقق من تنسيق الخطأ القديم.

      **الحل**: تحقق من البوليان `success` وادخل إلى كائن الخطأ المنظّم.

      ```javascript theme={null}
      // ❌ Wrong
      if (result.error) {
        console.log(result.message);
      }

      // ✅ Correct
      if (!result.success) {
        console.log(result.error.code, result.error.message);
        console.log("Request ID:", result.requestId);
      }
      ```
    </Accordion>

    <Accordion title="مشكلة: أخطاء 404 غير موجود" icon="circle-exclamation">
      **المشكلة**: استخدام مسارات الـ endpoint القديمة في v2.

      **الحل**: حدّث جميع المسارات وفقاً لجدول المرجع أعلاه.

      ```javascript theme={null}
      // ❌ Wrong
      POST /v2/topup/sendTopup
      GET /v2/internet/checkCards/ADSL

      // ✅ Correct
      POST /v3/mobile/send
      GET /v3/internet/products?type=ADSL
      ```
    </Accordion>
  </AccordionGroup>

  ***

  ***

  ## مرجع الـ endpoints الكامل

  | الخدمة             | الـ endpoint في v2                      | الـ endpoint في v3                            | ملاحظات                                  |
  | ------------------ | --------------------------------------- | --------------------------------------------- | ---------------------------------------- |
  | **المصادقة**       |                                         |                                               |                                          |
  | الرأس              | `authorization: KEY`                    | `X-Access-Token: KEY`                         | اسم الرأس تغيّر                          |
  | التحقق             | `GET /v2/validate`                      | `GET /v3/validate`                            | الاستجابة مُغلَّفة                       |
  | **الجوال**         |                                         |                                               |                                          |
  | قائمة الخطط        | `GET /v2/plans/listAll`                 | `GET /v3/mobile/plans`                        | المسار تغيّر، خطأ إملائي مُصحَّح         |
  | إرسال شحنة         | `POST /v2/topup/sendTopup`              | `POST /v3/mobile/send`                        | المسار مُبسَّط                           |
  | التحقق بالمرجع     | `GET /v2/topup/checkStatus/REF/:ref`    | `GET /v3/mobile/check-ref/:ref`               | المسار مُبسَّط، معلومات الاسترداد أُضيفت |
  | التحقق بالمعرِّف   | `GET /v2/topup/checkStatus/ID/:id`      | `GET /v3/mobile/check-id/:id`                 | المسار مُبسَّط                           |
  | قائمة الشحنات      | `GET /v2/topup/list`                    | `GET /v3/mobile/list`                         | الترقيم انتقل إلى `data.pagination`      |
  | **الإنترنت**       |                                         |                                               |                                          |
  | المنتجات           | `GET /v2/internet/checkCards/:type`     | `GET /v3/internet/products?type=`             | معامل المسار ← معامل الاستعلام           |
  | التحقق من الرقم    | `GET /v2/internet/checkNumber/:t/:n`    | `GET /v3/internet/check-number?type=&number=` | معاملات المسار ← معاملات الاستعلام       |
  | الإرسال            | `POST /v2/internet/sendTopup`           | `POST /v3/internet/send`                      | المسار مُبسَّط                           |
  | التحقق بالمرجع     | `GET /v2/internet/checkStatus/REF/:ref` | `GET /v3/internet/check-ref/:ref`             | المسار مُبسَّط                           |
  | التحقق بالمعرِّف   | `GET /v2/internet/checkStatus/ID/:id`   | `GET /v3/internet/check-id/:id`               | المسار مُبسَّط                           |
  | القائمة            | `GET /v2/internet/list`                 | `GET /v3/internet/list`                       | الترقيم انتقل                            |
  | **بطاقات الهدايا** |                                         |                                               |                                          |
  | الكتالوج           | `GET /v2/gift-cards/catalogue`          | `GET /v3/gift-cards/catalog`                  | الإملاء مُصحَّح                          |
  | التحقق من المنتج   | `GET /v2/gift-cards/checkProduct/:id`   | `GET /v3/gift-cards/checkProduct/:id`         | الاستجابة مُغلَّفة                       |
  | تقديم الطلب        | `POST /v2/gift-cards/placeOrder`        | `POST /v3/gift-cards/placeOrder`              | الاستجابة مُغلَّفة                       |
  | التحقق من الطلب    | `GET /v2/gift-cards/checkOrder/:id`     | `GET /v3/gift-cards/checkOrder/:id`           | الاستجابة مُغلَّفة                       |
  | قائمة الطلبات      | `GET /v2/gift-cards/list`               | `GET /v3/gift-cards/list`                     | الترقيم انتقل                            |
  | **الحساب**         |                                         |                                               |                                          |
  | الرصيد             | `GET /v2/account/balance`               | `GET /v3/account/balance`                     | الاستجابة مُغلَّفة                       |
  | المعاملات          | `GET /v2/account/transactions`          | `GET /v3/account/transactions`                | الترقيم انتقل                            |

  ***

  ## قائمة التحقق من الاختبار

  قبل النشر في الإنتاج، تحقق من:

  * [ ] جميع رؤوس المصادقة غُيِّرت إلى `X-Access-Token`
  * [ ] جميع مسارات الـ endpoints حُدِّثت إلى v3
  * [ ] التحقق من النجاح/الخطأ مُطبَّق في كل مكان
  * [ ] البيانات يمكن الوصول إليها عبر `result.data`
  * [ ] الترقيم يمكن الوصول إليه عبر `result.data.pagination`
  * [ ] أكواد الخطأ مُعالَجة مع `result.error.code`
  * [ ] معرِّفات الطلبات مسجَّلة لأغراض التصحيح
  * [ ] تم الاختبار في وضع sandbox أولاً
  * [ ] جميع الوظائف الموجودة لا تزال تعمل
  * [ ] سيناريوهات الخطأ مختبَرة (رصيد غير كافٍ، بيانات غير صالحة، إلخ)

  ***

  ## تحتاج مساعدة؟

  <CardGroup cols={2}>
    <Card title="وثائق API v3" href="/ar/quickstart" icon="book">
      مرجع v3 الكامل والأمثلة
    </Card>

    <Card title="دليل معالجة الأخطاء" href="/ar/api-reference/error-handling" icon="shield-check">
      أفضل الممارسات لمعالجة الأخطاء
    </Card>

    <Card title="إعدادات لوحة التحكم" icon="gear">
      **الوصول**: سجِّل الدخول إلى لوحة التحكم

      **إنشاء مفتاح sandbox**: أنشئ مفتاحاً للاختبار الآمن

      **القائمة البيضاء لعناوين IP**: أضف قيود IP لأمان معزّز
    </Card>

    <Card title="الدعم" icon="headset">
      **البريد الإلكتروني**: [support@oneclickdz.com](mailto:support@oneclickdz.com)

      **مهم**: أدرج دائماً معرِّف الطلب عند الإبلاغ عن مشكلات
    </Card>
  </CardGroup>

  <Info>
    **دعم الهجرة**: فريقنا هنا للمساعدة! راسلنا بالبريد الإلكتروني مع "دعم هجرة API v3" في سطر الموضوع، وأدرج: - تفاصيل تطبيقك الحالي - الأخطاء المحددة (مع معرِّفات الطلبات) - نماذج الكود التي تُظهر المشكلة
  </Info>
</div>
