> ## 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 2: Input Validation

> Validate phone numbers, amounts, and plan selection

## Overview

Before sending a top-up request, validate all inputs to prevent errors and ensure a smooth user experience.

<Note>
  Proper validation reduces API errors and improves user experience by catching mistakes early.
</Note>

## Phone Number Validation

Phone numbers must match this pattern: `^0[567][0-9]{8}$`

**Requirements:**

* Must start with `0`
* Second digit must be `5`, `6`, or `7`
* Exactly 10 digits total
* Only numeric characters

<Tabs>
  <Tab title="Valid Examples">
    - ✅ `"0778037340"`
    - ✅ `"0665983439"`
    - ✅ `"0556121212"`
  </Tab>

  <Tab title="Invalid Examples">
    * ❌ `"778037340"` - Missing leading zero
    * ❌ `"+213778037340"` - International format
    * ❌ `"0778 037 340"` - Contains spaces
  </Tab>
</Tabs>

<CodeGroup>
  ```javascript Node.js theme={null}
  function validatePhoneNumber(phone) {
    if (typeof phone !== 'string') {
      return { valid: false, error: 'Phone number must be a string' };
    }
    
    phone = phone.trim();
    
    if (!/^0[567][0-9]{8}$/.test(phone)) {
      return { valid: false, error: 'Invalid phone format. Must be 10 digits starting with 05, 06, or 07' };
    }
    
    return { valid: true, phone };
  }
  ```

  ```python Python theme={null}
  import re

  def validate_phone_number(phone):
      if not isinstance(phone, str):
          return {'valid': False, 'error': 'Phone number must be a string'}
      
      phone = phone.strip()
      
      if not re.match(r'^0[567][0-9]{8}$', phone):
          return {'valid': False, 'error': 'Invalid phone format. Must be 10 digits starting with 05, 06, or 07'}
      
      return {'valid': True, 'phone': phone}
  ```

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

  function validatePhoneNumber($phone) {
      if (!is_string($phone)) {
          return ['valid' => false, 'error' => 'Phone number must be a string'];
      }
      
      $phone = trim($phone);
      
      if (!preg_match('/^0[567][0-9]{8}$/', $phone)) {
          return ['valid' => false, 'error' => 'Invalid phone format. Must be 10 digits starting with 05, 06, or 07'];
      }
      
      return ['valid' => true, 'phone' => $phone];
  }
  ```
</CodeGroup>

## Plan Validation

Validate that the selected plan exists and is available:

<CodeGroup>
  ```javascript Node.js theme={null}
  function validatePlan(planCode, plans) {
    const plan = plans.find(p => p.code === planCode);
    
    if (!plan) {
      return { valid: false, error: `Plan ${planCode} not found` };
    }
    
    if (!plan.isEnabled) {
      return { valid: false, error: `Plan ${plan.name} is currently unavailable` };
    }
    
    return { valid: true, plan };
  }
  ```

  ```python Python theme={null}
  def validate_plan(plan_code, plans):
      plan = next((p for p in plans if p['code'] == plan_code), None)
      
      if not plan:
          return {'valid': False, 'error': f'Plan {plan_code} not found'}
      
      if not plan['is_enabled']:
          return {'valid': False, 'error': f"Plan {plan['name']} is currently unavailable"}
      
      return {'valid': True, 'plan': plan}
  ```

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

  function validatePlan($planCode, $plans) {
      $plan = null;
      foreach ($plans as $p) {
          if ($p['code'] === $planCode) {
              $plan = $p;
              break;
          }
      }
      
      if (!$plan) {
          return ['valid' => false, 'error' => "Plan $planCode not found"];
      }
      
      if (!$plan['is_enabled']) {
          return ['valid' => false, 'error' => "Plan {$plan['name']} is currently unavailable"];
      }
      
      return ['valid' => true, 'plan' => $plan];
  }
  ```
</CodeGroup>

## Amount Validation

