> ## 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.

# Step 1: Loading Mobile Plans

> Fetch and cache available mobile top-up plans with pricing

## Overview

The first step in integrating mobile top-ups is to fetch the list of available plans from the API. Plans include all operators (Mobilis, Djezzy, Ooredoo, Pixx) with both dynamic and fixed amount options.

<Info>
  Plans are stable and rarely change. **Cache them in your database** to reduce API calls and improve performance.
</Info>

<Card title="API Reference" icon="book" href="/en/api-reference/mobile/list-plans">
  View complete API documentation for the **GET /v3/mobile/plans** endpoint
</Card>

## Understanding Plan Types

### Dynamic Plans

Dynamic plans allow variable amounts within a min/max range:

```json theme={null}
{
  "code": "PREPAID_DJEZZY",
  "name": "Djezzy Prepaid",
  "operator": "Djezzy",
  "cost": 0.98,
  "isEnabled": true,
  "min_amount": 50,
  "max_amount": 5000
}
```

**Use cases:**

* Prepaid top-ups (credit)
* Postpaid bill payments (facture)
* International calling credit

### Fixed Plans

Fixed plans have predetermined amounts:

```json theme={null}
{
  "code": "PIXX_500",
  "name": "Pixx 500 DA",
  "operator": "Pixx",
  "cost": 0.97,
  "isEnabled": true,
  "amount": 500
}
```

**Use cases:**

* Special promotional offers
* Data packs
* Service activations

### GetMenu Plans

Special plans that retrieve available offers for a specific number:

```json theme={null}
{
  "code": "GETMENU_Mobilis",
  "name": "Mobilis GetMenu",
  "operator": "Mobilis",
  "cost": 0.98,
  "isEnabled": true,
  "min_amount": 50,
  "max_amount": 5000
}
```

**Returns:** Array of `suggested_offers` with all available plans for that specific number.

## Fetching Plans from API

