Passer au contenu principal

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.

Vue d’ensemble

Une fois toutes les entrées validées, vous êtes prêt à envoyer la demande de recharge à l’API OneClickDz. Ce guide couvre la soumission des demandes, la gestion des réponses et la gestion de votre système de références.

Référence API

Consultez la documentation API complète pour l’endpoint POST /v3/mobile/send

Demande de recharge de base

Exemple simple

curl -X POST https://api.oneclickdz.com/v3/mobile/send \
  -H "Content-Type: application/json" \
  -H "X-Access-Token: YOUR_API_KEY" \
  -d '{
    "plan_code": "PREPAID_DJEZZY",
    "MSSIDN": "0778037340",
    "amount": 500,
    "ref": "order-1730462400-user123"
  }'

Réponse en cas de succès

{
  "success": true,
  "data": {
    "topupId": "6901616fe9e88196b4eb64b0",
    "topupRef": "order-1730462400-user123"
  },
  "meta": {
    "timestamp": "2025-11-01T11:00:00.454Z"
  },
  "requestId": "req_1730462400_abc123"
}

Générer des références uniques

Fournissez toujours des références uniques pour éviter les doublons et permettre le suivi :
function generateOrderRef(userId) {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2, 8);
  return `${userId}-${timestamp}-${random}`;
}

// Examples:
// user123-1730462400-x7k2p9
// user456-1730462401-m5n8q3

Vérifier le solde avant l’envoi

Vérifiez toujours que le solde est suffisant pour éviter les demandes échouées :

Référence API du solde

En savoir plus sur l’endpoint GET /v3/account/balance
async function checkBalance() {
  const response = await fetch('https://api.oneclickdz.com/v3/account/balance', {
    headers: {
      'X-Access-Token': process.env.ONECLICKDZ_API_KEY
    }
  });
  
  const data = await response.json();
  
  if (!data.success) {
    throw new Error('Failed to check balance');
  }
  
  return data.data.balance;
}

async function sendTopUpWithBalanceCheck({ planCode, phone, amount, ref, requiredBalance }) {
  // Check balance first
  const balance = await checkBalance();
  
  if (balance < requiredBalance) {
    throw new Error(`Insufficient balance. Required: ${requiredBalance} DZD, Available: ${balance} DZD`);
  }
  
  // Proceed with top-up
  return await sendTopUp({ planCode, phone, amount, ref });
}

Gestion des erreurs

Gérez les erreurs API courantes :
Consultez la Référence de gestion des erreurs pour les codes d’erreur complets et les stratégies de traitement.
async function sendTopUpSafe(data) {
  try {
    return await sendTopUp(data);
  } catch (error) {
    // Parse error response
    if (error.response) {
      const errorData = error.response.data;
      
      switch (errorData.error?.code) {
        case 'ERR_VALIDATION':
          console.error('Validation error:', errorData.error.message);
          console.error('Field:', errorData.error.details?.field);
          break;
          
        case 'INSUFFICIENT_BALANCE':
          console.error('Insufficient balance');
          console.error('Required:', errorData.error.details?.required);
          console.error('Available:', errorData.error.details?.available);
          break;
          
        case 'DUPLICATED_REF':
          console.error('Duplicate reference');
          console.error('Existing topup:', errorData.error.details?.existingTopupId);
          // Check status of existing topup
          break;
          
        case 'INTERNAL_ERROR':
          console.error('Server error, contact support');
          console.error('Request ID:', errorData.requestId);
          break;
          
        default:
          console.error('Unknown error:', errorData.error?.message);
      }
    }
    
    throw error;
  }
}

Intégration avec la base de données

