Remboursements
Restituer des fonds sur un paiement réussi, puis suivre le remboursement jusqu'à son propre résultat.
Un remboursement restitue tout ou partie d'un paiement réussi, et vous pouvez cumuler plusieurs remboursements partiels jusqu'à épuisement du montant d'origine. C'est un objet à part entière, avec son propre id, son propre statut et ses propres webhooks.
Les remboursements exigent la clé secrète
POST /refunds exige une clé secrète. Un appel qui porte une clé publique
est refusé avec 406 Not Acceptable et le message Private Key Required. Cet endpoint a sa place
sur votre serveur, jamais dans un navigateur ni dans une application mobile.
Deux pages vont plus loin :
- Créer un remboursement, l'appel, ses paramètres et sa réponse.
- Suivre un remboursement, ses webhooks, pourquoi un remboursement échoue, comment tester un échec, et la liste des remboursements.
Ce qui peut être remboursé
Cinq conditions sont vérifiées avant l'enregistrement d'un remboursement, et chacune échoue avec
son propre 422.
| Condition | Ce que vous recevez en cas d'échec |
|---|---|
Le paiement est succeeded | Transaction must be completed to be refunded. Current status: … |
| Aucune rétrofacturation n'est ouverte sur le paiement | Transaction cannot be refunded while a chargeback is open: the payer's bank may return the funds itself. It can be refunded again once the dispute is decided. |
| Il reste un montant remboursable | Transaction has already been fully refunded., ou Transaction has already been fully refunded or charged back. quand une rétrofacturation perdue a pris ce qui restait |
| Le montant tient dans ce qui reste | Refund amount exceeds refundable amount (…) |
| La devise correspond à celle du paiement | Refunds must be in the transaction currency (XAF). |
Le montant remboursable est le montant du paiement moins tout ce qui a déjà été remboursé, en
comptant les remboursements encore pending ou processing comme ceux qui ont réussi, et moins les
rétrofacturations que vous avez perdues sur ce paiement : la banque du payeur lui a déjà rendu cet
argent.
Une rétrofacturation est un litige que le payeur a ouvert auprès de sa banque : les litiges dont
metadata.source vaut provider_webhook. Tant qu'elle est open ou under_review, la banque peut
rendre l'argent elle-même, alors aucun remboursement de ce paiement n'est accepté jusqu'à ce que le
litige soit tranché. Un litige que le payeur a ouvert depuis Pocket ne bloque aucun remboursement.
Un remboursement ne peut pas convertir une devise
currency est accepté, mais la seule valeur possible est la devise du paiement lui-même. Le champ
existe pour que vous puissiez être explicite, pas pour rembourser en XOF un paiement en XAF. Si
vous l'omettez, Wajub utilise de toute façon la devise du paiement.
Le remboursement a son propre cycle de vie
Cinq états, dont trois terminaux. Un remboursement ne revient jamais à un état précédent.
Le délai ne dépend pas de Wajub. Sur une carte, c'est l'émetteur qui décide, et plusieurs jours sont normaux. Sur Mobile Money, le crédit arrive généralement en quelques minutes, parfois en quelques heures. Rien dans votre intégration n'y change quoi que ce soit : annoncez au client une fourchette plutôt qu'une heure précise.
Un remboursement ne démarre pas dans le même état selon l'environnement
En production, un remboursement est créé pending et passe à processing quand il est envoyé.
En sandbox, il est créé directement en processing et se résout en quelques secondes. Écrivez votre handler sur les états terminaux et vous
ne verrez pas la différence ; si vous testez pending, vos tests en sandbox n'entreront jamais dans
cette branche.
Qui envoie un remboursement live
En production, un remboursement est envoyé de l'une de trois façons. execution_mode sur le
remboursement dit laquelle, une fois que Wajub l'a planifié, et manual_reason dit pourquoi quand il
n'est pas envoyé automatiquement.
execution_mode | Qui l'envoie |
|---|---|
automatic | Wajub, sur le numéro mobile money du payeur, en quelques minutes |
merchant | Vous : le paiement a été encaissé sur votre propre compte prestataire, depuis lequel Wajub ne peut pas rembourser |
manual | Le support Wajub |
manual_reason est un objet avec un code stable sur lequel brancher votre logique et un message
que vous pouvez afficher.
code | Signification |
|---|---|
refund_from_your_provider | Encaissé sur votre propre compte prestataire : remboursez-le là-bas. Il se met à jour ici quand le prestataire confirme |
card_or_bank_payment | Les remboursements automatiques couvrent le mobile money. Le support Wajub envoie celui-ci |
insufficient_balance | Votre solde ne couvrait pas le remboursement au moment de l'envoyer |
payer_number_missing | Le numéro mobile money du payeur n'est pas connu |
requested_over_24h | Demandé il y a plus d'un jour : le support Wajub l'envoie |
outcome_being_confirmed | Envoyé, et la réponse de l'opérateur n'est pas encore définitive |
automatic_attempt_failed | L'opérateur l'a refusé et aucun argent n'est parti : le support Wajub le traite |
wajub_review | Le support Wajub le traite |
execution_mode et manual_reason peuvent changer sans que le statut change ; chaque changement
envoie refund.updated avec le remboursement tel qu'il est désormais. Dans tous les cas, le
remboursement se termine succeeded ou failed. Les remboursements sandbox n'ont aucun des deux
champs.
Ce que dit le statut du paiement
Un paiement affiche partially_refunded dès que des remboursements réussis couvrent une partie
de son montant, et refunded dès qu'ils le couvrent en entier. Un remboursement pending,
processing ou failed ne change rien.
Le statut est une lecture, et rien d'autre ne bouge avec lui : aucun événement de paiement n'est
émis, et le paiement n'est pas modifié par ailleurs. Pour savoir ce qui reste remboursable, listez
les remboursements du paiement et additionnez ceux qui sont pending, processing ou succeeded.
https://api.wajub.com/payments/{id}/refundsSoustrayez ce total, et le montant des rétrofacturations que vous avez perdues sur le paiement, du montant du paiement et vous obtenez ce qui reste remboursable, c'est-à-dire exactement le chiffre que l'API vérifie quand vous envoyez le remboursement suivant. Gérer les remboursements le fait en code.
Filtrer les paiements remboursés
GET /payments?status=refunded et ?status=partially_refunded listent ces paiements, et
?status=succeeded les laisse de côté.
Qui supporte les frais
Wajub garde les frais d'un paiement que vous remboursez. Ce que vous décidez, c'est qui les
supporte au final, pour la part des frais qui correspond au montant remboursé : vous, ou le client.
C'est fees_bearer.
| Les frais ont été payés par | fees_bearer: merchant | fees_bearer: customer |
|---|---|---|
Vous (bearer: merchant sur le paiement) | Le client récupère le montant. Les frais que vous avez payés ne vous sont pas rendus | La part des frais est déduite de ce que le client récupère, et vous êtes débité d'autant en moins |
Le client, en plus (bearer: customer) | Le client récupère le montant et la part des frais, et vous êtes débité des deux | Le client récupère le montant, pas les frais |
Sans ce champ, les frais restent à celui qui les a payés : c'est la première et la dernière case du
tableau. Pour changer cela pour tous
les remboursements, réglez-le une fois dans Paramètres, Remboursements ; fees_bearer sur un
remboursement prend le dessus.
Le remboursement vous dit ce qui a été appliqué : fee_amount est la part des frais, et
payer_amount ce que le client reçoit. Votre solde est débité de payer_amount, ni plus ni moins.
Un remboursement partiel prend la même proportion des frais, et le remboursement qui solde le
paiement prend ce qu'il en reste : les parts s'additionnent exactement. Dans une devise sans
subdivision, comme le XAF, une part est un nombre entier, et payer_amount aussi.
Un paiement encaissé sur votre propre compte prestataire est différent. Wajub ne détient rien de
son argent : votre solde n'est pas débité, vous envoyez le remboursement vous-même depuis ce
prestataire, et le montant à envoyer est payer_amount. Avec bearer: merchant, Wajub n'a facturé
aucuns frais sur ce paiement : fee_amount vaut 0 et payer_amount est égal à amount. Avec
bearer: customer, le payeur a payé les frais en plus à votre prestataire, et le tableau ci-dessus
s'applique.
L'argent bouge au succès, pas à la création
Créer un remboursement réserve le montant sur ce qui est remboursable, mais ne touche à aucun solde.
Le débit a lieu quand le remboursement atteint succeeded, et seulement à ce moment-là, pour
payer_amount : le montant, plus ou moins la part des frais.
Deux conséquences à anticiper. En sandbox, un remboursement réussi débite votre solde sandbox du montant remboursé, comme un remboursement live débite votre solde. Un remboursement qui rembourse un litige que vous avez accepté le débite même s'il échoue, puisque le litige est perdu dans tous les cas. Et un remboursement émis sur un paiement déjà perdu dans un litige est plafonné au montant principal qui n'a pas déjà été repris : le même argent ne peut pas sortir deux fois par deux portes différentes.
Ce que devient ensuite le solde, et comment se comporte un solde négatif, est expliqué dans Solde et règlements.
Dans le Dashboard
Un remboursement peut être émis sans écrire de code. Ouvrez un paiement dans Paiements, utilisez
son action de remboursement, et le résultat est le même objet que celui que crée l'API. Le
formulaire demande qui supporte les frais quand le paiement en portait, et affiche ce que le client
recevra. L'action
exige la permission refund_payments, distincte de manage_payments : un membre de l'équipe peut
ainsi gérer les commandes sans pouvoir rendre de l'argent.
Remboursements les liste tous avec leur statut, et les exporte en CSV ou Excel en production.
Les remboursements que les payeurs demandent depuis Pocket se trouvent dans Litiges, comme une étape à part : voir Demandes de remboursement.
Demandes de remboursement
Un payeur qui utilise Pocket peut vous demander le remboursement d'un paiement qu'il a effectué, avec un montant et un motif. La demande apparaît dans la liste Litiges du Dashboard, comme une étape à part, et attend que vous l'approuviez ou la refusiez. Rien n'est remboursé avant l'approbation, et l'approbation crée le remboursement exactement comme le ferait l'API. Les membres qui gèrent les paiements reçoivent un e-mail à l'arrivée d'une demande.
La demande est l'étape amiable. Si elle ne règle pas le problème, le payeur peut la faire passer en litige :
| Votre réponse | Quand le payeur peut passer en litige |
|---|---|
| Aucune pour l'instant | À partir de 7 jours après la demande. Deux jours avant, les membres qui gèrent les paiements reçoivent un rappel par e-mail |
| Un refus | Pendant 30 jours après votre réponse. Passé ce délai, la demande est close |
| Une approbation | Jamais, l'argent a été rendu |
Tant qu'une rétrofacturation est open ou under_review sur le paiement, c'est la banque du payeur
qui décide. Une demande ne peut être ni approuvée ni passée en litige, et le payeur ne peut pas en
envoyer une nouvelle. Ses délais cessent de courir et aucun rappel n'est envoyé. Une fois que la
banque a tranché, ils reprennent là où ils en étaient : le jour où le payeur peut passer en litige,
et la fin des 30 jours après un refus, arrivent plus tard, du temps qu'a duré la rétrofacturation.
Pages associées
- Gérer les remboursementsLe parcours complet, rapprochement compris.
- LitigesQuand l'argent est repris plutôt que rendu.
- Solde et règlementsOù arrive un remboursement une fois qu'il a réussi.
- Cycle de vie d'un paiementPourquoi le paiement reste succeeded pendant tout ce temps.
- Mode sandboxLes numéros et cartes de test, et ce que chacun déclenche.
- Référence API des remboursementsTous les champs de la ressource, et les trois endpoints.