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

# Sending Internet Top-Ups

> Submit ADSL and 4G internet recharge orders with error handling

## Overview

Send internet top-up orders after validating phone numbers and checking product availability. Orders are processed with the operator and typically complete within 3-45 seconds.

<Warning>
  **Always validate numbers first** using `/check-number` to minimize failures and refunds.
</Warning>

## API Reference

<Card title="POST /v3/internet/send" icon="paper-plane" href="/en/api-reference/internet/send-topup">
  Complete endpoint documentation
</Card>

## Basic Order Submission

<CodeGroup>
  ```javascript Node.js theme={null}
  async function sendInternetTopup(orderData) {
    const response = await fetch(
      "https://api.oneclickdz.com/v3/internet/send",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-Access-Token": process.env.API_KEY,
        },
        body: JSON.stringify({
          type: orderData.type,      // 'ADSL' or '4G'
          number: orderData.number,   // Phone number
          value: orderData.value,     // Card value
          ref: orderData.ref,         // Your unique reference
        }),
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.error?.message || `HTTP ${response.status}`);
    }

    const result = await response.json();
    return result.data;
  }

  // Usage
  const order = await sendInternetTopup({
    type: 'ADSL',
    number: '036362608',
    value: 1000,
    ref: `order-${Date.now()}`
  });

  console.log('Top-up sent:', order.topupId);
  ```

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

  def send_internet_topup(order_data):
      response = requests.post(
          'https://api.oneclickdz.com/v3/internet/send',
          headers={
              'Content-Type': 'application/json',
              'X-Access-Token': os.getenv('API_KEY')
          },
          json={
              'type': order_data['type'],
              'number': order_data['number'],
              'value': order_data['value'],
              'ref': order_data['ref']
          }
      )
      
      if not response.ok:
          error = response.json()
          raise Exception(error.get('error', {}).get('message', f'HTTP {response.status_code}'))
      
      return response.json()['data']

  # Usage
  order = send_internet_topup({
      'type': 'ADSL',
      'number': '036362608',
      'value': 1000,
      'ref': f'order-{int(time.time() * 1000)}'
  })

  print(f'Top-up sent: {order["topupId"]}')
  ```

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

  function sendInternetTopup($orderData) {
      $data = [
          'type' => $orderData['type'],
          'number' => $orderData['number'],
          'value' => $orderData['value'],
          'ref' => $orderData['ref']
      ];
      
      $ch = curl_init('https://api.oneclickdz.com/v3/internet/send');
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json',
          'X-Access-Token: ' . getenv('API_KEY')
      ]);
      curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      
      $response = curl_exec($ch);
      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);
      
      if ($httpCode >= 400) {
          $error = json_decode($response, true);
          throw new Exception($error['error']['message'] ?? "HTTP {$httpCode}");
      }
      
      $result = json_decode($response, true);
      return $result['data'];
  }

  // Usage
  $order = sendInternetTopup([
      'type' => 'ADSL',
      'number' => '036362608',
      'value' => 1000,
      'ref' => 'order-' . (int)(microtime(true) * 1000)
  ]);

  echo "Top-up sent: {$order['topupId']}\n";
  ?>
  ```

  ```bash cURL theme={null}
  curl https://api.oneclickdz.com/v3/internet/send \
    -X POST \
    -H "Content-Type: application/json" \
    -H "X-Access-Token: YOUR_API_KEY" \
    -d '{
      "type": "ADSL",
      "number": "036362608",
      "value": 1000,
      "ref": "order-123456"
    }'
  ```
</CodeGroup>

## Success Response

```json theme={null}
{
  "success": true,
  "data": {
    "topupId": "6901616fe9e88196b4eb64b2",
    "topupRef": "order-123456"
  },
  "meta": {
    "timestamp": "2025-11-01T12:00:00.000Z"
  }
}
```

## Pre-Order Validation

Always validate before sending orders:

