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

# Validation

> Validate customer details before making bill payments

## Overview

Always validate customer details before making a payment. Validation confirms the customer exists, shows their details, and prevents payment errors.

**What you'll learn:**

* Why validation is important
* Validate customer details
* Understand validation responses
* Handle validation errors
* Best practices

***

## Why Validate?

<CardGroup cols={2}>
  <Card title="Confirm Customer" icon="user-check">
    Verify customer exists and is active
  </Card>

  <Card title="See Details" icon="circle-info">
    View customer name and account info
  </Card>

  <Card title="Prevent Errors" icon="shield-check">
    Avoid paying wrong account
  </Card>

  <Card title="Check Balance" icon="wallet">
    See current balance (for postpaid)
  </Card>
</CardGroup>

***

## Validate Customer

Verify customer details before payment.

<CodeGroup>
  ```javascript Node.js theme={null}
  import MoneiSDK from 'monei-sdk';

  const monei = new MoneiSDK({
    apiKey: process.env.MONEI_API_KEY,
  });

  // Validate phone number for airtime
  const validation = await monei.billsValidation.validate({
    biller: 'mtn',
    customerId: '08012345678',
    type: 'PREPAID'
  });

  console.log('Validation Result:');
  console.log('Customer Name:', validation.customerName);
  console.log('Customer ID:', validation.customerId);
  console.log('Biller:', validation.billerName);

  // Validate meter number for electricity
  const meterValidation = await monei.billsValidation.validate({
    biller: 'ikedc-prepaid',
    customerId: '12345678901',
    type: 'PREPAID'
  });

  console.log('\nMeter Validation:');
  console.log('Customer:', meterValidation.customerName);
  console.log('Address:', meterValidation.address);
  console.log('Meter Number:', meterValidation.customerId);

  // Validate smartcard for cable TV
  const cardValidation = await monei.billsValidation.validate({
    billerId: 'dstv-ng',
    customerId: '1234567890',
    type: 'PREPAID'
  });

  console.log('\nSmartcard Validation:');
  console.log('Customer:', cardValidation.customerName);
  console.log('Current Package:', cardValidation.currentPackage);
  console.log('Due Date:', cardValidation.dueDate);
  ```

  ```python Python theme={null}
  from monei import MoneiClient

  monei = MoneiClient(
      api_key=os.getenv('MONEI_API_KEY')
  )

  # Validate phone number
  validation = monei.billsValidation.validate(
      biller_id='mtn-ng',
      customer_id='08012345678',
      type='PREPAID'
  )

  print('Validation Result:')
  print(f'Customer: {validation.customer_name}')
  print(f'ID: {validation.customer_id}')
  print(f'Biller: {validation.biller_name}')

  # Validate meter number
  meter_validation = monei.bills_validation.validate(
      biller_id='ikedc-prepaid',
      customer_id='12345678901',
      type='PREPAID'
  )

  print(f'\nMeter Validation:')
  print(f'Customer: {meter_validation.customer_name}')
  print(f'Address: {meter_validation.address}')

  # Validate smartcard
  card_validation = monei.bills_validation.validate(
      biller_id='dstv-ng',
      customer_id='1234567890',
      type='PREPAID'
  )

  print(f'\nSmartcard:')
  print(f'Customer: {card_validation.customer_name}')
  print(f'Package: {card_validation.current_package}')
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.monei.cc/api/v1/bills/validate \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "billerId": "mtn-ng",
      "customerId": "08012345678",
      "type": "PREPAID"
    }'
  ```
</CodeGroup>

**Request Parameters:**

| Parameter    | Type   | Required | Description                           |
| ------------ | ------ | -------- | ------------------------------------- |
| `billerId`   | string | Yes      | Biller identifier                     |
| `customerId` | string | Yes      | Customer ID (phone, meter, smartcard) |
| `type`       | string | Yes      | PREPAID or POSTPAID                   |

**Response:**

```json theme={null}
{
  "statusCode": 200,
  "message": "Customer validated successfully",
  "data": {
    "customerName": "JOHN DOE",
    "customerId": "08012345678",
    "billerName": "MTN Nigeria",
    "billerId": "mtn-ng",
    "type": "PREPAID",
    "validated": true
  }
}
```

***

## Validation by Category

Different categories return different information:

