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

# Livraison du Code de Carte

> Livrer en toute sécurité les codes de carte internet et les détails des transactions aux clients

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

<Warning>
  **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.
</Warning>

## Structure des données de carte

Les commandes exécutées contiennent trois champs clés :

```json theme={null}
{
  "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

<Card title="GET /v3/internet/check-id/{id}" icon="magnifying-glass" href="/fr/api-reference/internet/check-by-id">
  Récupérer les détails de la carte exécutée
</Card>

## Stockage sécurisé

Chiffrez toujours les codes de carte avant de les stocker dans votre base de données :

<CodeGroup>
  ```javascript Node.js theme={null}
  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()
        }
      }
    );
  }
  ```

  ```python Python theme={null}
  from cryptography.hazmat.primitives.ciphers.aead import AESGCM
  import os
  import base64

  # Encryption key (32 bytes)
  ENCRYPTION_KEY = bytes.fromhex(os.getenv('ENCRYPTION_KEY'))

  def encrypt_card_code(code):
      aesgcm = AESGCM(ENCRYPTION_KEY)
      nonce = os.urandom(12)
      
      encrypted = aesgcm.encrypt(nonce, code.encode('utf-8'), None)
      
      return {
          'nonce': base64.b64encode(nonce).decode('utf-8'),
          'encryptedData': base64.b64encode(encrypted).decode('utf-8')
      }

  def decrypt_card_code(nonce_b64, encrypted_data_b64):
      aesgcm = AESGCM(ENCRYPTION_KEY)
      nonce = base64.b64decode(nonce_b64)
      encrypted = base64.b64decode(encrypted_data_b64)
      
      decrypted = aesgcm.decrypt(nonce, encrypted, None)
      
      return decrypted.decode('utf-8')

  # Store encrypted card
  def store_card_securely(topup_id, card_data):
      encrypted = encrypt_card_code(card_data['card_code'])
      
      db.internet_orders.update_one(
          {'topupId': topup_id},
          {
              '$set': {
                  'status': 'FULFILLED',
                  'encryptedCard': encrypted,
                  'numTrans': card_data['num_trans'],
                  'dateTraitement': card_data['date_traitement'],
                  'fulfilledAt': datetime.now()
              }
          }
      )
  ```

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

  // Using OpenSSL for encryption
  define('ENCRYPTION_KEY', getenv('ENCRYPTION_KEY')); // 32 bytes hex
  define('CIPHER_ALGO', 'aes-256-gcm');

  function encryptCardCode($code) {
      $key = hex2bin(ENCRYPTION_KEY);
      $iv = random_bytes(16);
      $tag = '';
      
      $encrypted = openssl_encrypt(
          $code,
          CIPHER_ALGO,
          $key,
          OPENSSL_RAW_DATA,
          $iv,
          $tag,
          '',
          16
      );
      
      return [
          'iv' => bin2hex($iv),
          'encryptedData' => bin2hex($encrypted),
          'authTag' => bin2hex($tag)
      ];
  }

  function decryptCardCode($ivHex, $encryptedHex, $authTagHex) {
      $key = hex2bin(ENCRYPTION_KEY);
      $iv = hex2bin($ivHex);
      $encrypted = hex2bin($encryptedHex);
      $authTag = hex2bin($authTagHex);
      
      $decrypted = openssl_decrypt(
          $encrypted,
          CIPHER_ALGO,
          $key,
          OPENSSL_RAW_DATA,
          $iv,
          $authTag
      );
      
      if ($decrypted === false) {
          throw new Exception('Decryption failed');
      }
      
      return $decrypted;
  }

  // Store encrypted card
  function storeCardSecurely($topupId, $cardData) {
      $encrypted = encryptCardCode($cardData['card_code']);
      
      updateOrderInDatabase($topupId, [
          'status' => 'FULFILLED',
          'encryptedCard' => $encrypted,
          'numTrans' => $cardData['num_trans'],
          'dateTraitement' => $cardData['date_traitement'],
          'fulfilledAt' => date('Y-m-d H:i:s')
      ]);
  }
  ?>
  ```
</CodeGroup>

## Méthodes de livraison

### 1. Livraison par e-mail

```javascript theme={null}
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

```javascript theme={null}
// 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

