Skip to main content

Vue d’ensemble

Les paiements peuvent échouer pour diverses raisons. Ce guide vous aide à comprendre les erreurs courantes et comment les gérer dans votre application.

Statuts de paiement

Important : Seules les demandes de paiement (payment_requests) ont un statut. Les liens de paiement (payment_links) n’ont pas de statut. Les demandes de paiement peuvent avoir les statuts suivants :
  • pending : Le paiement est en attente de confirmation
  • success : Le paiement a été effectué avec succès
  • error : Le paiement a échoué
Pour les liens de paiement, utilisez le champ canReceivePayments (booléen) pour vérifier si le lien peut accepter de nouveaux paiements.

Erreurs communes

Lien expiré

Erreur : link_expired ou payment_link_expired Message : “Payment link has expired” Cause : Le lien de paiement a expiré et ne peut plus accepter de paiements. Solution :
  • Vérifiez toujours canReceivePayments avant de diriger un client vers un lien
  • Créez un nouveau lien de paiement si le lien a expiré
  • Informez le client que le lien a expiré et proposez de créer un nouveau lien
Exemple de gestion :
async function checkAndRedirectToPayment(paymentLinkId) {
  // Vérifier la disponibilité du lien
  const response = await fetch(
    `https://api.jeko.africa/partner_api/payment_links/${paymentLinkId}`,
    {
      headers: {
        'X-API-KEY': apiKey,
        'X-API-KEY-ID': apiKeyId
      }
    }
  );
  
  const paymentLink = await response.json();
  
  if (!paymentLink.canReceivePayments) {
    // Le lien a expiré ou a été utilisé
    if (paymentLink.allowMultiplePayments === false) {
      // Lien à usage unique - créer un nouveau lien
      const newLink = await createNewPaymentLink(paymentLink.storeId, paymentLink.amount);
      return newLink.link;
    } else {
      // Lien expiré - informer l'utilisateur
      throw new Error('Le lien de paiement a expiré. Veuillez créer un nouveau lien.');
    }
  }
  
  return paymentLink.link;
}

Lien déjà utilisé

Erreur : link_used ou payment_link_already_used Message : “Payment link has already been used” Cause : Le lien de paiement est à usage unique (allowMultiplePayments: false) et a déjà été utilisé pour un paiement réussi. Solution :
  • Vérifiez canReceivePayments avant de diriger un client vers un lien
  • Pour les liens à usage unique, créez un nouveau lien pour chaque paiement
  • Informez le client que le lien a déjà été utilisé
Exemple de gestion :
async function handlePaymentLink(paymentLinkId) {
  const paymentLink = await getPaymentLink(paymentLinkId);
  
  if (!paymentLink.canReceivePayments) {
    if (paymentLink.allowMultiplePayments === false) {
      // Lien à usage unique déjà utilisé
      // Créer un nouveau lien
      const newLink = await createPaymentLink({
        storeId: paymentLink.storeId,
        title: paymentLink.title,
        amountCents: paymentLink.amount.amount,
        currency: paymentLink.amount.currency,
        allowMultiplePayments: false
      });
      
      return {
        error: 'LINK_USED',
        message: 'Ce lien a déjà été utilisé. Un nouveau lien a été créé.',
        newLink: newLink.link
      };
    }
  }
  
  return { link: paymentLink.link };
}

Demande de paiement non trouvée (404 Not Found)

Erreur : payment_request_not_found Message : “Payment request not found” Cause : La demande de paiement n’existe pas ou n’appartient pas à votre entreprise. Solution :
  • Vérifiez que l’ID de la demande de paiement est correct
  • Vérifiez que la demande appartient à votre entreprise
  • Vérifiez que la demande n’a pas été supprimée

Magasin non trouvé (404 Not Found)

Erreur : store_not_found Message : “Store not found” Cause : Le storeId fourni n’existe pas ou n’appartient pas à votre entreprise. Solution :
  • Vérifiez que le storeId est correct
  • Utilisez l’endpoint /partner_api/stores pour lister vos magasins
  • Assurez-vous que le magasin existe et est actif

Dispositif non trouvé (422 Validation Error)

Erreur : validation_error Message : “The paymentDetails.data.deviceId field is required when paymentDetails.type is soundbox” Cause : Pour les paiements soundbox, le deviceId est requis mais manquant ou invalide. Solution :
  • Vérifiez que le deviceId est fourni pour les paiements soundbox
  • Vérifiez que le deviceId existe via l’endpoint /partner_api/devices
  • Assurez-vous que le dispositif est actif et associé au bon magasin

Erreur de validation (422 Unprocessable Entity)

Erreur : validation_error Message : “Validation error” Cause : Les données fournies ne respectent pas les règles de validation. Problèmes courants :
  • Montant inférieur au minimum (100 centimes pour payment_requests, 10000 centimes pour payment_links)
  • Code devise invalide (doit être ISO 4217, 3 caractères)
  • Référence manquante ou invalide (1-100 caractères)
  • Titre manquant ou invalide pour payment_links (10-255 caractères)
  • URLs de callback invalides (doivent être HTTPS valides)
  • Méthode de paiement invalide
Solution :
  • Vérifiez que tous les champs requis sont présents
  • Vérifiez que les valeurs respectent les contraintes (montant minimum, longueur, format)
  • Vérifiez que les URLs sont valides et utilisent HTTPS

Paiement échoué

Erreur : payment_failed ou transaction_failed Message : “Payment failed” Cause : Le paiement a échoué côté opérateur (Mobile Money ou banque). Solution :
  • Vérifiez que le client a suffisamment de fonds
  • Vérifiez que le compte du client est actif
  • Proposez au client de réessayer
  • Contactez le support si le problème persiste