<Tabs>
  <Tab title="Airtime & Data">
    **Phone Number Validation**

    ```javascript theme={null}
    const validation = await monei.billsValidation.validate({
      billerId: 'mtn-ng',
      customerId: '08012345678',
      type: 'PREPAID'
    });
    ```

    **Response Fields:**

    * `customerName` - Account holder name
    * `customerId` - Phone number
    * `billerName` - Network name
    * `validated` - true/false

    **Customer ID Format:** 11 digits (0801234567)
  </Tab>

  <Tab title="Cable TV">
    **Smartcard Validation**

    ```javascript theme={null}
    const validation = await monei.billsValidation.validate({
      billerId: 'dstv-ng',
      customerId: '1234567890',
      type: 'PREPAID'
    });
    ```

    **Response Fields:**

    * `customerName` - Account holder
    * `customerId` - Smartcard number
    * `currentPackage` - Active package
    * `dueDate` - Renewal date
    * `balance` - Outstanding balance

    **Customer ID Format:** 10 digits
  </Tab>

  <Tab title="Electricity">
    **Meter Number Validation**

    ```javascript theme={null}
    const validation = await monei.billsValidation.validate({
      billerId: 'ikedc-prepaid',
      customerId: '12345678901',
      type: 'PREPAID'
    });
    ```

    **Response Fields:**

    * `customerName` - Meter owner
    * `customerId` - Meter number
    * `address` - Service address
    * `accountNumber` - Account number
    * `meterType` - Meter type
    * `outstandingBalance` - Balance (postpaid)

    **Customer ID Format:** 11-13 digits
  </Tab>
</Tabs>

***

## Complete Validation Flow

<CodeGroup>
  ```javascript Node.js theme={null}
  async function validateAndPay(billerId, customerId, amount) {
    try {
      // 1. Get biller details
      const billers = await monei.billsDiscovery.getBillers();
      const biller = billers.find(b => b.billerId === billerId);
      
      if (!biller) {
        throw new Error('Biller not found');
      }
      
      console.log('Biller:', biller.name);
      console.log('Fee:', biller.fee);
      console.log('Amount Range:', biller.minAmount, '-', biller.maxAmount);
      
      // 2. Validate customer
      console.log('\nValidating customer...');
      const validation = await monei.billsValidation.validate({
        billerId: biller.billerId,
        customerId: customerId,
        type: biller.type
      });
      
      if (!validation.validated) {
        throw new Error('Customer validation failed');
      }
      
      console.log('✓ Customer validated');
      console.log('Name:', validation.customerName);
      
      // 3. Confirm details
      console.log('\nPayment Summary:');
      console.log('Biller:', validation.billerName);
      console.log('Customer:', validation.customerName);
      console.log('Amount:', amount);
      console.log('Fee:', biller.fee);
      console.log('Total:', amount + biller.fee);
      
      // 4. Make payment (next step)
      console.log('\n✓ Ready to proceed with payment');
      
      return validation;
      
    } catch (error) {
      console.error('Error:', error.message);
      throw error;
    }
  }

  // Usage
  await validateAndPay('mtn-ng', '08012345678', 1000);
  ```

  ```python Python theme={null}
  async def validate_and_pay(biller_id, customer_id, amount):
      try:
          # 1. Get biller
          billers = monei.bills_discovery.get_billers()
          biller = next((b for b in billers if b.biller_id == biller_id), None)
          
          if not biller:
              raise Exception('Biller not found')
          
          print(f'Biller: {biller.name}')
          print(f'Fee: ₦{biller.fee}')
          
          # 2. Validate
          print('\nValidating...')
          validation = monei.bills_validation.validate(
              biller_id=biller.biller_id,
              customer_id=customer_id,
              type=biller.type
          )
          
          if not validation.validated:
              raise Exception('Validation failed')
          
          print('✓ Validated')
          print(f'Name: {validation.customer_name}')
          
          # 3. Summary
          print('\nPayment Summary:')
          print(f'Biller: {validation.biller_name}')
          print(f'Customer: {validation.customer_name}')
          print(f'Amount: ₦{amount}')
          print(f'Fee: ₦{biller.fee}')
          print(f'Total: ₦{amount + biller.fee}')
          
          print('\n✓ Ready to pay')
          
          return validation
          
      except Exception as error:
          print(f'Error: {error}')
          raise

  # Usage
  await validate_and_pay('mtn-ng', '08012345678', 1000)
  ```
</CodeGroup>

***

## Error Handling

<AccordionGroup>
  <Accordion icon="circle-xmark" title="Customer Not Found">
    **Error:** Customer ID does not exist

    **Common causes:**

    * Wrong phone/meter/card number
    * Incorrect biller selected
    * Inactive account

    **Solution:**

    * Verify customer ID with user
    * Check biller is correct
    * Try different format (with/without prefix)
  </Accordion>

  <Accordion icon="ban" title="Invalid Customer ID Format">
    **Error:** Customer ID format is invalid

    **Formats by category:**

    * Airtime: 11 digits (08012345678)
    * Electricity: 11-13 digits
    * Cable TV: 10 digits
    * Internet: Varies by provider

    **Solution:**

    * Validate format before API call
    * Remove spaces and special characters
    * Check digit count
  </Accordion>

  <Accordion icon="exclamation-triangle" title="Service Unavailable">
    **Error:** Biller service temporarily unavailable

    **Causes:**

    * Biller system down
    * Maintenance window
    * Network issues

    **Solution:**

    * Retry after a few minutes
    * Try during off-peak hours
    * Check biller status
    * Use alternative biller if available
  </Accordion>

  <Accordion icon="clock" title="Validation Timeout">
    **Error:** Validation request timed out

    **Solution:**

    * Retry the request
    * Check internet connection
    * Try during off-peak hours
    * Contact support if persists
  </Accordion>
