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 exécutées, récupérez les codes et numéros de série des cartes depuis l’API et livrez-les en toute sécurité aux clients. Ne stockez jamais les codes de carte en texte clair.
Critique en matière de sécurité : Les codes de carte sont des identifiants précieux. Chiffrez-les lors du stockage et de la transmission.

Référence API

GET /v3/gift-cards/checkOrder/{orderId}

Récupérer les cartes exécutées de la commande

Structure des données de carte

Les commandes exécutées contiennent des cartes avec deux champs :
{
  "cards": [
    {
      "value": "XXXX-XXXX-XXXX-XXXX",  // Identifiant principal (PIN/code)
      "serial": "123456789"             // Identifiant secondaire (numéro de série)
    }
  ]
}
Les champs value et serial sont sensibles et doivent être protégés.

Aides au chiffrement

const crypto = require('crypto');

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

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

function decryptCardData(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;
}

// Usage
const encrypted = encryptCardData('XXXX-XXXX-XXXX-XXXX');
const decrypted = decryptCardData(encrypted.iv, encrypted.encryptedData, encrypted.authTag);

Stockage sécurisé des cartes

async function storeOrderCards(orderId, userId, cards) {
  const encryptedCards = cards.map(card => {
    const encryptedValue = encryptCardData(card.value);
    const encryptedSerial = encryptCardData(card.serial);
    
    return {
      value: encryptedValue,
      serial: encryptedSerial,
      deliveredAt: null
    };
  });
  
  await db.orders.updateOne(
    { orderId },
    {
      $set: {
        userId,
        status: 'FULFILLED',
        encryptedCards,
        fulfilledAt: new Date()
      }
    }
  );
  
  console.log(`Stored ${cards.length} encrypted cards for order ${orderId}`);
}

// Retrieve and decrypt
async function getOrderCards(orderId) {
  const order = await db.orders.findOne({ orderId });
  
  if (!order || !order.encryptedCards) {
    throw new Error('Order not found or cards not available');
  }
  
  return order.encryptedCards.map(card => ({
    value: decryptCardData(
      card.value.iv,
      card.value.encryptedData,
      card.value.authTag
    ),
    serial: decryptCardData(
      card.serial.iv,
      card.serial.encryptedData,
      card.serial.authTag
    )
  }));
}

Méthodes de livraison

1. Livraison par e-mail

async function deliverCardsViaEmail(userId, orderId, cards) {
  const user = await db.users.findOne({ _id: userId });
  
  // Build email content with cards
  const cardList = cards.map((card, index) => `
    Card ${index + 1}:
    Code: ${card.value}
    Serial: ${card.serial}
  `).join('\n\n');
  
  await sendEmail({
    to: user.email,
    subject: 'Your Gift Card Order',
    html: `
      <h2>Your gift cards are ready!</h2>
      <p>Order ID: ${orderId}</p>
      <pre>${cardList}</pre>
      <p><strong>Important:</strong> Keep these codes secure and don't share them.</p>
    `
  });
  
  // Mark as delivered
  await db.orders.updateOne(
    { orderId },
    { $set: { 'encryptedCards.$[].deliveredAt': new Date() } }
  );
  
  console.log(`Delivered ${cards.length} cards to ${user.email}`);
}

2. Affichage dans l’application

// API endpoint to display cards in-app
app.get('/api/orders/:orderId/cards', authenticateUser, async (req, res) => {
  const { orderId } = req.params;
  const userId = req.user.id;
  
  // Verify ownership
  const order = await db.orders.findOne({ orderId, 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 and return cards
  const cards = await getOrderCards(orderId);
  
  res.json({
    orderId,
    cards: cards.map((card, index) => ({
      cardNumber: index + 1,
      code: card.value,
      serial: card.serial
    }))
  });
});

3. Téléchargement sécurisé de fichier

async function generateSecureCardFile(orderId, cards) {
  const content = cards.map((card, index) => `
Gift Card ${index + 1}
Code: ${card.value}
Serial: ${card.serial}
--------------------
  `).join('\n');
  
  // Encrypt the file content
  const encrypted = encryptCardData(content);
  
  // Store temporarily with unique token
  const token = crypto.randomBytes(32).toString('hex');
  await db.downloadTokens.insertOne({
    token,
    orderId,
    encrypted,
    expiresAt: new Date(Date.now() + 5 * 60 * 1000) // 5 minutes
  });
  
  return token;
}

// Download endpoint
app.get('/api/download/:token', async (req, res) => {
  const { token } = req.params;
  
  const download = await db.downloadTokens.findOne({ token });
  
  if (!download || download.expiresAt < new Date()) {
    return res.status(404).json({ error: 'Download link expired' });
  }
  
  const content = decryptCardData(
    download.encrypted.iv,
    download.encrypted.encryptedData,
    download.encrypted.authTag
  );
  
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Disposition', `attachment; filename="cards-${download.orderId}.txt"`);
  res.send(content);
  
  // Delete token after use
  await db.downloadTokens.deleteOne({ token });
});

Journalisation d’audit

Journalisez les événements de livraison sans exposer les données de carte :
async function logCardDelivery(orderId, userId, method, cardCount) {
  await db.auditLogs.insertOne({
    event: 'CARDS_DELIVERED',
    orderId,
    userId,
    method, // 'email', 'in-app', 'download'
    cardCount,
    timestamp: new Date(),
    ipAddress: req.ip,
    userAgent: req.headers['user-agent']
  });
  
  console.log(`[AUDIT] Delivered ${cardCount} cards for order ${orderId} via ${method}`);
}

// ❌ Ne jamais journaliser les vrais codes de carte
// console.log('Card code:', card.value); // NE PAS FAIRE

Bonnes pratiques

Chiffrer au repos

Toujours chiffrer les cartes avant de les stocker en base de données

Utiliser HTTPS uniquement

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

Limiter l'accès

Vérifier la propriété de l’utilisateur avant d’afficher les cartes

Pas de journaux en texte clair

Ne jamais journaliser les codes de carte en texte clair

Suppression sécurisée

Supprimer les cartes en toute sécurité après récupération par le client si la politique l’exige

Piste d'audit

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

Flux de livraison complet

async function completeOrderDelivery(orderId, userId) {
  // 1. Verify order is fulfilled
  const orderStatus = await checkOrderStatus(orderId);
  
  if (orderStatus.status !== 'FULFILLED' && orderStatus.status !== 'PARTIALLY_FILLED') {
    throw new Error('Order not ready for delivery');
  }
  
  // 2. Store encrypted cards
  await storeOrderCards(orderId, userId, orderStatus.cards);
  
  // 3. Deliver to customer
  await deliverCardsViaEmail(userId, orderId, orderStatus.cards);
  
  // 4. Log delivery
  await logCardDelivery(orderId, userId, 'email', orderStatus.cards.length);
  
  console.log(`✅ Order ${orderId} delivery complete`);
}

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 les champs value et serial des cartes 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 les cartes
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

Suppression sécurisée

Mettre en œuvre une politique de suppression des cartes si requis par la réglementation

É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é

Passer des commandes

Soumettre des commandes validées

Charger le catalogue

Récupérer les produits disponibles