Enregistrez les commandes avant et après les appels API :
async function createTopUpOrder({ userId, planCode, phone, amount }) {
  // Start database transaction
  const transaction = await db.transaction();
  
  try {
    // 1. Generate reference
    const ref = generateOrderRef(userId);
    
    // 2. Get plan details
    const plan = await db.mobilePlans.findOne({
      where: { code: planCode }
    });
    
    const cost = amount * plan.wholesaleCost;
    
    // 3. Check user balance
    const user = await db.users.findOne({
      where: { id: userId },
      lock: true,  // Lock row for update
      transaction
    });
    
    if (user.balance < cost) {
      await transaction.rollback();
      throw new Error('Insufficient user balance');
    }
    
    // 4. Create order record
    const order = await db.orders.create({
      userId,
      ref,
      planCode,
      phone,
      amount,
      cost,
      status: 'PENDING',
      createdAt: new Date()
    }, { transaction });
    
    // 5. Deduct user balance
    await db.users.update({
      balance: user.balance - cost
    }, {
      where: { id: userId },
      transaction
    });
    
    // 6. Send to API
    const result = await sendTopUp({
      planCode,
      phone,
      amount,
      ref
    });
    
    // 7. Update order with API response
    await db.orders.update({
      apiTopupId: result.topupId,
      apiTopupRef: result.topupRef,
      status: 'PROCESSING'
    }, {
      where: { id: order.id },
      transaction
    });
    
    // Commit transaction
    await transaction.commit();
    
    return {
      orderId: order.id,
      topupId: result.topupId,
      ref: ref
    };
    
  } catch (error) {
    // Rollback on any error
    await transaction.rollback();
    throw error;
  }
}

Traitement asynchrone

Pour de meilleures performances, traitez les recharges de manière asynchrone :
const Queue = require('bull');
const topupQueue = new Queue('topup-processing');

// Add job to queue
async function queueTopUp(orderData) {
  const order = await db.orders.create({
    ...orderData,
    status: 'QUEUED'
  });
  
  await topupQueue.add({
    orderId: order.id
  });
  
  return order;
}

// Process queue
topupQueue.process(async (job) => {
  const { orderId } = job.data;
  
  const order = await db.orders.findOne({ where: { id: orderId } });
  
  try {
    // Send top-up
    const result = await sendTopUp({
      planCode: order.planCode,
      phone: order.phone,
      amount: order.amount,
      ref: order.ref
    });
    
    // Update order
    await db.orders.update({
      apiTopupId: result.topupId,
      status: 'PROCESSING'
    }, {
      where: { id: orderId }
    });
    
    // Start status polling (another queue)
    await pollQueue.add({ topupId: result.topupId, orderId });
    
  } catch (error) {
    // Handle error
    await db.orders.update({
      status: 'FAILED',
      errorMessage: error.message
    }, {
      where: { id: orderId }
    });
    
    // Refund user
    await refundUser(order.userId, order.cost);
  }
});

Logique de nouvelle tentative

Implémentez des nouvelles tentatives pour les erreurs réseau :
async function sendTopUpWithRetry(data, maxRetries = 3) {
  let lastError;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await sendTopUp(data);
    } catch (error) {
      lastError = error;
      
      // Don't retry on validation or duplicate errors
      if (error.code === 'ERR_VALIDATION' || error.code === 'DUPLICATED_REF') {
        throw error;
      }
      
      // Wait before retry (exponential backoff)
      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000; // 2s, 4s, 8s
        console.log(`Retry ${attempt}/${maxRetries} after ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
  
  throw lastError;
}

Bonnes pratiques

Générez un ref unique pour chaque demande afin d’éviter les doublons et permettre le suivi.
Vérifiez que le solde est suffisant avant d’envoyer la demande pour éviter les échecs.
Encapsulez la création de commande et la déduction de solde dans des transactions pour la cohérence des données.
Utilisez des files d’attente pour de meilleures performances et une meilleure expérience utilisateur.
Réessayez les erreurs réseau avec un backoff exponentiel, mais pas les erreurs de validation.
Journalisez toutes les demandes et réponses à des fins de débogage et d’audit.

Étapes suivantes

Étape 4 : Interrogation du statut

Apprenez à interroger et suivre le statut des recharges

API de vérification par référence

Documentation API pour GET /v3/mobile/check-ref/:ref

API de vérification par ID

Documentation API pour GET /v3/mobile/check-id/:id

Référence de gestion des erreurs

Guide complet de gestion et de récupération des erreurs

Configuration des Webhooks

Configurez des notifications de statut en temps réel

Stratégies d'interrogation

Optimisez votre implémentation d’interrogation

API Historique des transactions

Consultez l’historique de vos transactions

API de solde

Endpoint de vérification du solde du compte