Jèko
Paiements

API direct (encaissement direct fournisseur)

Envoyer le payeur droit chez son opérateur, sans passer par la page de paiement hébergée par Jèko

L'API direct est une variante du paiement en ligne. Au lieu de renvoyer le payeur vers la page de paiement hébergée par Jèko, elle appelle son opérateur dès la création de la demande.

Ce que vous y gagnez dépend du réseau, et c'est la première chose à savoir : sur Orange, Wave et Djamo, vous récupérez l'URL de l'opérateur au lieu de celle de Jèko, et le payeur revient sur vos pages plutôt que sur les nôtres. Sur MTN et Moov, l'opérateur pousse une demande de code sur le téléphone du payeur et il n'y a plus de page à ouvrir du tout.

Pour plus de détails : Create payment request (Partner API)

Quand la choisir

Le flux hébergé reste le choix par défaut. Il pose lui-même au payeur la question du moyen de paiement, et il vous évite d'avoir à traiter un redirectUrl qui ne veut pas dire la même chose selon le réseau.

L'API direct a du sens dans deux cas :

  • Vous voulez maîtriser l'écran de paiement et vous connaissez déjà le moyen de paiement choisi. Le payeur passe directement chez l'opérateur, puis revient sur vos pages.
  • Vous encaissez sur MTN ou Moov et vous connaissez le numéro du payeur. L'opérateur l'appelle en USSD, et il n'y a aucune page à ouvrir.

Si vous ne connaissez pas le moyen de paiement avant de créer la demande, restez sur le paiement en ligne.

Activer le mode direct

L'API direct utilise le même endpoint et le même type que le paiement en ligne, avec paymentDetails.type: "redirect". Deux champs de paymentDetails.data s'y ajoutent.

  • forceProviderDirect : true pour activer ce mode. Omis ou false, vous obtenez le flux hébergé standard.
  • payerPhone : numéro mobile ivoirien du payeur, indicatif 225 obligatoire (+225 ou 225), suivi de 01, 05 ou 07 puis huit chiffres. +2250765432108 et 2250765432108 sont valides, 0765432108 est refusé. Obligatoire dès que forceProviderDirect vaut true.

Tous les autres champs sont ceux du paiement en ligne : storeId, amountCents, currency, reference, paymentMethod, successUrl et errorUrl.

Comment ça marche

La création se déroule en deux temps :

  1. Jèko crée la demande de paiement, comme pour un paiement en ligne classique.
  2. Jèko appelle immédiatement l'opérateur, en lui transmettant vos successUrl et errorUrl.

C'est le second appel qui distingue l'API direct, et il a trois conséquences que vous devez traiter, détaillées plus bas : le contenu de redirectUrl dépend de l'opérateur, vos URLs de retour remplacent la page Jèko comme point d'arrivée du payeur, et un échec de cet appel consomme votre référence.

Exemple de requête

curl -X POST "https://api.jeko.africa/partner_api/payment_requests" \
  -H "X-API-KEY: your_api_key_here" \
  -H "X-API-KEY-ID: your_api_key_id_here" \
  -H "Content-Type: application/json" \
  -d '{
    "storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
    "amountCents": 10000,
    "currency": "XOF",
    "reference": "PAY-DIRECT-2024-001",
    "paymentDetails": {
      "type": "redirect",
      "data": {
        "paymentMethod": "orange",
        "forceProviderDirect": true,
        "payerPhone": "+2250765432108",
        "successUrl": "https://myapp.com/payment/success?reference=PAY-DIRECT-2024-001",
        "errorUrl": "https://myapp.com/payment/error?reference=PAY-DIRECT-2024-001"
      }
    }
  }'

Réponse réussie

{
  "id": "d22c81f3-ee04-4ec5-8bd2-cd8af5dabcfc",
  "storeId": "59ae202a-f583-4a15-970f-9e99bd1e0baa",
  "reference": "PAY-DIRECT-2024-001",
  "type": "redirect",
  "paymentMethod": "orange",
  "status": "pending",
  "redirectUrl": "https://webpay.orange.ci/...",
  "errorReason": null
}

La réponse a la même forme qu'en paiement en ligne. Seul le contenu de redirectUrl change, et il dépend de l'opérateur.

Le comportement dépend de l'opérateur

C'est le point le plus important de cette page. Les cinq moyens de paiement ne se comportent pas de la même façon en mode direct.