### Basic Request

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.oneclickdz.com/v3/mobile/plans \
    -H "X-Access-Token: YOUR_API_KEY"
  ```

  ```javascript Node.js theme={null}
  const fetch = require('node-fetch');

  async function fetchMobilePlans() {
    const response = await fetch('https://api.oneclickdz.com/v3/mobile/plans', {
      headers: {
        'X-Access-Token': process.env.ONECLICKDZ_API_KEY
      }
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    
    if (!data.success) {
      throw new Error('Failed to fetch plans');
    }

    return {
      dynamicPlans: data.data.dynamicPlans,
      fixedPlans: data.data.fixedPlans
    };
  }

  // Usage
  const { dynamicPlans, fixedPlans } = await fetchMobilePlans();
  console.log(`Loaded ${dynamicPlans.length} dynamic plans and ${fixedPlans.length} fixed plans`);
  ```

  ```python Python theme={null}
  import requests
  import os

  def fetch_mobile_plans():
      """Fetch mobile plans from API"""
      response = requests.get(
          'https://api.oneclickdz.com/v3/mobile/plans',
          headers={'X-Access-Token': os.getenv('ONECLICKDZ_API_KEY')}
      )
      
      response.raise_for_status()
      data = response.json()
      
      if not data['success']:
          raise Exception('Failed to fetch plans')
      
      return {
          'dynamic_plans': data['data']['dynamicPlans'],
          'fixed_plans': data['data']['fixedPlans']
      }

  # Usage
  plans = fetch_mobile_plans()
  print(f"Loaded {len(plans['dynamic_plans'])} dynamic and {len(plans['fixed_plans'])} fixed plans")
  ```

  ```php PHP theme={null}
  <?php

  function fetchMobilePlans() {
      $ch = curl_init('https://api.oneclickdz.com/v3/mobile/plans');
      
      curl_setopt_array($ch, [
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_HTTPHEADER => [
              'X-Access-Token: ' . getenv('ONECLICKDZ_API_KEY')
          ]
      ]);
      
      $response = curl_exec($ch);
      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
      
      if ($httpCode !== 200) {
          throw new Exception("HTTP error! status: $httpCode");
      }
      
      $data = json_decode($response, true);
      
      if (!$data['success']) {
          throw new Exception('Failed to fetch plans');
      }
      
      return [
          'dynamic_plans' => $data['data']['dynamicPlans'],
          'fixed_plans' => $data['data']['fixedPlans']
      ];
  }

  // Usage
  $plans = fetchMobilePlans();
  echo "Loaded " . count($plans['dynamic_plans']) . " dynamic and " . count($plans['fixed_plans']) . " fixed plans\n";
  ```
</CodeGroup>

### Response Structure

```json theme={null}
{
  "success": true,
  "data": {
    "dynamicPlans": [
      {
        "code": "PREPAID_MOBILIS",
        "name": "📱 PREPAID | عادي",
        "operator": "Mobilis",
        "cost": 0.96,
        "isEnabled": true,
        "min_amount": 40,
        "max_amount": 3999
      },
      {
        "code": "GROS_MOBILIS",
        "name": "📱 GROS MOBILIS | جملة",
        "operator": "GMobilis",
        "isEnabled": true,
        "min_amount": 5000,
        "max_amount": 300000
      }
    ],
    "fixedPlans": [
      {
        "code": "MIX500_MOBILIS",
        "name": "📱🌐 AUTO | MIX 500",
        "operator": "Mobilis",
        "isEnabled": true,
        "cost": 0.96,
        "amount": 500
      },
      {
        "code": "MIX1000_OOREDOO",
        "name": "📱🌐 AUTO | MIX 1000",
        "operator": "Ooredoo",
        "isEnabled": true,
        "cost": 0.99,
        "amount": 1000
      }
    ]
  },
  "meta": {
    "timestamp": "2025-10-29T00:35:59.220Z"
  }
}
```

## Understanding the Cost Field

The `cost` field represents your wholesale price multiplier:

<Tabs>
  <Tab title="How It Works">
    **Example: cost = 0.98**

    For a 1000 DZD top-up:

    * Face value: 1000 DZD (what user receives)
    * Your cost: 1000 × 0.98 = 980 DZD (what you pay)
    * Your margin: 1000 - 980 = 20 DZD (2%)
  </Tab>

  <Tab title="Calculating Sell Price">
    **Add your markup:**

    ```javascript theme={null}
    const faceValue = 1000;
    const cost = 0.98;
    const ourCost = faceValue * cost; // 980 DZD

    // Add 5% profit margin
    const markup = 0.05;
    const sellPrice = ourCost * (1 + markup); // 1029 DZD
    const profit = sellPrice - ourCost; // 49 DZD
    ```
  </Tab>

  <Tab title="Important Note">
    <Warning>
      **Never expose the `cost` field to end users!**

      This is your wholesale pricing. Always calculate and display your own retail prices.
    </Warning>
  </Tab>
</Tabs>

## Caching Plans in Database

Since plans rarely change, cache them locally with your pricing:

### Database Schema

<CodeGroup>
  ```sql SQL theme={null}
  CREATE TABLE mobile_plans (
      id SERIAL PRIMARY KEY,
      code VARCHAR(100) UNIQUE NOT NULL,
      name VARCHAR(255) NOT NULL,
      operator VARCHAR(50) NOT NULL,
      type VARCHAR(20) NOT NULL, -- 'dynamic' or 'fixed'
      
      -- Cost info
      wholesale_cost DECIMAL(5,4) NOT NULL,
      sell_price_multiplier DECIMAL(5,4) NOT NULL,
      
      -- Amount limits
      min_amount INTEGER,
      max_amount INTEGER,
      fixed_amount INTEGER,
      
      -- Status
      is_enabled BOOLEAN DEFAULT true,
      is_visible BOOLEAN DEFAULT true,
      
      -- Metadata
      created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      last_synced_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  );

  CREATE INDEX idx_mobile_plans_operator ON mobile_plans(operator);
  CREATE INDEX idx_mobile_plans_enabled ON mobile_plans(is_enabled);
  CREATE INDEX idx_mobile_plans_code ON mobile_plans(code);
  ```

  ```javascript MongoDB (Mongoose) theme={null}
  const mobilePlanSchema = new mongoose.Schema({
    code: { type: String, required: true, unique: true },
    name: { type: String, required: true },
    operator: { type: String, required: true, index: true },
    type: { type: String, enum: ['dynamic', 'fixed'], required: true },
    
    wholesaleCost: { type: Number, required: true },
    sellPriceMultiplier: { type: Number, required: true },
    
    minAmount: { type: Number },
    maxAmount: { type: Number },
    fixedAmount: { type: Number },
    
    isEnabled: { type: Boolean, default: true, index: true },
    isVisible: { type: Boolean, default: true },
    
    lastSyncedAt: { type: Date, default: Date.now }
  }, {
    timestamps: true
  });

  const MobilePlan = mongoose.model('MobilePlan', mobilePlanSchema);
  ```
</CodeGroup>

### Sync Function

<CodeGroup>
  ```javascript Node.js theme={null}
  const db = require('./database');

  async function syncMobilePlans() {
    try {
      console.log('🔄 Syncing mobile plans...');
      
      // Fetch plans from API
      const plans = await fetchMobilePlans();
      
      // Calculate your pricing
      const PROFIT_MARGIN = 0.05; // 5% profit
      
      for (const plan of plans) {
        const isFixed = !!plan.amount;
        
        const planData = {
          code: plan.code,
          name: plan.name,
          operator: plan.operator,
          type: isFixed ? 'fixed' : 'dynamic',
          wholesaleCost: plan.cost,
          sellPriceMultiplier: plan.cost * (1 + PROFIT_MARGIN),
          minAmount: plan.min_amount || null,
          maxAmount: plan.max_amount || null,
          fixedAmount: plan.amount || null,
          isEnabled: plan.isEnabled,
          lastSyncedAt: new Date()
        };
        
        // Upsert (insert or update)
        await db.mobilePlans.upsert({
          where: { code: plan.code },
          update: planData,
          create: planData
        });
      }
      
      console.log(`✅ Successfully synced ${plans.length} plans`);
      
      // Log statistics
      const stats = {
        total: plans.length,
        dynamic: plans.filter(p => !p.amount).length,
        fixed: plans.filter(p => p.amount).length,
        enabled: plans.filter(p => p.isEnabled).length
      };
      
      console.log('📊 Plan statistics:', stats);
      
      return stats;
    } catch (error) {
      console.error('❌ Failed to sync plans:', error);
      throw error;
    }
  }

  // Run sync on startup
  syncMobilePlans();

  // Schedule daily sync at midnight
  const cron = require('node-cron');
  cron.schedule('0 0 * * *', () => {
    console.log('⏰ Running scheduled plan sync...');
    syncMobilePlans();
  });
  ```

  ```python Python theme={null}
  from datetime import datetime
  import schedule
  import time

  def sync_mobile_plans():
      """Sync mobile plans to database"""
      try:
          print('🔄 Syncing mobile plans...')
          
          # Fetch plans from API
          plans = fetch_mobile_plans()
          
          # Calculate your pricing
          PROFIT_MARGIN = 0.05  # 5% profit
          
          for plan in plans:
              is_fixed = 'amount' in plan
              
              plan_data = {
                  'code': plan['code'],
                  'name': plan['name'],
                  'operator': plan['operator'],
                  'type': 'fixed' if is_fixed else 'dynamic',
                  'wholesale_cost': plan['cost'],
                  'sell_price_multiplier': plan['cost'] * (1 + PROFIT_MARGIN),
                  'min_amount': plan.get('min_amount'),
                  'max_amount': plan.get('max_amount'),
                  'fixed_amount': plan.get('amount'),
                  'is_enabled': plan['isEnabled'],
                  'last_synced_at': datetime.now()
              }
              
              # Upsert to database
              db.mobile_plans.upsert(
                  filter={'code': plan['code']},
                  data=plan_data
              )
          
          print(f'✅ Successfully synced {len(plans)} plans')
          
          # Log statistics
          stats = {
              'total': len(plans),
              'dynamic': len([p for p in plans if 'amount' not in p]),
              'fixed': len([p for p in plans if 'amount' in p]),
              'enabled': len([p for p in plans if p['isEnabled']])
          }
          
          print('📊 Plan statistics:', stats)
          
          return stats
          
      except Exception as error:
          print(f'❌ Failed to sync plans: {error}')
          raise

  # Run sync on startup
  sync_mobile_plans()

  # Schedule daily sync at midnight
  schedule.every().day.at("00:00").do(sync_mobile_plans)

  # Keep scheduler running
  while True:
      schedule.run_pending()
      time.sleep(60)
  ```

  ```php PHP theme={null}
  <?php

  function syncMobilePlans($db) {
      try {
          echo "🔄 Syncing mobile plans...\n";
          
          // Fetch plans from API
          $plans = fetchMobilePlans();
          
          // Calculate your pricing
          $profitMargin = 0.05; // 5% profit
          
          foreach ($plans as $plan) {
              $isFixed = isset($plan['amount']);
              
              $planData = [
                  'code' => $plan['code'],
                  'name' => $plan['name'],
                  'operator' => $plan['operator'],
                  'type' => $isFixed ? 'fixed' : 'dynamic',
                  'wholesale_cost' => $plan['cost'],
                  'sell_price_multiplier' => $plan['cost'] * (1 + $profitMargin),
                  'min_amount' => $plan['min_amount'] ?? null,
                  'max_amount' => $plan['max_amount'] ?? null,
                  'fixed_amount' => $plan['amount'] ?? null,
                  'is_enabled' => $plan['isEnabled'],
                  'last_synced_at' => date('Y-m-d H:i:s')
              ];
              
              // Upsert to database
              $db->query(
                  "INSERT INTO mobile_plans 
                  (code, name, operator, type, wholesale_cost, sell_price_multiplier, 
                   min_amount, max_amount, fixed_amount, is_enabled, last_synced_at)
                  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                  ON DUPLICATE KEY UPDATE
                  name = VALUES(name),
                  operator = VALUES(operator),
                  type = VALUES(type),
                  wholesale_cost = VALUES(wholesale_cost),
                  sell_price_multiplier = VALUES(sell_price_multiplier),
                  min_amount = VALUES(min_amount),
                  max_amount = VALUES(max_amount),
                  fixed_amount = VALUES(fixed_amount),
                  is_enabled = VALUES(is_enabled),
                  last_synced_at = VALUES(last_synced_at)",
                  array_values($planData)
              );
          }
          
          echo "✅ Successfully synced " . count($plans) . " plans\n";
          
          // Log statistics
          $stats = [
              'total' => count($plans),
              'dynamic' => count(array_filter($plans, fn($p) => !isset($p['amount']))),
              'fixed' => count(array_filter($plans, fn($p) => isset($p['amount']))),
              'enabled' => count(array_filter($plans, fn($p) => $p['isEnabled']))
          ];
          
          echo "📊 Plan statistics: " . json_encode($stats) . "\n";
          
          return $stats;
          
      } catch (Exception $error) {
          echo "❌ Failed to sync plans: " . $error->getMessage() . "\n";
          throw $error;
      }
  }

  // Run sync on startup
  syncMobilePlans($db);

  // For scheduled execution, use cron:
  // 0 0 * * * /usr/bin/php /path/to/sync_plans.php
  ```
</CodeGroup>

## Serving Plans to Users

When users request plans, serve from your database with your pricing:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function getUserPlans(filters = {}) {
    const { operator, type, enabled = true } = filters;
    
    const query = { isEnabled: enabled, isVisible: true };
    
    if (operator) query.operator = operator;
    if (type) query.type = type;
    
    const plans = await db.mobilePlans.findMany({
      where: query,
      orderBy: [
        { operator: 'asc' },
        { fixedAmount: 'asc' },
        { name: 'asc' }
      ]
    });
    
    // Transform for user display (remove wholesale cost!)
    return plans.map(plan => ({
      code: plan.code,
      name: plan.name,
      operator: plan.operator,
      type: plan.type,
      minAmount: plan.minAmount,
      maxAmount: plan.maxAmount,
      amount: plan.fixedAmount,
      // Don't expose wholesale cost!
      // Only expose what user needs
    }));
  }

  // API endpoint
  app.get('/api/mobile/plans', async (req, res) => {
    try {
      const { operator } = req.query;
      const plans = await getUserPlans({ operator });
      res.json({ success: true, data: { plans } });
    } catch (error) {
      res.status(500).json({ 
        success: false, 
        error: error.message 
      });
    }
  });
  ```

  ```python Python theme={null}
  def get_user_plans(operator=None, plan_type=None, enabled=True):
      """Get plans for user display"""
      query = {
          'is_enabled': enabled,
          'is_visible': True
      }
      
      if operator:
          query['operator'] = operator
      if plan_type:
          query['type'] = plan_type
      
      plans = db.mobile_plans.find(query).sort([
          ('operator', 1),
          ('fixed_amount', 1),
          ('name', 1)
      ])
      
      # Transform for user display (remove wholesale cost!)
      return [{
          'code': plan['code'],
          'name': plan['name'],
          'operator': plan['operator'],
          'type': plan['type'],
          'minAmount': plan.get('min_amount'),
          'maxAmount': plan.get('max_amount'),
          'amount': plan.get('fixed_amount')
          # Don't expose wholesale cost!
      } for plan in plans]

  # Flask endpoint
  @app.route('/api/mobile/plans', methods=['GET'])
  def api_mobile_plans():
      try:
          operator = request.args.get('operator')
          plans = get_user_plans(operator=operator)
          return jsonify({'success': True, 'data': {'plans': plans}})
      except Exception as error:
          return jsonify({'success': False, 'error': str(error)}), 500
  ```

  ```php PHP theme={null}
  <?php

  function getUserPlans($db, $operator = null, $type = null, $enabled = true) {
      $conditions = ['is_enabled = ?', 'is_visible = ?'];
      $params = [$enabled, true];
      
      if ($operator) {
          $conditions[] = 'operator = ?';
          $params[] = $operator;
      }
      
      if ($type) {
          $conditions[] = 'type = ?';
          $params[] = $type;
      }
      
      $where = implode(' AND ', $conditions);
      $query = "SELECT code, name, operator, type, min_amount, max_amount, fixed_amount 
                FROM mobile_plans 
                WHERE $where 
                ORDER BY operator, fixed_amount, name";
      
      $plans = $db->query($query, $params)->fetchAll(PDO::FETCH_ASSOC);
      
      // Transform for user display
      return array_map(function($plan) {
          return [
              'code' => $plan['code'],
              'name' => $plan['name'],
              'operator' => $plan['operator'],
              'type' => $plan['type'],
              'minAmount' => $plan['min_amount'],
              'maxAmount' => $plan['max_amount'],
              'amount' => $plan['fixed_amount']
              // Don't expose wholesale cost!
          ];
      }, $plans);
  }

  // API endpoint
  if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_SERVER['REQUEST_URI'] === '/api/mobile/plans') {
      try {
          $operator = $_GET['operator'] ?? null;
          $plans = getUserPlans($db, $operator);
          
          header('Content-Type: application/json');
          echo json_encode(['success' => true, 'data' => ['plans' => $plans]]);
      } catch (Exception $error) {
          http_response_code(500);
          echo json_encode(['success' => false, 'error' => $error->getMessage()]);
      }
  }
  ```
</CodeGroup>

## Filtering Plans

### By Operator

<CodeGroup>
  ```javascript Node.js theme={null}
  const mobilisPlans = await getUserPlans({ operator: 'Mobilis' });
  const djezzyPlans = await getUserPlans({ operator: 'Djezzy' });
  const ooredooPlans = await getUserPlans({ operator: 'Ooredoo' });
  ```

  ```python Python theme={null}
  mobilis_plans = get_user_plans(operator='Mobilis')
  djezzy_plans = get_user_plans(operator='Djezzy')
  ooredoo_plans = get_user_plans(operator='Ooredoo')
  ```

  ```php PHP theme={null}
  $mobilisPlans = getUserPlans($db, 'Mobilis');
  $djezzyPlans = getUserPlans($db, 'Djezzy');
  $ooredooPlans = getUserPlans($db, 'Ooredoo');
  ```
</CodeGroup>

### By Phone Number

<CodeGroup>
  ```javascript Node.js theme={null}
  function getOperatorFromPhone(phone) {
    const prefixMap = {
      '065': ['Mobilis'],
      '066': ['Mobilis', 'Ooredoo'],
      '067': ['Mobilis'],
      '077': ['Djezzy', 'Mobilis'],
      '078': ['Djezzy'],
      '055': ['Ooredoo', 'Djezzy', 'Mobilis'],
      '056': ['Ooredoo'],
      '068': ['Pixx']
    };
    
    const prefix = phone.substring(0, 3);
    return prefixMap[prefix] || [];
  }

  async function getPlansForPhone(phone) {
    const operators = getOperatorFromPhone(phone);
    
    if (operators.length === 0) {
      throw new Error('Invalid phone number prefix');
    }
    
    const plans = await db.mobilePlans.findMany({
      where: {
        operator: { in: operators },
        isEnabled: true,
        isVisible: true
      }
    });
    
    return plans;
  }
  ```

  ```python Python theme={null}
  def get_operator_from_phone(phone):
      prefix_map = {
          '065': ['Mobilis'],
          '066': ['Mobilis', 'Ooredoo'],
          '067': ['Mobilis'],
          '077': ['Djezzy', 'Mobilis'],
          '078': ['Djezzy'],
          '055': ['Ooredoo', 'Djezzy', 'Mobilis'],
          '056': ['Ooredoo'],
          '068': ['Pixx']
      }
      
      prefix = phone[:3]
      return prefix_map.get(prefix, [])

  def get_plans_for_phone(phone):
      operators = get_operator_from_phone(phone)
      
      if not operators:
          raise ValueError('Invalid phone number prefix')
      
      plans = db.mobile_plans.find({
          'operator': {'$in': operators},
          'is_enabled': True,
          'is_visible': True
      })
      
      return list(plans)
  ```

  ```php PHP theme={null}
  <?php

  function getOperatorFromPhone($phone) {
      $prefixMap = [
          '065' => ['Mobilis'],
          '066' => ['Mobilis', 'Ooredoo'],
          '067' => ['Mobilis'],
          '077' => ['Djezzy', 'Mobilis'],
          '078' => ['Djezzy'],
          '055' => ['Ooredoo', 'Djezzy', 'Mobilis'],
          '056' => ['Ooredoo'],
          '068' => ['Pixx']
      ];
      
      $prefix = substr($phone, 0, 3);
      return $prefixMap[$prefix] ?? [];
  }

  function getPlansForPhone($db, $phone) {
      $operators = getOperatorFromPhone($phone);
      
      if (empty($operators)) {
          throw new Exception('Invalid phone number prefix');
      }
      
      $placeholders = implode(',', array_fill(0, count($operators), '?'));
      $query = "SELECT * FROM mobile_plans 
                WHERE operator IN ($placeholders) 
                AND is_enabled = 1 
                AND is_visible = 1";
      
      return $db->query($query, $operators)->fetchAll(PDO::FETCH_ASSOC);
  }
  ```
</CodeGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Cache Locally" icon="database">
    Always cache plans in your database. Plans rarely change, and caching dramatically improves performance.
  </Accordion>

  <Accordion title="Hide Wholesale Costs" icon="eye-slash">
    Never expose the `cost` field to end users. Only show your retail pricing.
  </Accordion>

  <Accordion title="Sync Regularly" icon="arrows-rotate">
    Set up a daily cron job to sync plans. This ensures you have the latest offerings and availability.
  </Accordion>

  <Accordion title="Check isEnabled" icon="toggle-on">
    Always verify `isEnabled` before displaying plans. Disabled plans may be temporarily unavailable due to operator issues.
  </Accordion>

  <Accordion title="Add Profit Margin" icon="chart-line">
    Calculate your selling price by adding a reasonable profit margin (typically 3-10%) to the wholesale cost.
  </Accordion>

  <Accordion title="Index Your Database" icon="magnifying-glass">
    Create indexes on frequently queried fields (operator, code, isEnabled) for fast lookups.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Step 2: Validation" icon="shield-check" href="/en/mobile-topup-guides/2-validation">
    Learn how to validate phone numbers and user inputs
  </Card>

  <Card title="Plans API Reference" icon="book" href="/en/api-reference/mobile/list-plans">
    Complete API documentation for GET /v3/mobile/plans
  </Card>

  <Card title="Account Balance API" icon="wallet" href="/en/api-reference/account/get-balance">
    Learn how to check your account balance
  </Card>

  <Card title="Pricing Guide" icon="dollar-sign" href="/en/pricing">
    Understand API pricing and cost structure
  </Card>

  <Card title="Response Format" icon="file-code" href="/en/api-reference/response-format">
    Learn about API response structures
  </Card>

  <Card title="Models Reference" icon="database" href="/en/api-reference/models">
    View all data models and schemas
  </Card>
</CardGroup>