```javascript theme={null}
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

<CodeGroup>
  ```javascript Node.js theme={null}
  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`);
  }
  ```

  ```python Python theme={null}
  async def complete_order_delivery(topup_id, user_id):
      # 1. Get order details
      order = check_topup_status(topup_id)
      
      if order['status'] != 'FULFILLED':
          raise ValueError('Order not ready for delivery')
      
      # 2. Store encrypted card
      store_card_securely(topup_id, order)
      
      # 3. Deliver to customer
      await deliver_card_via_email(user_id, topup_id, order)
      
      # 4. Log delivery (without sensitive data)
      await log_card_delivery(topup_id, user_id, 'email')
      
      print(f"✅ Order {topup_id} delivery complete")
  ```

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

  function completeOrderDelivery($topupId, $userId) {
      // 1. Get order details
      $order = checkTopupStatus($topupId);
      
      if ($order['status'] !== 'FULFILLED') {
          throw new Exception('Order not ready for delivery');
      }
      
      // 2. Store encrypted card
      storeCardSecurely($topupId, $order);
      
      // 3. Deliver to customer
      deliverCardViaEmail($userId, $topupId, $order);
      
      // 4. Log delivery (without sensitive data)
      logCardDelivery($topupId, $userId, 'email');
      
      error_log("✅ Order {$topupId} delivery complete");
  }
  ?>
  ```
</CodeGroup>

## Journalisation d'audit

Journalisez les événements de livraison sans exposer les données de carte :

```javascript theme={null}
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 :

```javascript theme={null}
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

<CardGroup cols={2}>
  <Card title="Chiffrer au repos" icon="lock">
    Toujours chiffrer les codes de carte avant de les stocker en base de données
  </Card>

  <Card title="Utiliser HTTPS uniquement" icon="shield-halved">
    Ne jamais transmettre les cartes sur des connexions non chiffrées
  </Card>

  <Card title="Vérifier la propriété" icon="user-lock">
    Vérifier que l'utilisateur possède la commande avant d'afficher la carte
  </Card>

  <Card title="Pas de journaux en texte clair" icon="file-slash">
    Ne jamais journaliser les codes de carte en texte clair
  </Card>

  <Card title="Inclure les instructions" icon="book">
    Toujours fournir des instructions d'utilisation claires
  </Card>

  <Card title="Piste d'audit" icon="clipboard-list">
    Journaliser les événements de livraison sans données sensibles
  </Card>
</CardGroup>

## Liste de vérification de sécurité

<Steps>
  <Step title="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
  </Step>

  <Step title="Chiffrer avant de stocker">
    Toujours chiffrer `card_code` avant l'insertion en base de données
  </Step>

  <Step title="Vérifier la propriété de l'utilisateur">
    Vérifier que l'ID utilisateur correspond à la commande avant d'afficher la carte
  </Step>

  <Step title="Utiliser HTTPS">
    S'assurer que toutes les méthodes de livraison utilisent un transport chiffré
  </Step>

  <Step title="Journalisation d'audit">
    Journaliser les événements de livraison sans inclure les vrais codes de carte
  </Step>

  <Step title="Instructions claires">
    Fournir des instructions d'utilisation étape par étape pour chaque type de service
  </Step>
</Steps>

## Gestion des Erreurs

```javascript theme={null}
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

<CardGroup cols={3}>
  <Card title="Vue d'ensemble" icon="book-open" href="/fr/internet-topup-guides/overview">
    Retour à la vue d'ensemble de l'intégration
  </Card>

  <Card title="Suivre le statut" icon="chart-line" href="/fr/internet-topup-guides/4-status-tracking">
    Interroger l'exécution des commandes
  </Card>

  <Card title="Référence API" icon="book" href="/fr/api-reference/internet/check-by-id">
    Documentation complète de l'endpoint
  </Card>

  <Card title="Bonnes pratiques de sécurité" icon="shield" href="/fr/security-best-practices">
    Directives générales de sécurité
  </Card>

  <Card title="Envoyer les recharges" icon="paper-plane" href="/fr/internet-topup-guides/3-sending-topups">
    Soumettre des commandes validées
  </Card>

  <Card title="Charger les produits" icon="list" href="/fr/internet-topup-guides/1-loading-products">
    Récupérer les cartes disponibles
  </Card>
</CardGroup>
