Aller au contenu

Paiements

Statut pending bloqué, échec sans motif, double débit ou erreur 404 sur un identifiant valide.

Sept symptômes couvrent presque toutes les questions liées aux paiements. Repérez le vôtre et lisez la cause avant la solution. Trois d'entre eux proviennent de la même incompréhension.

Le paiement reste pending sans évolution

Un paiement Mobile Money attend une personne. Wajub a interrogé l'opérateur, qui a envoyé une demande sur un téléphone. Tant que personne ne saisit son code PIN, aucun résultat n'est disponible. pending n'est pas un état bloqué, mais un état d'attente.

Effectuez les vérifications suivantes dans cet ordre.

VérificationMéthode
Le payeur a-t-il ouvert la page ?authorization_url est à usage unique et expire avec le paiement
La demande est-elle arrivée ?L'opérateur l'envoie, pas Wajub. La page hébergée affiche le code USSD en solution de repli
Le paiement est-il simplement trop récent ?En période de pointe, les opérateurs peuvent mettre une minute à envoyer la demande

Le paiement ne reste pas indéfiniment pending. Il expire automatiquement et passe à expired.

Un paiement qui dure 30 minutes au lieu d'une journée
curl https://api.wajub.com/payments \
  -H "Authorization: sk_test.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "currency": "XAF",
    "email": "buyer@example.com",
    "expires": { "in": 30 }
  }'

Le champ imbriqué est expires.in et sa valeur s'exprime en minutes, de 5 à 43200, soit 30 jours. La valeur par défaut est 1440. Écrire expires_in au premier niveau ne produit aucun effet. La valeur est ignorée et le délai reste fixé à 24 heures.

Le paiement a échoué sans motif visible

L'objet contient reason, un code stable que votre programme peut traiter. Le message lisible qui l'accompagne provient du prestataire et peut changer sans préavis.

Lisez le motif, pas le message
curl https://api.wajub.com/payments/trx_test_CSUGajfv9xh0XQ5wu2lx \
  -H "Authorization: sk_test.kZ3qP8mWvL2xR7tB5nY4hC6dF9jS1aG0eU3i…" \
  | jq '.transaction | { status, reason, channel, amount }'

Motifs d'échec répertorie chaque code et précise ceux qu'une nouvelle tentative peut résoudre. En résumé, le payeur doit corriger insufficient_funds, wrong_pin et authorization_timeout. channel_unavailable et operator_declined justifient une nouvelle tentative. invalid_number et fraud_blocked échoueront toujours tant que la situation ne change pas.

Mon appel a expiré et j'ignore si le paiement existe

Cette situation est dangereuse, car les deux résultats sont possibles et un seul permet d'agir sans risque. Par défaut, le SDK abandonne après 30 secondes et lève une erreur de connexion. Cette erreur n'indique pas ce que le serveur a effectué.

Ne créez pas un second paiement pour le vérifier. Renvoyez la même requête avec la même Idempotency-Key. Wajub renvoie le paiement initial s'il existe ou le crée dans le cas contraire.

Une nouvelle tentative sans risque de double débit
const payment = await wajub.payments.create(params, {
  idempotencyKey: `ORDER-${order.id}`,
});

Sans cette clé, la nouvelle tentative provoque un second débit. Idempotence explique comment construire une clé qui survit au redémarrage de votre processus.

Le client a été débité deux fois

Ce problème provient presque toujours de l'une de deux causes.

La première est une nouvelle tentative sans clé d'idempotence, présentée ci-dessus. La seconde vient de l'idée que reference évite les doublons. Ce n'est pas le cas. reference est une chaîne libre sans règle d'unicité. Envoyer deux fois la même valeur crée deux paiements qui débitent tous les deux.

Si le problème s'est déjà produit, remboursez le doublon au lieu de l'annuler. Un paiement succeeded ne peut plus être annulé, seulement remboursé. Consultez Remboursements.

GET /payments/{something} renvoie 404 pour mon identifiant

Il existe trois causes, de la plus fréquente à la plus rare.

Vous avez transmis votre propre référence. L'endpoint accepte uniquement l'uid Wajub. Un paiement créé avec "reference": "ORDER-4172" n'est pas accessible depuis /payments/ORDER-4172 et répond avec 404 Payment Not Found. Enregistrez le champ id de la réponse de création avec votre commande, puis utilisez-le pour la recherche.

Valeur à conserver et valeur à ne pas utiliser pour la recherche
{
"code": 201,
"status": "Created",
"message": "Payment initiated",
"authorization_url": "https://pay.wajub.com/…",
"transaction": {
"id": "trx_test_CSUGajfv9xh0XQ5wu2lx",
"reference": "ORDER-4172"
}
}

id permet de retrouver le paiement. reference vous appartient et sert à vos propres recherches.

Vous utilisez le mauvais environnement. Une clé de la sandbox ne voit aucun paiement live, et inversement. Les bases sont distinctes. La réponse est donc 404, pas une erreur d'autorisation. Le préfixe test_ de l'identifiant indique l'environnement concerné.

Le paiement appartient à une autre équipe. Les identifiants ne passent pas d'une équipe à l'autre. La réponse reste volontairement 404 plutôt que 403.

Le montant est refusé avec une réponse 422

Trois règles s'appliquent. Les utilisateurs provenant d'une autre plateforme rencontrent souvent la première.

Les montants utilisent les unités principales. 5000 signifie cinq mille francs, pas cinquante. Aucun centime ne doit être converti. XAF et XOF ne possèdent aucune sous-unité.

Chaque devise possède des limites. Le serveur les applique et la réponse 422 indique le champ concerné. Lisez errors.amount au lieu de deviner. Pour XAF et XOF, le minimum est faible et le maximum assez élevé. Vous les rencontrerez généralement après avoir envoyé une valeur dans la mauvaise unité.

Le Mobile Money possède son propre plafond sans refuser le paiement. Au-dessus de 500 000 XAF ou XOF, la page hébergée encaisse le montant par tranches plutôt qu'en un seul débit. Le paiement reste dans partial tant qu'une partie seulement est encaissée. Il passe à succeeded après la dernière tranche. Considérez partial comme « pas encore payé », jamais comme un signal de livraison partielle.

Tout fonctionne dans la sandbox, mais rien en live

Deux causes sont possibles.

Vos clés live peuvent exister alors que votre compte n'est pas encore activé. Les paiements live exigent la validation du KYC. Passer en live contient la checklist.

Vous utilisez peut-être aussi des numéros de test de la sandbox auprès de vrais opérateurs. Dans la sandbox, les six derniers chiffres du numéro déterminent le résultat. En live, ils identifient une personne. +237670000002 provoque un échec dans la sandbox, mais appartient à quelqu'un en production.

Suffixe de la sandboxRésultat
000000Réussite
000001Échec avec insufficient_funds
000002Échec
000003Délai expiré
000004Annulé par le payeur
000009Paiement réussi, mais tous ses remboursements échouent

Que pensez-vous de ce contenu ?