Validate amounts based on plan type (dynamic vs fixed):

<CodeGroup>
  ```javascript Node.js theme={null}
  function validateAmount(amount, plan) {
    // Fixed plans use their predefined amount
    if (plan.type === 'fixed') {
      return { valid: true, amount: plan.fixedAmount };
    }
    
    // Dynamic plans require amount within range
    if (!amount) {
      return { valid: false, error: 'Amount is required for dynamic plans' };
    }
    
    const numAmount = Number(amount);
    
    if (isNaN(numAmount) || !Number.isInteger(numAmount)) {
      return { valid: false, error: 'Amount must be an integer' };
    }
    
    if (numAmount < plan.minAmount) {
      return { valid: false, error: `Amount must be at least ${plan.minAmount} DZD` };
    }
    
    if (numAmount > plan.maxAmount) {
      return { valid: false, error: `Amount cannot exceed ${plan.maxAmount} DZD` };
    }
    
    return { valid: true, amount: numAmount };
  }
  ```

  ```python Python theme={null}
  def validate_amount(amount, plan):
      # Fixed plans use their predefined amount
      if plan['type'] == 'fixed':
          return {'valid': True, 'amount': plan['fixed_amount']}
      
      # Dynamic plans require amount within range
      if amount is None:
          return {'valid': False, 'error': 'Amount is required for dynamic plans'}
      
      try:
          num_amount = int(amount)
      except (ValueError, TypeError):
          return {'valid': False, 'error': 'Amount must be an integer'}
      
      if num_amount < plan['min_amount']:
          return {'valid': False, 'error': f"Amount must be at least {plan['min_amount']} DZD"}
      
      if num_amount > plan['max_amount']:
          return {'valid': False, 'error': f"Amount cannot exceed {plan['max_amount']} DZD"}
      
      return {'valid': True, 'amount': num_amount}
  ```

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

  function validateAmount($amount, $plan) {
      // Fixed plans use their predefined amount
      if ($plan['type'] === 'fixed') {
          return ['valid' => true, 'amount' => $plan['fixed_amount']];
      }
      
      // Dynamic plans require amount within range
      if ($amount === null || $amount === '') {
          return ['valid' => false, 'error' => 'Amount is required for dynamic plans'];
      }
      
      if (!is_numeric($amount)) {
          return ['valid' => false, 'error' => 'Amount must be an integer'];
      }
      
      $numAmount = (int)$amount;
      
      if ($numAmount < $plan['min_amount']) {
          return ['valid' => false, 'error' => "Amount must be at least {$plan['min_amount']} DZD"];
      }
      
      if ($numAmount > $plan['max_amount']) {
          return ['valid' => false, 'error' => "Amount cannot exceed {$plan['max_amount']} DZD"];
      }
      
      return ['valid' => true, 'amount' => $numAmount];
  }
  ```
</CodeGroup>

## Complete Validation

Combine all validations:

<CodeGroup>
  ```javascript Node.js theme={null}
  function validateTopUpRequest(data, plans) {
    const errors = [];
    
    // Validate phone
    const phoneValidation = validatePhoneNumber(data.phone);
    if (!phoneValidation.valid) {
      errors.push({ field: 'phone', message: phoneValidation.error });
    }
    
    // Validate plan
    const planValidation = validatePlan(data.planCode, plans);
    if (!planValidation.valid) {
      errors.push({ field: 'planCode', message: planValidation.error });
      return { valid: false, errors };
    }
    
    // Validate amount
    const amountValidation = validateAmount(data.amount, planValidation.plan);
    if (!amountValidation.valid) {
      errors.push({ field: 'amount', message: amountValidation.error });
    }
    
    if (errors.length > 0) {
      return { valid: false, errors };
    }
    
    return {
      valid: true,
      data: {
        phone: phoneValidation.phone,
        planCode: planValidation.plan.code,
        amount: amountValidation.amount
      }
    };
  }

  // Usage
  const result = validateTopUpRequest({
    phone: '0778037340',
    planCode: 'PREPAID_DJEZZY',
    amount: 500
  }, plans);

  if (!result.valid) {
    console.error('Validation errors:', result.errors);
  } else {
    console.log('Valid request:', result.data);
  }
  ```

  ```python Python theme={null}
  def validate_topup_request(data, plans):
      errors = []
      
      # Validate phone
      phone_validation = validate_phone_number(data.get('phone'))
      if not phone_validation['valid']:
          errors.append({'field': 'phone', 'message': phone_validation['error']})
      
      # Validate plan
      plan_validation = validate_plan(data.get('plan_code'), plans)
      if not plan_validation['valid']:
          errors.append({'field': 'plan_code', 'message': plan_validation['error']})
          return {'valid': False, 'errors': errors}
      
      # Validate amount
      amount_validation = validate_amount(data.get('amount'), plan_validation['plan'])
      if not amount_validation['valid']:
          errors.append({'field': 'amount', 'message': amount_validation['error']})
      
      if errors:
          return {'valid': False, 'errors': errors}
      
      return {
          'valid': True,
          'data': {
              'phone': phone_validation['phone'],
              'plan_code': plan_validation['plan']['code'],
              'amount': amount_validation['amount']
          }
      }

  # Usage
  result = validate_topup_request({
      'phone': '0778037340',
      'plan_code': 'PREPAID_DJEZZY',
      'amount': 500
  }, plans)

  if not result['valid']:
      print('Validation errors:', result['errors'])
  else:
      print('Valid request:', result['data'])
  ```

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

  function validateTopUpRequest($data, $plans) {
      $errors = [];
      
      // Validate phone
      $phoneValidation = validatePhoneNumber($data['phone'] ?? '');
      if (!$phoneValidation['valid']) {
          $errors[] = ['field' => 'phone', 'message' => $phoneValidation['error']];
      }
      
      // Validate plan
      $planValidation = validatePlan($data['plan_code'] ?? '', $plans);
      if (!$planValidation['valid']) {
          $errors[] = ['field' => 'plan_code', 'message' => $planValidation['error']];
          return ['valid' => false, 'errors' => $errors];
      }
      
      // Validate amount
      $amountValidation = validateAmount($data['amount'] ?? null, $planValidation['plan']);
      if (!$amountValidation['valid']) {
          $errors[] = ['field' => 'amount', 'message' => $amountValidation['error']];
      }
      
      if (!empty($errors)) {
          return ['valid' => false, 'errors' => $errors];
      }
      
      return [
          'valid' => true,
          'data' => [
              'phone' => $phoneValidation['phone'],
              'plan_code' => $planValidation['plan']['code'],
              'amount' => $amountValidation['amount']
          ]
      ];
  }

  // Usage
  $result = validateTopUpRequest([
      'phone' => '0778037340',
      'plan_code' => 'PREPAID_DJEZZY',
      'amount' => 500
  ], $plans);

  if (!$result['valid']) {
      print_r($result['errors']);
  } else {
      print_r($result['data']);
  }
  ```
</CodeGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Validate Client-Side" icon="bolt">
    Check inputs in the UI before making API calls to improve UX.
  </Accordion>

  <Accordion title="Always Validate Server-Side" icon="server">
    Never trust client input. Always validate on the server.
  </Accordion>

  <Accordion title="Provide Clear Errors" icon="message">
    Show specific error messages that help users fix issues.
  </Accordion>

  <Accordion title="Sanitize Inputs" icon="broom">
    Remove whitespace and normalize inputs before validation.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Step 3: Sending Top-Ups" icon="paper-plane" href="/en/mobile-topup-guides/3-sending-topups">
    Learn how to send top-up requests
  </Card>

  <Card title="API Reference" icon="book" href="/en/api-reference/mobile/send-topup">
    Complete API documentation
  </Card>
</CardGroup>
