Aller au contenu

Transferts

Refus avant l'envoi, échec chez l'opérateur ou limitation dans une boucle de payouts.

Un transfert envoie vos fonds vers l'extérieur. Il est donc plus strictement contrôlé qu'un paiement : clé autorisée, fréquence des appels et solde disponible. La plupart des problèmes de transfert proviennent du fonctionnement normal de l'un de ces trois contrôles.

Erreur 406 Private Key Required pour une clé publique

Vous avez envoyé une clé publique. Les payouts, le solde, les remboursements, les litiges, les bénéficiaires et les connexions Sync acceptent uniquement une clé privée.

RouteClé publiqueClé privée
/paymentsAcceptéeAcceptée
/transfers, /balance, /refunds, /disputes, /beneficiaries, /accounts406Acceptée

Notez le code. Il s'agit de 406, pas de 403. Une branche qui attend 403 pour détecter une mauvaise clé ne s'exécute jamais ici.

Erreur 403 This API key does not have permission to write transfer liée au scope

Vous avez envoyé une clé restreinte sans le scope nécessaire. Les payouts exigent transfer.write et les routes de lecture exigent transfer.read. Les scopes sont figés à la création de la clé. Pour les élargir, créez une nouvelle clé.

Le transfert a immédiatement échoué

Lisez failure_reason sur l'objet du transfert, pas reason : reason est le libellé que vous avez fourni. Trois codes couvrent la plupart des cas.

failure_reasonCauseAction
invalid_recipientLe bénéficiaire est absent ou n'a pas de canal de payoutCorrigez le bénéficiaire, puis créez un nouveau transfert
no_providerAucun prestataire n'est éligible pour ce canal et ce montant en ce momentRéessayez plus tard, ou payez sur un autre canal
provider_rejectedTous les prestataires éligibles ont refusé le payoutLisez failure_message, corrigez, puis créez-en un nouveau

Quand un prestataire refuse, vérifiez d'abord que le numéro appartient à l'opérateur du channel indiqué. Au Cameroun, un numéro qui commence par +23767 appartient à MTN et +23769 à Orange. Formats de numéros de téléphone contient le tableau des préfixes, et Motifs d'échec les autres codes.

Un solde trop faible pour le payout ne donne pas un transfert en échec : POST /transfers répond 422 avec error_code: insufficient_balance et rien n'est créé. Son message vaut Insufficient available balance for this payout. (and 1 more error) : la phrase figure sur amount et sur balance, et le suffixe compte la seconde. Le même suffixe termine un refus faute de prestataire et le numéro sandbox de fonds insuffisants. Comparez error_code, ou lisez errors, jamais le message entier. Le moment du règlement en est souvent la cause. Un encaissement succeeded n'est pas encore utilisable. Il devient disponible après le règlement. Votre solde contient une valeur available et une valeur pending. Un payout utilise uniquement available.

Je ne peux pas annuler un transfert

Il n'existe aucun endpoint d'annulation. POST /transfers crée le transfert. GET /transfers et GET /transfers/{id} le lisent. Une fois créé, le transfert passe à succeeded ou failed, ou à cancelled s'il est annulé avant d'être envoyé (à partir de la version d'API 2026-10-12, les versions antérieures le lisent failed). Un payout que l'opérateur annule de son côté finit failed.

Ce choix est volontaire. Un payout s'exécute sans intervention humaine. Une période d'annulation permettrait de reprendre les fonds après leur crédit au bénéficiaire. Validez avant d'envoyer.

Réponse 429 dans une boucle de payouts

Les payouts possèdent leur propre plafond en plus des quatre limites générales : 20 par minute, par équipe et par environnement, quel que soit votre plan, partagé par les payouts, les lots, les payouts Sync et la création de bénéficiaires. Une boucle sur une liste de bénéficiaires l'atteint bien avant le quota de l'équipe. Un payout live qui a attendu plus de dix secondes derrière un autre payout du compte répond aussi 429, avec error_code: payout_queue_busy et Retry-After : rien n'a été créé, renvoyez-le.

La réponse 429 de ce plafond ne contient pas le champ type présent avec les limites générales. Un handler qui lit toujours type échoue donc sur la réponse qu'il doit justement traiter.

Réponse de la limitation des payouts
{
"code": 429,
"status": "Too Many Requests",
"message": "Too Many requests. Merchant limit : 360",
"retry_after": 24
}

Espacez les appels, respectez retry_after et exécutez les lots de payouts en dehors des périodes où une personne peut en attendre un. Gestion des limites de requêtes présente cette stratégie.

Payer plusieurs personnes à la fois

POST /transfers/batch envoie jusqu'à 500 payouts en un seul appel, et ne compte qu'une fois dans le plafond de 20 par minute, quelle que soit sa taille. Il ne compte aussi qu'une fois dans le nombre horaire d'appels de payout de la vélocité, et un nouveau lot est refusé en entier avec 422 quand l'heure n'a plus de place. Chaque ligne ajoute son montant au montant horaire et échoue séparément : la réponse liste chaque ligne avec son status, et une ligne rejetée porte un message.

Après un délai expiré ou un échec partiel, renvoyez le lot entier avec la même Idempotency-Key. Seules les lignes qui ne sont pas passées partent, les autres reviennent telles qu'elles sont déjà, même quand l'heure n'a plus de place : seules les lignes encore à envoyer sont alors rejetées, avec le message de vélocité, et la même clé les enverra plus tard. Ne renvoyez jamais sous une nouvelle clé un lot dont vous n'êtes pas sûr qu'il a échoué : chaque ligne serait payée une seconde fois. Une ligne dont la reference a déjà servi pour un autre payout est rejetée au lieu d'être envoyée. Le Dashboard ne propose pas de téléversement CSV.

Le bénéficiaire affirme n'avoir rien reçu

Avant de suspecter le transfert, vérifiez ses données.

Interrogez le transfert, pas le bénéficiaire
curl https://api.wajub.com/transfers/po_9xh0XQ5wu2lxCSUGajfv \
  -H "Authorization: sk.xxxxxxxxxxxxxxxx…" \
  | jq '.transfer | { status, failure_reason, amount, currency, created_at }'

succeeded signifie que l'opérateur a confirmé le crédit. Les fonds se trouvent alors chez le bénéficiaire. La question doit lui être adressée ou transmise à son opérateur, pas à Wajub. processing signifie que le transfert est toujours en cours. En Mobile Money, il dure généralement moins de deux minutes, mais peut prendre plus de temps sur un réseau encombré.

Que pensez-vous de ce contenu ?