<CodeGroup>
  ```javascript Node.js theme={null}
  async function validateAndSend(orderData) {
    // Step 1: Validate phone number
    try {
      await validateInternetNumber(orderData.type, orderData.number);
    } catch (error) {
      throw new Error(`Invalid phone number: ${error.message}`);
    }

    // Step 2: Check product availability
    const products = await loadInternetProducts(orderData.type);
    const product = products.find(
      p => p.value === orderData.value && p.available
    );
    
    if (!product) {
      throw new Error(`Product ${orderData.value} DA not available for ${orderData.type}`);
    }

    // Step 3: Check balance
    const balance = await getBalance();
    if (balance < product.cost) {
      throw new Error(
        `Insufficient balance. Required: ${product.cost} DA, Available: ${balance} DA`
      );
    }

    // Step 4: Send order
    console.log(`Sending ${orderData.type} ${orderData.value} DA to ${orderData.number}`);
    const result = await sendInternetTopup(orderData);
    
    return {
      topupId: result.topupId,
      topupRef: result.topupRef,
      cost: product.cost,
      type: orderData.type,
      number: orderData.number,
      value: orderData.value
    };
  }

  // Helper to get balance
  async function getBalance() {
    const response = await fetch(
      "https://api.oneclickdz.com/v3/account/balance",
      {
        headers: { "X-Access-Token": process.env.API_KEY },
      }
    );
    const result = await response.json();
    return result.data.balance;
  }

  // Usage
  try {
    const result = await validateAndSend({
      type: 'ADSL',
      number: '036362608',
      value: 1000,
      ref: `order-${Date.now()}`
    });
    
    console.log('✅ Order placed successfully');
    console.log(`  Top-up ID: ${result.topupId}`);
    console.log(`  Cost: ${result.cost} DA`);
  } catch (error) {
    console.error('❌ Order failed:', error.message);
  }
  ```

  ```python Python theme={null}
  def validate_and_send(order_data):
      # Step 1: Validate phone number
      try:
          validate_internet_number(order_data['type'], order_data['number'])
      except Exception as e:
          raise ValueError(f"Invalid phone number: {e}")
      
      # Step 2: Check product availability
      products = load_internet_products(order_data['type'])
      product = next(
          (p for p in products if p['value'] == order_data['value'] and p['available']),
          None
      )
      
      if not product:
          raise ValueError(
              f"Product {order_data['value']} DA not available for {order_data['type']}"
          )
      
      # Step 3: Check balance
      balance = get_balance()
      if balance < product['cost']:
          raise ValueError(
              f"Insufficient balance. Required: {product['cost']} DA, Available: {balance} DA"
          )
      
      # Step 4: Send order
      print(f"Sending {order_data['type']} {order_data['value']} DA to {order_data['number']}")
      result = send_internet_topup(order_data)
      
      return {
          'topupId': result['topupId'],
          'topupRef': result['topupRef'],
          'cost': product['cost'],
          'type': order_data['type'],
          'number': order_data['number'],
          'value': order_data['value']
      }

  def get_balance():
      response = requests.get(
          'https://api.oneclickdz.com/v3/account/balance',
          headers={'X-Access-Token': os.getenv('API_KEY')}
      )
      response.raise_for_status()
      return response.json()['data']['balance']

  # Usage
  try:
      result = validate_and_send({
          'type': 'ADSL',
          'number': '036362608',
          'value': 1000,
          'ref': f'order-{int(time.time() * 1000)}'
      })
      
      print('✅ Order placed successfully')
      print(f"  Top-up ID: {result['topupId']}")
      print(f"  Cost: {result['cost']} DA")
  except ValueError as e:
      print(f'❌ Order failed: {e}')
  ```

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

  function validateAndSend($orderData) {
      // Step 1: Validate phone number
      try {
          validateInternetNumber($orderData['type'], $orderData['number']);
      } catch (Exception $e) {
          throw new Exception("Invalid phone number: " . $e->getMessage());
      }
      
      // Step 2: Check product availability
      $products = loadInternetProducts($orderData['type']);
      $product = null;
      foreach ($products as $p) {
          if ($p['value'] === $orderData['value'] && $p['available']) {
              $product = $p;
              break;
          }
      }
      
      if ($product === null) {
          throw new Exception(
              "Product {$orderData['value']} DA not available for {$orderData['type']}"
          );
      }
      
      // Step 3: Check balance
      $balance = getBalance();
      if ($balance < $product['cost']) {
          throw new Exception(
              "Insufficient balance. Required: {$product['cost']} DA, Available: {$balance} DA"
          );
      }
      
      // Step 4: Send order
      error_log("Sending {$orderData['type']} {$orderData['value']} DA to {$orderData['number']}");
      $result = sendInternetTopup($orderData);
      
      return [
          'topupId' => $result['topupId'],
          'topupRef' => $result['topupRef'],
          'cost' => $product['cost'],
          'type' => $orderData['type'],
          'number' => $orderData['number'],
          'value' => $orderData['value']
      ];
  }

  function getBalance() {
      $ch = curl_init('https://api.oneclickdz.com/v3/account/balance');
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'X-Access-Token: ' . getenv('API_KEY')
      ]);
      $response = curl_exec($ch);
      curl_close($ch);
      
      $result = json_decode($response, true);
      return $result['data']['balance'];
  }

  // Usage
  try {
      $result = validateAndSend([
          'type' => 'ADSL',
          'number' => '036362608',
          'value' => 1000,
          'ref' => 'order-' . (int)(microtime(true) * 1000)
      ]);
      
      echo "✅ Order placed successfully\n";
      echo "  Top-up ID: {$result['topupId']}\n";
      echo "  Cost: {$result['cost']} DA\n";
  } catch (Exception $e) {
      echo "❌ Order failed: " . $e->getMessage() . "\n";
  }
  ?>
  ```
</CodeGroup>

## Transaction Tracking

Store order details in your database:

```javascript theme={null}
async function createOrderTransaction(userId, orderDetails) {
  const transaction = {
    userId,
    topupId: orderDetails.topupId,
    ref: orderDetails.topupRef,
    type: orderDetails.type,
    number: orderDetails.number,
    value: orderDetails.value,
    cost: orderDetails.cost,
    status: 'HANDLING',
    createdAt: new Date(),
    updatedAt: new Date()
  };
  
  await db.internetOrders.insertOne(transaction);
  
  console.log('Transaction saved:', transaction.topupId);
  return transaction;
}

