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 les commandes de recharge internet exécutées, récupérez les codes de carte et les numéros de transaction depuis l’API et livrez-les en toute sécurité aux clients. Les codes de carte doivent être manipulés avec soin car ils représentent une valeur.
Critique en matière de sécurité : Les codes de carte sont des identifiants précieux. Chiffrez toujours lors du stockage et de la transmission.

Structure des données de carte

Les commandes exécutées contiennent trois champs clés :
{
  "status": "FULFILLED",
  "card_code": "123456789012",
  "num_trans": "AT-2025-12345",
  "date_traitement": "2025-11-01T12:00:45.000Z"
}
  • card_code : Le code rechargeable à saisir (identifiant principal)
  • num_trans : Numéro de transaction Algérie Télécom (preuve d’achat)
  • date_traitement : Horodatage de traitement
Ces trois éléments doivent être livrés au client.

Référence API

GET /v3/internet/check-id/{id}

Récupérer les détails de la carte exécutée

Stockage sécurisé

Chiffrez toujours les codes de carte avant de les stocker dans votre base de données :
const crypto = require('crypto');

// Encryption configuration
const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY; // Must be 32 bytes
const ALGORITHM = 'aes-256-gcm';

function encryptCardCode(code) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(
    ALGORITHM,
    Buffer.from(ENCRYPTION_KEY, 'hex'),
    iv
  );
  
  let encrypted = cipher.update(code, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  
  const authTag = cipher.getAuthTag();
  
  return {
    iv: iv.toString('hex'),
    encryptedData: encrypted,
    authTag: authTag.toString('hex')
  };
}

function decryptCardCode(iv, encryptedData, authTag) {
  const decipher = crypto.createDecipheriv(
    ALGORITHM,
    Buffer.from(ENCRYPTION_KEY, 'hex'),
    Buffer.from(iv, 'hex')
  );
  
  decipher.setAuthTag(Buffer.from(authTag, 'hex'));
  
  let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  
  return decrypted;
}

// Store encrypted card
async function storeCardSecurely(topupId, cardData) {
  const encrypted = encryptCardCode(cardData.card_code);
  
  await db.internetOrders.updateOne(
    { topupId },
    {
      $set: {
        status: 'FULFILLED',
        encryptedCard: encrypted,
        numTrans: cardData.num_trans,
        dateTraitement: cardData.date_traitement,
        fulfilledAt: new Date()
      }
    }
  );
}

Méthodes de livraison

1. Livraison par e-mail

async function deliverCardViaEmail(userId, topupId, cardData) {
  const user = await db.users.findOne({ _id: userId });
  
  await sendEmail({
    to: user.email,
    subject: 'Your Internet Card is Ready',
    html: `
      <h2>Your internet recharge card</h2>
      <p>Service: ${cardData.type}</p>
      <p>Number: ${cardData.number}</p>
      <p>Value: ${cardData.topup_amount} DA</p>
      
      <h3>Card Details:</h3>
      <p><strong>Card Code:</strong> ${cardData.card_code}</p>
      <p><strong>Transaction Number:</strong> ${cardData.num_trans}</p>
      <p><strong>Date:</strong> ${new Date(cardData.date_traitement).toLocaleString()}</p>
      
      <h3>How to Use:</h3>
      <p>1. Dial *600# from your ${cardData.type} line</p>
      <p>2. Select "Recharge"</p>
      <p>3. Enter the card code: ${cardData.card_code}</p>
      
      <p><strong>Important:</strong> Keep this code secure and don't share it with anyone.</p>
    `
  });
  
  // Mark as delivered
  await db.internetOrders.updateOne(
    { topupId },
    { $set: { deliveredAt: new Date() } }
  );
  
  console.log(`Card delivered to ${user.email}`);
}

2. Affichage dans l’application

// API endpoint to display card in-app
app.get('/api/internet-orders/:topupId/card', authenticateUser, async (req, res) => {
  const { topupId } = req.params;
  const userId = req.user.id;
  
  // Verify ownership
  const order = await db.internetOrders.findOne({ topupId, userId });
  
  if (!order) {
    return res.status(404).json({ error: 'Order not found' });
  }
  
  if (order.status !== 'FULFILLED') {
    return res.status(400).json({ error: 'Order not fulfilled yet' });
  }
  
  // Decrypt card code
  const cardCode = decryptCardCode(
    order.encryptedCard.iv,
    order.encryptedCard.encryptedData,
    order.encryptedCard.authTag
  );
  
  res.json({
    topupId: order.topupId,
    type: order.type,
    number: order.number,
    value: order.value,
    cardCode,
    transactionNumber: order.numTrans,
    processedDate: order.dateTraitement,
    instructions: getUsageInstructions(order.type)
  });
});

function getUsageInstructions(type) {
  if (type === 'ADSL') {
    return [
      'Dial *600# from your ADSL line',
      'Select "Recharge"',
      'Enter the card code',
      'Confirm to add credit to your account'
    ];
  } else { // 4G
    return [
      'Dial *600# from your 4G device',
      'Select "Recharge"',
      'Enter the card code',
      'Your data will be activated immediately'
    ];
  }
}

3. Livraison par SMS