Moyen de paiementCe que contient redirectUrlLe numéro fourniCe que vous en faites
orangeL'URL webpay d'Orange Moneyenregistré, non utiliséRedirigez le payeur dessus
waveL'URL de paiement de Waveenregistré, non utiliséRedirigez le payeur dessus
djamoL'URL de paiement de Djamoenregistré, non utiliséRedirigez le payeur dessus
mtnLa page hébergée par Jèkoappelé en USSDVoir ci-dessous
moovLa page hébergée par Jèkoappelé en USSDVoir ci-dessous

MTN et Moov ne redirigent pas

Ces deux réseaux confirment le paiement par USSD : l'opérateur pousse une demande de code directement sur le téléphone du payeur, il n'y a pas de page à ouvrir. En mode direct, redirectUrl retombe donc sur le lien hébergé Jèko (), qui sert de page d'attente.

Ne construisez pas votre intégration en supposant que redirectUrl mène toujours à l'opérateur. Pour MTN et Moov, affichez plutôt votre propre écran d'attente et laissez le webhook vous annoncer le résultat.

Prévoyez aussi le cas où rien n'arrive. Si le payeur ne voit pas la demande de code ou ne la confirme pas, la demande reste pending et cesse d'être payable trente minutes après sa création.

Si l'appel à l'opérateur échoue

L'API répond 400 avec "id": "third_party_payment_provider_error" et un message générique, « An error occurred while processing your payment, please retry ». Rien dans cette réponse ne vous dit ce qui suit, et c'est pourtant l'essentiel.

La demande de paiement a déjà été créée et votre reference lui reste attachée, pour la traçabilité. Conséquence directe : rejouer le même appel avec la même référence renvoie un 409 payment_request_exists_with_reference. Ce n'est pas une erreur de votre code, c'est la demande de la tentative précédente.

Pour réessayer, générez une nouvelle référence. Une référence par tentative, pas une par commande.

La demande de la tentative échouée reste payable

Le premier temps a créé une demande avec son lien hébergé, et cet échec ne l'annule pas : le payeur peut encore la régler par ce lien pendant trente minutes. Si vous réessayez avec une nouvelle référence, vous avez donc deux demandes payables pour la même commande.

Tant que vous n'avez pas reçu de webhook sur la première, ne considérez pas la nouvelle tentative comme le seul encaissement possible, et réconciliez sur toutes les références essayées.

async function createDirectPayment(orderId, attempt = 1) {
  const reference = `ORDER-${orderId}-T${attempt}`;

  const response = await fetch('https://api.jeko.africa/partner_api/payment_requests', {
    method: 'POST',
    headers: {
      'X-API-KEY': process.env.JEKO_API_KEY,
      'X-API-KEY-ID': process.env.JEKO_API_KEY_ID,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      storeId: process.env.JEKO_STORE_ID,
      amountCents: 10000,
      currency: 'XOF',
      reference,
      paymentDetails: {
        type: 'redirect',
        data: {
          paymentMethod: 'orange',
          forceProviderDirect: true,
          payerPhone: '+2250765432108',
          successUrl: `https://myapp.com/payment/success?ref=${reference}`,
          errorUrl: `https://myapp.com/payment/error?ref=${reference}`
        }
      }
    })
  });

  if (!response.ok) {
    // Ne rejouez jamais avec la même référence : elle est déjà consommée.
    if (attempt < 3) return createDirectPayment(orderId, attempt + 1);
    throw new Error('Initialisation du paiement direct impossible');
  }

  return response.json();
}

Conservez la correspondance entre votre commande et chaque référence essayée. Le webhook vous renvoie la référence dans transactionDetails.reference, c'est elle qui vous permettra de réconcilier.

Les erreurs propres au mode direct

SituationRéponse
forceProviderDirect: true sans payerPhone422, payerPhone requis
payerPhone sans indicatif 225, par exemple 0765432108422, format invalide
L'appel à l'opérateur échoue400 third_party_payment_provider_error
Référence déjà utilisée par une tentative précédente409 payment_request_exists_with_reference

Un numéro dont le préfixe ne correspond pas au paymentMethod n'est pas rejeté par la validation : l'appel part, et c'est l'opérateur qui le refuse. Vous récupérez alors le 400 ci-dessus, avec la référence déjà consommée.

Le catalogue complet est dans Gérer les échecs.

Suivre le paiement

Rien ne change par rapport au paiement en ligne. La demande naît en pending, et le webhook reste la seule confirmation fiable.

Sur Orange, Wave et Djamo, vos successUrl et errorUrl sont transmises à l'opérateur, qui y ramène le payeur : c'est la différence avec le flux hébergé, où il revient sur la page Jèko. Mais une redirection n'est pas une preuve de paiement. Sur MTN et Moov, personne ne ramène le payeur nulle part, et le webhook est votre seul signal.

Et ensuite

On this page