// Usage
const orderResult = await validateAndSend(orderData);
await createOrderTransaction(userId, orderResult);
```

## Generating Unique References

Ensure each order has a unique reference:

```javascript theme={null}
function generateOrderReference(userId, type) {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 8);
  return `${type.toLowerCase()}-${userId}-${timestamp}-${random}`;
}

// Usage
const ref = generateOrderReference(123, 'ADSL');
// Example: 'adsl-123-1730448000000-x7k2m9'
```

## Error Handling

<CodeGroup>
  ```javascript Node.js theme={null}
  async function sendTopupSafely(orderData) {
    try {
      const result = await sendInternetTopup(orderData);
      return { success: true, data: result };
    } catch (error) {
      console.error('Order failed:', error);
      
      // Parse error type
      const message = error.message.toLowerCase();
      
      if (message.includes('err_phone')) {
        return {
          success: false,
          error: 'INVALID_PHONE',
          message: 'Invalid phone number for this service type'
        };
      }
      
      if (message.includes('err_stock')) {
        return {
          success: false,
          error: 'OUT_OF_STOCK',
          message: 'This card value is currently out of stock'
        };
      }
      
      if (message.includes('insufficient_balance')) {
        return {
          success: false,
          error: 'LOW_BALANCE',
          message: 'Insufficient account balance'
        };
      }
      
      if (message.includes('duplicated_ref')) {
        return {
          success: false,
          error: 'DUPLICATE_REF',
          message: 'This reference has already been used'
        };
      }
      
      return {
        success: false,
        error: 'UNKNOWN',
        message: 'Failed to process order. Please try again.'
      };
    }
  }
  ```

  ```python Python theme={null}
  def send_topup_safely(order_data):
      try:
          result = send_internet_topup(order_data)
          return {'success': True, 'data': result}
      except Exception as error:
          message = str(error).lower()
          
          if 'err_phone' in message:
              return {
                  'success': False,
                  'error': 'INVALID_PHONE',
                  'message': 'Invalid phone number for this service type'
              }
          
          if 'err_stock' in message:
              return {
                  'success': False,
                  'error': 'OUT_OF_STOCK',
                  'message': 'This card value is currently out of stock'
              }
          
          if 'insufficient_balance' in message:
              return {
                  'success': False,
                  'error': 'LOW_BALANCE',
                  'message': 'Insufficient account balance'
              }
          
          if 'duplicated_ref' in message:
              return {
                  'success': False,
                  'error': 'DUPLICATE_REF',
                  'message': 'This reference has already been used'
              }
          
          return {
              'success': False,
              'error': 'UNKNOWN',
              'message': 'Failed to process order. Please try again.'
          }
  ```

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

  function sendTopupSafely($orderData) {
      try {
          $result = sendInternetTopup($orderData);
          return ['success' => true, 'data' => $result];
      } catch (Exception $error) {
          $message = strtolower($error->getMessage());
          
          if (strpos($message, 'err_phone') !== false) {
              return [
                  'success' => false,
                  'error' => 'INVALID_PHONE',
                  'message' => 'Invalid phone number for this service type'
              ];
          }
          
          if (strpos($message, 'err_stock') !== false) {
              return [
                  'success' => false,
                  'error' => 'OUT_OF_STOCK',
                  'message' => 'This card value is currently out of stock'
              ];
          }
          
          if (strpos($message, 'insufficient_balance') !== false) {
              return [
                  'success' => false,
                  'error' => 'LOW_BALANCE',
                  'message' => 'Insufficient account balance'
              ];
          }
          
          if (strpos($message, 'duplicated_ref') !== false) {
              return [
                  'success' => false,
                  'error' => 'DUPLICATE_REF',
                  'message' => 'This reference has already been used'
              ];
          }
          
          return [
              'success' => false,
              'error' => 'UNKNOWN',
              'message' => 'Failed to process order. Please try again.'
          ];
      }
  }
  ?>
  ```
</CodeGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Validate First" icon="check">
    Always use `/check-number` before sending
  </Card>

  <Card title="Check Stock" icon="box">
    Verify product availability before ordering
  </Card>

  <Card title="Unique References" icon="fingerprint">
    Generate unique `ref` for each order
  </Card>

  <Card title="Store Immediately" icon="database">
    Save `topupId` right after successful submission
  </Card>
</CardGroup>

## After Submitting Order

<Steps>
  <Step title="Store Top-up ID">
    Save `topupId` to your database immediately
  </Step>

  <Step title="Start Polling">
    Begin checking status every 5-10 seconds
  </Step>

  <Step title="Update UI">
    Show "Processing order..." message to user
  </Step>

  <Step title="Wait for Final State">
    Continue polling until FULFILLED, REFUNDED, or QUEUED
  </Step>
</Steps>

## Next Steps

<CardGroup cols={3}>
  <Card title="Track Status" icon="chart-line" href="/en/internet-topup-guides/4-status-tracking">
    Poll order status until completion
  </Card>

  <Card title="Deliver Cards" icon="file-code" href="/en/internet-topup-guides/5-card-delivery">
    Deliver card codes to customers
  </Card>

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

  <Card title="Validate Numbers" icon="check" href="/en/internet-topup-guides/2-validation">
    Verify phone numbers first
  </Card>

  <Card title="Overview" icon="book-open" href="/en/internet-topup-guides/overview">
    Back to integration overview
  </Card>

  <Card title="Balance Check" icon="wallet" href="/en/api-reference/account/get-balance">
    Get account balance
  </Card>
</CardGroup>
