Overview
The products endpoint returns available internet recharge cards for ADSL or 4G LTE services with real-time pricing and stock availability. Products should be cached briefly to minimize API calls.Cache product data for 5-10 minutes. Stock levels change more frequently than gift cards.
API Reference
GET /v3/internet/products
Complete endpoint documentation
Basic Product Loading
async function loadInternetProducts(type) {
if (!['ADSL', '4G'].includes(type)) {
throw new Error('Invalid type. Must be ADSL or 4G');
}
const response = await fetch(
`https://api.oneclickdz.com/v3/internet/products?type=${type}`,
{
headers: {
"X-Access-Token": process.env.API_KEY,
},
}
);
if (!response.ok) {
throw new Error(`Failed to load products: ${response.status}`);
}
const result = await response.json();
return result.data.products;
}
// Usage
const adslProducts = await loadInternetProducts('ADSL');
const lteProducts = await loadInternetProducts('4G');
console.log(`ADSL: ${adslProducts.length} products`);
console.log(`4G: ${lteProducts.length} products`);
import requests
import os
def load_internet_products(service_type):
if service_type not in ['ADSL', '4G']:
raise ValueError('Invalid type. Must be ADSL or 4G')
response = requests.get(
'https://api.oneclickdz.com/v3/internet/products',
headers={'X-Access-Token': os.getenv('API_KEY')},
params={'type': service_type}
)
response.raise_for_status()
return response.json()['data']['products']
# Usage
adsl_products = load_internet_products('ADSL')
lte_products = load_internet_products('4G')
print(f"ADSL: {len(adsl_products)} products")
print(f"4G: {len(lte_products)} products")
<?php
function loadInternetProducts($type) {
if (!in_array($type, ['ADSL', '4G'])) {
throw new InvalidArgumentException('Invalid type. Must be ADSL or 4G');
}
$url = "https://api.oneclickdz.com/v3/internet/products?type={$type}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'X-Access-Token: ' . getenv('API_KEY')
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new Exception("Failed to load products: " . $httpCode);
}
$result = json_decode($response, true);
return $result['data']['products'];
}
// Usage
$adslProducts = loadInternetProducts('ADSL');
$lteProducts = loadInternetProducts('4G');
echo "ADSL: " . count($adslProducts) . " products\n";
echo "4G: " . count($lteProducts) . " products\n";
?>
# ADSL products
curl "https://api.oneclickdz.com/v3/internet/products?type=ADSL" \
-H "X-Access-Token: YOUR_API_KEY"
# 4G products
curl "https://api.oneclickdz.com/v3/internet/products?type=4G" \
-H "X-Access-Token: YOUR_API_KEY"
Response Structure
{
"success": true,
"data": {
"products": [
{
"value": 500,
"cost": 490,
"available": true
},
{
"value": 1000,
"cost": 980,
"available": true
},
{
"value": 2000,
"cost": 1960,
"available": true
},
{
"value": 5000,
"cost": 4900,
"available": false
}
]
},
"meta": {
"timestamp": "2025-11-01T12:00:00.000Z",
"type": "ADSL"
}
}
Caching Implementation
class ProductCache {
constructor(ttlMinutes = 10) {
this.cache = new Map();
this.ttl = ttlMinutes * 60 * 1000;
}
async get(type) {
const cached = this.cache.get(type);
const now = Date.now();
// Return cached if still valid
if (cached && (now - cached.timestamp) < this.ttl) {
console.log(`Returning cached ${type} products`);
return cached.data;
}
// Fetch fresh data
console.log(`Fetching fresh ${type} products`);
const products = await loadInternetProducts(type);
this.cache.set(type, {
data: products,
timestamp: now,
});
return products;
}
invalidate(type) {
if (type) {
this.cache.delete(type);
} else {
this.cache.clear();
}
}
}
// Usage
const cache = new ProductCache(10); // 10 minutes TTL
// First call - fetches from API
const adsl1 = await cache.get('ADSL');
// Second call within 10 minutes - returns cached
const adsl2 = await cache.get('ADSL');
// Different type - fetches separately
const lte = await cache.get('4G');
// Force refresh
cache.invalidate('ADSL');
const adsl3 = await cache.get('ADSL'); // Fetches fresh
from datetime import datetime, timedelta
import requests
import os
class ProductCache:
def __init__(self, ttl_minutes=10):
self.cache = {}
self.ttl = timedelta(minutes=ttl_minutes)
def get(self, service_type):
cached = self.cache.get(service_type)
now = datetime.now()
# Return cached if still valid
if cached and (now - cached['timestamp']) < self.ttl:
print(f"Returning cached {service_type} products")
return cached['data']
# Fetch fresh data
print(f"Fetching fresh {service_type} products")
products = load_internet_products(service_type)
self.cache[service_type] = {
'data': products,
'timestamp': now
}
return products
def invalidate(self, service_type=None):
if service_type:
self.cache.pop(service_type, None)
else:
self.cache.clear()
# Usage
cache = ProductCache(ttl_minutes=10)
# First call - fetches from API
adsl1 = cache.get('ADSL')
# Second call within 10 minutes - returns cached
adsl2 = cache.get('ADSL')
# Different type - fetches separately
lte = cache.get('4G')
# Force refresh
cache.invalidate('ADSL')
adsl3 = cache.get('ADSL')
<?php
class ProductCache {
private $cache = [];
private $ttl;
public function __construct($ttlMinutes = 10) {
$this->ttl = $ttlMinutes * 60;
}
public function get($type) {
$now = time();
// Return cached if still valid
if (isset($this->cache[$type]) &&
($now - $this->cache[$type]['timestamp']) < $this->ttl) {
error_log("Returning cached {$type} products");
return $this->cache[$type]['data'];
}
// Fetch fresh data
error_log("Fetching fresh {$type} products");
$products = loadInternetProducts($type);
$this->cache[$type] = [
'data' => $products,
'timestamp' => $now
];
return $products;
}
public function invalidate($type = null) {
if ($type) {
unset($this->cache[$type]);
} else {
$this->cache = [];
}
}
}
// Usage
$cache = new ProductCache(10);
// First call - fetches from API
$adsl1 = $cache->get('ADSL');
// Second call within 10 minutes - returns cached
$adsl2 = $cache->get('ADSL');
// Different type - fetches separately
$lte = $cache->get('4G');
// Force refresh
$cache->invalidate('ADSL');
$adsl3 = $cache->get('ADSL');
?>
Filtering Available Products
Only show products that are in stock:function getAvailableProducts(products) {
return products.filter(p => p.available);
}
// Usage
const allProducts = await cache.get('ADSL');
const available = getAvailableProducts(allProducts);
console.log(`${available.length}/${allProducts.length} products in stock`);
if (available.length === 0) {
console.log('No products available at the moment');
}
def get_available_products(products):
return [p for p in products if p['available']]
# Usage
all_products = cache.get('ADSL')
available = get_available_products(all_products)
print(f"{len(available)}/{len(all_products)} products in stock")
if not available:
print('No products available at the moment')
<?php
function getAvailableProducts($products) {
return array_filter($products, function($p) {
return $p['available'];
});
}
// Usage
$allProducts = $cache->get('ADSL');
$available = array_values(getAvailableProducts($allProducts));
echo count($available) . "/" . count($allProducts) . " products in stock\n";
if (empty($available)) {
echo "No products available at the moment\n";
}
?>
Applying Customer Markup
Add your profit margin to wholesale prices:function applyMarkup(products, markupPercent = 5) {
return products
.filter(p => p.available)
.map(p => ({
value: p.value,
wholesaleCost: p.cost, // Store but don't show
customerPrice: Math.ceil(p.cost * (1 + markupPercent / 100)),
available: true,
}));
}
// Usage
const products = await cache.get('ADSL');
const customerPrices = applyMarkup(products, 5); // 5% markup
customerPrices.forEach(p => {
console.log(`${p.value} DA card: ${p.customerPrice} DA`);
// Don't log wholesaleCost in production!
});
import math
def apply_markup(products, markup_percent=5):
available = [p for p in products if p['available']]
return [
{
'value': p['value'],
'wholesaleCost': p['cost'], # Store but don't show
'customerPrice': math.ceil(p['cost'] * (1 + markup_percent / 100)),
'available': True
}
for p in available
]
# Usage
products = cache.get('ADSL')
customer_prices = apply_markup(products, markup_percent=5)
for p in customer_prices:
print(f"{p['value']} DA card: {p['customerPrice']} DA")
<?php
function applyMarkup($products, $markupPercent = 5) {
$available = array_filter($products, function($p) {
return $p['available'];
});
return array_map(function($p) use ($markupPercent) {
return [
'value' => $p['value'],
'wholesaleCost' => $p['cost'], // Store but don't show
'customerPrice' => ceil($p['cost'] * (1 + $markupPercent / 100)),
'available' => true
];
}, $available);
}
// Usage
$products = $cache->get('ADSL');
$customerPrices = applyMarkup($products, 5); // 5% markup
foreach ($customerPrices as $p) {
echo "{$p['value']} DA card: {$p['customerPrice']} DA\n";
}
?>
Building Product UI
Example structure for displaying products to customers:async function buildProductOptions(type, markupPercent = 5) {
const products = await cache.get(type);
return {
serviceType: type,
serviceName: type === 'ADSL' ? 'ADSL Internet' : '4G LTE Internet',
options: products
.filter(p => p.available)
.map(p => ({
value: p.value,
label: `${p.value} DA`,
price: Math.ceil(p.cost * (1 + markupPercent / 100)),
inStock: true,
}))
.sort((a, b) => a.value - b.value) // Sort by value ascending
};
}
// Usage
const adslOptions = await buildProductOptions('ADSL', 5);
const lteOptions = await buildProductOptions('4G', 5);
// Returns UI-ready structure:
// {
// serviceType: 'ADSL',
// serviceName: 'ADSL Internet',
// options: [
// { value: 500, label: '500 DA', price: 515, inStock: true },
// { value: 1000, label: '1000 DA', price: 1029, inStock: true },
// ...
// ]
// }
Loading Both Service Types
Fetch ADSL and 4G products in parallel:async function loadAllInternetProducts() {
const [adsl, lte] = await Promise.all([
cache.get('ADSL'),
cache.get('4G'),
]);
return {
adsl: applyMarkup(adsl, 5),
lte: applyMarkup(lte, 5),
};
}
// Usage
const allProducts = await loadAllInternetProducts();
console.log('ADSL:', allProducts.adsl.length, 'products');
console.log('4G:', allProducts.lte.length, 'products');
Best Practices
Cache 5-10 Minutes
Balance freshness with API load reduction
Filter Available Only
Only display products where
available: trueHide Wholesale Prices
Never show raw
cost values to customersHandle Errors Gracefully
Fall back to cached data if API is temporarily unavailable
Error Handling
async function loadProductsSafely(type) {
try {
return await cache.get(type);
} catch (error) {
console.error(`Failed to load ${type} products:`, error);
// Return stale cached data if available
const cached = cache.cache.get(type);
if (cached) {
console.log('Using stale cached data');
return cached.data;
}
throw new Error(`${type} products unavailable`);
}
}
Next Steps
Validate Numbers
Verify phone numbers before ordering
Send Top-Ups
Submit orders with error handling
API Reference
Complete endpoint documentation
Overview
Back to integration overview
Track Status
Monitor order fulfillment
Deliver Cards
Securely deliver card codes