async function deliverCardViaSMS(phoneNumber, cardData) {
  const message = `Your ${cardData.type} card is ready!\n\nCard Code: ${cardData.card_code}\nTransaction: ${cardData.num_trans}\n\nTo use: Dial *600# and follow instructions.`;
  
  await sendSMS({
    to: phoneNumber,
    message
  });
  
  console.log(`Card delivered via SMS to ${phoneNumber}`);
}

Flux de livraison complet

async function completeOrderDelivery(topupId, userId) {
  // 1. Get order details
  const order = await checkTopupStatus(topupId);
  
  if (order.status !== 'FULFILLED') {
    throw new Error('Order not ready for delivery');
  }
  
  // 2. Store encrypted card
  await storeCardSecurely(topupId, order);
  
  // 3. Deliver to customer
  await deliverCardViaEmail(userId, topupId, order);
  
  // 4. Log delivery (without sensitive data)
  await logCardDelivery(topupId, userId, 'email');
  
  console.log(`✅ Order ${topupId} delivery complete`);
}

Journalisation d’audit

Journalisez les événements de livraison sans exposer les données de carte :
async function logCardDelivery(topupId, userId, method) {
  await db.auditLogs.insertOne({
    event: 'CARD_DELIVERED',
    topupId,
    userId,
    method, // 'email', 'sms', 'in-app'
    timestamp: new Date(),
    ipAddress: req.ip,
    userAgent: req.headers['user-agent']
  });
  
  // ❌ Ne jamais journaliser les vrais codes de carte
  // console.log('Card code:', card.card_code); // NE PAS FAIRE
}

Instructions d’Utilisation par Type

Fournissez des instructions claires pour chaque type de service :
function getCardUsageInstructions(type) {
  const instructions = {
    ADSL: {
      title: 'Comment utiliser votre carte ADSL',
      steps: [
        'Décrochez votre téléphone fixe',
        'Composez *600#',
        'Sélectionnez "Recharge" ou "Flexy"',
        'Entrez votre code de carte : ${cardCode}',
        'Appuyez sur # pour confirmer',
        'Votre crédit sera ajouté immédiatement'
      ],
      support: 'Pour obtenir de l\'aide, appelez le 3003 depuis votre ligne ADSL'
    },
    '4G': {
      title: 'Comment utiliser votre carte 4G',
      steps: [
        'Assurez-vous que votre SIM 4G est active',
        'Composez *600# depuis votre appareil',
        'Sélectionnez "Recharge Internet"',
        'Entrez votre code de carte : ${cardCode}',
        'Appuyez sur # pour confirmer',
        'Vos données seront activées en quelques minutes'
      ],
      support: 'Pour obtenir de l\'aide, appelez le 3003 depuis votre mobile'
    }
  };
  
  return instructions[type];
}

Bonnes pratiques

Chiffrer au repos

Toujours chiffrer les codes de carte avant de les stocker en base de données

Utiliser HTTPS uniquement

Ne jamais transmettre les cartes sur des connexions non chiffrées

Vérifier la propriété

Vérifier que l’utilisateur possède la commande avant d’afficher la carte

Pas de journaux en texte clair

Ne jamais journaliser les codes de carte en texte clair

Inclure les instructions

Toujours fournir des instructions d’utilisation claires

Piste d'audit

Journaliser les événements de livraison sans données sensibles

Liste de vérification de sécurité

1

Générer une clé de chiffrement

Créer une clé de chiffrement sécurisée de 32 octets et la stocker dans les variables d’environnement
2

Chiffrer avant de stocker

Toujours chiffrer card_code avant l’insertion en base de données
3

Vérifier la propriété de l'utilisateur

Vérifier que l’ID utilisateur correspond à la commande avant d’afficher la carte
4

Utiliser HTTPS

S’assurer que toutes les méthodes de livraison utilisent un transport chiffré
5

Journalisation d'audit

Journaliser les événements de livraison sans inclure les vrais codes de carte
6

Instructions claires

Fournir des instructions d’utilisation étape par étape pour chaque type de service

Gestion des Erreurs

async function deliverCardSafely(topupId, userId) {
  try {
    await completeOrderDelivery(topupId, userId);
    return { success: true };
  } catch (error) {
    console.error('Échec de livraison :', error);
    
    if (error.message.includes('not ready')) {
      return {
        success: false,
        error: 'ORDER_NOT_READY',
        message: 'La commande est toujours en cours de traitement. Veuillez patienter.'
      };
    }
    
    if (error.message.includes('not found')) {
      return {
        success: false,
        error: 'ORDER_NOT_FOUND',
        message: 'Commande introuvable ou vous n\'y avez pas accès.'
      };
    }
    
    return {
      success: false,
      error: 'DELIVERY_FAILED',
      message: 'Échec de livraison de la carte. Veuillez contacter le support.'
    };
  }
}

Étapes suivantes

Vue d'ensemble

Retour à la vue d’ensemble de l’intégration

Suivre le statut

Interroger l’exécution des commandes

Référence API

Documentation complète de l’endpoint

Bonnes pratiques de sécurité

Directives générales de sécurité

Envoyer les recharges

Soumettre des commandes validées

Charger les produits

Récupérer les cartes disponibles