</AccordionGroup>

***

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Validate" icon="check-double">
    Never skip validation - always verify before payment
  </Card>

  <Card title="Show Customer Name" icon="user">
    Display validated name to user for confirmation
  </Card>

  <Card title="Cache Results" icon="database">
    Cache validation for few minutes to reduce API calls
  </Card>

  <Card title="Validate Format" icon="ruler">
    Validate customer ID format client-side first
  </Card>

  <Card title="Handle Errors" icon="bug">
    Provide clear error messages to users
  </Card>

  <Card title="Show Summary" icon="list">
    Display payment summary before confirmation
  </Card>
</CardGroup>

***

## Input Validation

Validate customer ID format before API call:

<CodeGroup>
  ```javascript Node.js theme={null}
  // Validation helpers
  const validators = {
    airtime: (phone) => {
      // Nigerian phone: 11 digits starting with 0
      return /^0[789][01]\d{8}$/.test(phone);
    },
    
    meterNumber: (meter) => {
      // Meter: 11-13 digits
      return /^\d{11,13}$/.test(meter);
    },
    
    smartcard: (card) => {
      // Smartcard: 10 digits
      return /^\d{10}$/.test(card);
    }
  };

  // Validate before API call
  function validateInput(category, customerId) {
    const cleaned = customerId.replace(/\s+/g, '');
    
    switch (category) {
      case 'airtime':
      case 'data':
        if (!validators.airtime(cleaned)) {
          throw new Error('Invalid phone number format. Must be 11 digits (e.g., 08012345678)');
        }
        break;
        
      case 'electricity':
        if (!validators.meterNumber(cleaned)) {
          throw new Error('Invalid meter number. Must be 11-13 digits');
        }
        break;
        
      case 'cable_tv':
        if (!validators.smartcard(cleaned)) {
          throw new Error('Invalid smartcard number. Must be 10 digits');
        }
        break;
    }
    
    return cleaned;
  }

  // Usage
  try {
    const phone = validateInput('airtime', '0801 234 5678');
    console.log('Valid phone:', phone); // 08012345678
    
    const validation = await monei.bills.validate({
      billerId: 'mtn-ng',
      customerId: phone,
      type: 'PREPAID'
    });
  } catch (error) {
    console.error('Validation error:', error.message);
  }
  ```

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

  # Validators
  class CustomerIdValidator:
      @staticmethod
      def airtime(phone):
          # 11 digits starting with 0
          return bool(re.match(r'^0[789][01]\d{8}$', phone))
      
      @staticmethod
      def meter_number(meter):
          # 11-13 digits
          return bool(re.match(r'^\d{11,13}$', meter))
      
      @staticmethod
      def smartcard(card):
          # 10 digits
          return bool(re.match(r'^\d{10}$', card))

  # Validate input
  def validate_input(category, customer_id):
      # Remove spaces
      cleaned = customer_id.replace(' ', '')
      
      if category in ['airtime', 'data']:
          if not CustomerIdValidator.airtime(cleaned):
              raise ValueError('Invalid phone number')
      
      elif category == 'electricity':
          if not CustomerIdValidator.meter_number(cleaned):
              raise ValueError('Invalid meter number')
      
      elif category == 'cable_tv':
          if not CustomerIdValidator.smartcard(cleaned):
              raise ValueError('Invalid smartcard number')
      
      return cleaned

  # Usage
  try:
      phone = validate_input('airtime', '0801 234 5678')
      print(f'Valid phone: {phone}')
      
      validation = monei.bills.validate(
          biller_id='mtn-ng',
          customer_id=phone,
          type='PREPAID'
      )
  except ValueError as error:
      print(f'Error: {error}')
  ```
</CodeGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Overview" icon="circle-info" href="/bill-payments/overview">
    Bill payments introduction
  </Card>

  <Card title="Discovery" icon="magnifying-glass" href="/bill-payments/discovery">
    Browse available billers
  </Card>

  <Card title="Payments" icon="credit-card" href="/bill-payments/payments">
    Make bill payments
  </Card>

  <Card title="History" icon="clock-rotate-left" href="/bill-payments/history">
    View payment history
  </Card>
</CardGroup>
