Remboursements
Rendre tout ou partie d'un encaissement, et suivre ce qui a déjà été rendu.
Créer un remboursement
/v1/refundsVise une transaction succeeded. Omettez amount pour rembourser la totalité du reste dû.
orange est refusée en 422 avec NGP002 (« Orange Money ne supporte pas les remboursements automatiques ») : le remboursement est enregistré en failed et le montant réservé est rendu, refunded_amount_xof ne bouge pas. Pour rembourser un client Orange Money, faites la demande au support NguePay, qui la traite manuellement. Seuls les paiements par carte (stripe) se remboursent par API pour l'instant.| Champ | Type | Requis | Description |
|---|---|---|---|
transaction_uuid | uuid | ✅ | La transaction à rembourser. |
amount | entier | ❌ | XOF entiers. Omis = remboursement total. |
reason | chaîne (≤ 255) | ❌ | Votre motif, enregistré et renvoyé tel quel dans le reason de la réponse (espaces de début et de fin retirés). Omis ou vide : NguePay pose requested_by_merchant. |
Ajoutez l'en-tête Idempotency-Key si votre client HTTP peut rejouer l'appel : la même clé sur la même transaction rend le remboursement déjà enregistré au lieu d'en créer un second, et l'opérateur n'est sollicité qu'une fois par clé. La même clé avec un autre montant est refusée en 422 : ce n'est pas un rejeu. Voir Idempotence & rejeu.
curl -X POST https://api.live.nguepay.com/api/v1/refunds \
-H "Authorization: Bearer sk_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{
"transaction_uuid": "9f1c0c2e-2b4a-4f0d-9a1b-6d2f7c3e4a55",
"amount": 5000,
"reason": "Article indisponible"
}'{
"success": true,
"data": {
"uuid": "b17e3a44-9c21-4f77-8a0e-1d5c2b9f3e10",
"status": "succeeded",
"amount_xof": 5000,
"reason": "Article indisponible",
"failure_reason": null,
"processed_at": "2026-09-17T22:14:03.000000Z",
"created_at": "2026-09-17T22:14:01.000000Z",
"transaction": {
"uuid": "9f1c0c2e-2b4a-4f0d-9a1b-6d2f7c3e4a55",
"reference": "cmd_10452",
"provider_code": "stripe"
}
},
"message": "Remboursement effectué."
}| Champ | Type | Description |
|---|---|---|
uuid | uuid | Identifiant du remboursement — le refund_id du webhook refund.succeeded. |
status | chaîne | Voir Statuts. |
amount_xof | entier | Montant remboursé en XOF entiers. Pas de champ amount en centimes sur cet objet. |
reason | chaîne | null | Le motif que vous avez envoyé, tel quel ; sans motif, requested_by_merchant ; pour un remboursement fait depuis la console Stripe, stripe_charge_refunded. |
failure_reason | chaîne | null | Motif du refus, en failed. |
processed_at | date | null | Exécution par l'opérateur ; null tant qu'elle n'est pas confirmée. |
created_at | date | Création. |
transaction | objet | { uuid, reference, provider_code } de la transaction remboursée. |
Réponse 201. Le message vaut Remboursement effectué., ou Remboursement en cours de traitement. quand l'opérateur confirme plus tard (status: processing). GET /refunds (liste data.refunds) et GET /refunds/{uuid} renvoient le même objet.
Ce qui change sur la transaction
La transaction reste en succeeded : il n'existe pas de statut « remboursé ». Ce qui bouge, c'est refunded_amount_xof, le cumul déjà rendu. Pour savoir si une commande est intégralement remboursée, comparez ce cumul à amount_xof.
Ce choix évite une ambiguïté coûteuse : un remboursement partiel ne doit pas faire disparaître le fait que l'argent a été encaissé, ni fausser votre chiffre d'affaires.
Raccourci par transaction
curl -X POST https://api.live.nguepay.com/api/v1/transactions/{uuid}/refund \
-H "Authorization: Bearer sk_live_VOTRE_CLE" \
-H "Content-Type: application/json" \
-d '{"amount": 5000, "reason": "Geste commercial"}'200), avec son nouveau refunded_amount_xof. Pour obtenir l'uuid du remboursement dès la réponse, utilisez POST /refunds.Statuts
| Statut | Signification |
|---|---|
pending | Transmis à l'opérateur, en cours. |
processing | Accepté par l'opérateur, exécution pas encore confirmée. Le montant reste réservé. |
succeeded | L'argent est reparti chez le client. |
failed | Refusé ; failure_reason précise pourquoi. |
L'événement refund.succeeded est envoyé à toutes vos destinations webhook abonnées. Comme pour un paiement, c'est lui qui fait foi.
Limites
- On ne rembourse pas plus que ce qui reste dû sur la transaction — y compris les remboursements lancés depuis la console de l'opérateur, qui sont décomptés dès que son webhook nous les apprend. Pour Stripe, chaque remboursement est suivi individuellement, avec son propre montant.
- Une transaction
pendingoufailedne se rembourse pas — elle s'annule. - Les délais de restitution dépendent de l'opérateur, pas de NguePay.
- Orange Money : pas de remboursement par API (refus
NGP002, montant rendu) — demande manuelle au support.