Clé API invalide (401 Unauthorized)

Erreur : unauthorized Message : “Unauthorized” Cause : Les clés API sont invalides, manquantes ou expirées. Solution :
  • Vérifiez que les en-têtes X-API-KEY et X-API-KEY-ID sont présents
  • Vérifiez que les clés API sont correctes
  • Régénérez vos clés API depuis le Jeko Cockpit si nécessaire

Accès interdit (403 Forbidden)

Erreur : forbidden ou forbidden_action Message : “Forbidden” ou “Action interdite” Cause : La clé API n’a pas la permission d’accéder à cette ressource ou d’effectuer cette action. Solution :
  • Vérifiez les permissions de votre clé API
  • Contactez le support pour vérifier les permissions de votre compte

Conflit de référence (409 Conflict)

Erreur : payment_request_exists_with_reference Message : “Une demande de paiement avec cette référence existe déjà” Cause : Une demande de paiement avec la même référence existe déjà. Solution :
  • Utilisez des références uniques pour chaque demande de paiement
  • Incluez un identifiant unique (timestamp, UUID, orderId) dans la référence

Gestion des erreurs dans votre application

Vérification préventive

Avant de créer un paiement, effectuez ces vérifications :
  1. Vérifier l’existence du magasin :
curl -X GET "https://api.jeko.africa/partner_api/stores/{storeId}" \
  -H "X-API-KEY: your_api_key_here" \
  -H "X-API-KEY-ID: your_api_key_id_here"
  1. Pour les paiements soundbox, vérifier le dispositif :
curl -X GET "https://api.jeko.africa/partner_api/devices" \
  -H "X-API-KEY: your_api_key_here" \
  -H "X-API-KEY-ID: your_api_key_id_here"
  1. Pour les liens de paiement, vérifier la disponibilité :
curl -X GET "https://api.jeko.africa/partner_api/payment_links/{paymentLinkId}" \
  -H "X-API-KEY: your_api_key_here" \
  -H "X-API-KEY-ID: your_api_key_id_here"

Gestion des erreurs dans le code

async function createPaymentRequest(paymentData) {
  try {
    // Vérifications préventives
    await validateStore(paymentData.storeId);
    
    if (paymentData.type === 'soundbox') {
      await validateDevice(paymentData.deviceId);
    }
    
    // Créer la demande de paiement
    const response = await fetch('https://api.jeko.africa/partner_api/payment_requests', {
      method: 'POST',
      headers: {
        'X-API-KEY': apiKey,
        'X-API-KEY-ID': apiKeyId,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(paymentData)
    });
    
    if (!response.ok) {
      const error = await response.json();
      
      // Gérer les erreurs spécifiques
      switch (error.id) {
        case 'payment_request_exists_with_reference':
          throw new Error('Une demande avec cette référence existe déjà. Utilisez une référence unique.');
        case 'store_not_found':
          throw new Error('Magasin introuvable. Vérifiez le storeId.');
        case 'validation_error':
          throw new Error(`Erreur de validation: ${error.extras?.errors?.map(e => e.message).join(', ')}`);
        case 'unauthorized':
          throw new Error('Clés API invalides. Vérifiez vos identifiants.');
        default:
          throw new Error(`Erreur: ${error.message}`);
      }
    }
    
    return await response.json();
  } catch (error) {
    console.error('Erreur lors de la création du paiement:', error);
    throw error;
  }
}

async function handlePaymentLink(paymentLinkId) {
  try {
    // Vérifier la disponibilité du lien
    const response = await fetch(
      `https://api.jeko.africa/partner_api/payment_links/${paymentLinkId}`,
      {
        headers: {
          'X-API-KEY': apiKey,
          'X-API-KEY-ID': apiKeyId
        }
      }
    );
    
    if (!response.ok) {
      const error = await response.json();
      
      if (error.id === 'payment_link_not_found') {
        throw new Error('Lien de paiement introuvable.');
      }
      
      throw new Error(`Erreur: ${error.message}`);
    }
    
    const paymentLink = await response.json();
    
    if (!paymentLink.canReceivePayments) {
      if (paymentLink.allowMultiplePayments === false) {
        throw new Error('LINK_USED', 'Ce lien a déjà été utilisé.');
      } else {
        throw new Error('LINK_EXPIRED', 'Ce lien a expiré.');
      }
    }
    
    return paymentLink.link;
  } catch (error) {
    console.error('Erreur lors de la vérification du lien:', error);
    throw error;
  }
}

Utilisation des webhooks pour le suivi

Configurez des webhooks pour être notifié automatiquement des changements de statut des paiements. Cela vous permet de :
  • Suivre les paiements en temps réel
  • Gérer les échecs automatiquement
  • Mettre à jour votre système lorsque le statut change
Consultez la documentation Webhooks pour plus d’informations.

Bonnes pratiques

  1. Vérifications préventives : Toujours vérifier les prérequis avant de créer un paiement
  2. Gestion d’erreurs robuste : Implémentez une gestion d’erreurs complète pour tous les cas d’échec
  3. Logging : Enregistrez toutes les erreurs pour le débogage et l’analyse
  4. Messages utilisateur : Informez l’utilisateur des erreurs de manière claire et actionnable
  5. Retry logic : Pour les erreurs temporaires, implémentez une logique de réessai avec backoff exponentiel
  6. Monitoring : Surveillez les taux d’échec pour identifier les problèmes récurrents
  7. Vérification des liens : Toujours vérifier canReceivePayments avant de diriger un client vers un lien

Support

Si vous rencontrez des erreurs persistantes ou des problèmes non documentés, contactez le support JEKO à hello@jeko.africa.