Aller au contenu principal
Tous les articles
Produit13 min de lecture

Rembourser un client : en totalité ou en partie, depuis le portail ou par l'API

Rembourser un client en totalité ou en partie, depuis le portail ou par l'API : refundReference, statuts, effet sur le solde, export et message au client.

Rembourser un client se fait depuis le portail ChariPay ou par l'API, en totalité ou partiellement : vous désignez le paiement d'origine et le montant à rendre, et ce montant est déduit de votre solde disponible. Le remboursement est gratuit. Par l'API, une refundReference dérivée de la commande garantit qu'un même remboursement ne part jamais deux fois, même si votre code rejoue l'appel. Et si le client n'a pas encore payé, il n'y a rien à rembourser : on annule le lien ou la session. Ce guide couvre les deux situations, le suivi par webhook, l'effet sur le solde et sur le versement suivant, la ligne dans l'export et le message à envoyer au client.

Annuler avant le paiement, rembourser après

ChariPay est une plateforme de paiement marocaine, un PSP opéré par Chari Money, établissement de paiement agréé par Bank Al-Maghrib. Avant de chercher comment rembourser, posez-vous une seule question : l'argent a-t-il déjà bougé ? Tant que le client n'a pas payé, il n'y a rien à rendre — il faut seulement l'empêcher de payer. Une fois un paiement par carte réussi, le remboursement est le seul geste possible.

SituationLe bon gesteCe qui se passe
Lien de paiement envoyé, pas encore payéAnnuler le lien — par l'API, POST /v1/payment-links/{reference}/cancelLe lien passe « annulé » ; un lien annulé ne peut plus être payé
Session de paiement créée, pas encore payéeAnnuler la session — POST /v1/payment-sessions/{sessionId}/cancelLa session est annulée ; sans cet appel, elle expire d'elle-même, 72 heures par défaut ou à son expiresAt
Paiement par carte réussiRembourser, en totalité ou partiellementLe montant est déduit de votre solde disponible ; le retour côté banque n'est pas instantané

L'annulation est le geste le plus propre : aucun mouvement, aucune ligne à rapprocher. Annulez un lien dès qu'il ne correspond plus à la commande — rupture de stock, client qui se rétracte, erreur de montant — plutôt que de le laisser vivre jusqu'à son expiration : un client pressé pourrait encore le payer.

Si vous vendez sur Shopify ou WooCommerce, la façon de refléter le remboursement dans la plateforme elle-même est traitée dans encaisser sur Shopify au Maroc et encaisser sur WooCommerce au Maroc. Ce guide traite le remboursement côté ChariPay, quel que soit l'outil de vente.

Rembourser un client depuis le portail

Le portail permet de rembourser un client en totalité ou partiellement, sans une ligne de code. Ce n'est pas un geste que tout le monde peut faire, et c'est voulu : les rôles du portail séparent la consultation de l'action. Le propriétaire ou un gestionnaire habilité déclenche les opérations sortantes, dont les remboursements ; le caissier encaisse sans voir le solde ni les virements, et ne rembourse pas ; le comptable lit tout sans rien déclencher. Une demande faite au comptoir remonte donc au gestionnaire.

Avant de valider, quatre décisions vous reviennent :

  1. 1Le paiement concerné. Identifiez-le parmi vos transactions, et vérifiez le montant payé et le client.
  2. 2Total ou partiel. Rendez-vous tout, ou seulement une partie ? La réponse dépend de votre politique de retour et de ce qui a été livré.
  3. 3Le montant. Pour un remboursement partiel, calculez-le avant de commencer : article manquant, prestation non réalisée, geste commercial.
  4. 4La raison. Consignez-la dans votre propre suivi : votre comptable, et parfois votre client, vous la demanderont plus tard.

Le montant est ensuite déduit de votre solde disponible. Les rôles font le tri en amont ; en aval, le journal d'audit est chaîné cryptographiquement : l'historique ne peut pas être réécrit.

Rembourser par l'API avec une refundReference déterministe

Par l'API, un remboursement tient en un appel : POST /v1/refunds, avec l'identifiant du paiement d'origine, votre référence de remboursement et un motif.

bash
curl -X POST 'https://api-psp.charipay.ma/v1/refunds' \
  -H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
  -H 'Content-Type: application/json' \
  -d '{
    "operationId": 8123,
    "refundReference": "refund-ORD-2026-0421-1",
    "refundAmount": 100.00,
    "reason": "CUSTOMER_CANCELLATION",
    "note": "Article retourne"
  }'

Champ par champ :

  • `operationId` identifie le paiement à rembourser. Lisez-le dans GET /v1/transactions ou GET /v1/transactions/{operationId}. À défaut, externalId accepte la valeur de votre orderId pour un paiement de session — attention, ce n'est pas l'externalId que vous avez envoyé à la création de la session. Le guide relier un paiement à sa commande montre où chaque identifiant revient.
  • `refundReference` (64 caractères au plus) est votre référence, déterministe, construite à partir du numéro de commande, comme refund-ORD-2026-0421-1. C'est la clé d'idempotence : la création répond 202 Accepted, un rejeu de la même référence renvoie le remboursement existant en 200, sans débiter une seconde fois — jamais de 201. Le principe est détaillé dans l'idempotence des paiements.
  • `refundAmount` fixe le montant d'un remboursement partiel ; absent, le remboursement est total.
  • `reason` prend une valeur d'énumération : MERCHANT_CANCELLATION, CUSTOMER_CANCELLATION, PLATFORM_ORCHESTRATION ou OTHER. Un texte libre y est refusé : il va dans `note`, 128 caractères au plus. metadata accepte en plus vos propres clés.

La référence complète des trois endpoints — création, lecture, liste — est dans le module « Remboursements » de la documentation.

Ce circuit se répète sans risque en sandbox : Commencer en mode test. Trois champs (nom, e-mail professionnel, entreprise), un lien d'activation reçu par e-mail pour choisir votre mot de passe, puis le portail, où vous créez vous-même votre clé de test. Payez une commande avec la carte de test, remboursez-la par l'API, rejouez l'appel pour voir le 200 : aucun argent réel ne circule, et la vérification de votre entreprise (KYB) ne conditionne que le passage en production.

Remboursement partiel ou total : refundAmount décide

Le remboursement partiel n'est pas une opération à part : c'est le même appel, avec un champ en plus. Sans refundAmount, vous rendez la totalité du paiement ; avec refundAmount, vous rendez ce montant-là, en dirhams et en unités majeures (100.00 = 100,00 MAD).

Exemple : la commande ORD-2026-0421 a été payée 250,00 MAD et le client renvoie un article à 100,00 MAD. C'est l'appel ci-dessus : "refundAmount": 100.00, le motif CUSTOMER_CANCELLATION et la note "Article retourne". Le client garde le reste de sa commande, et votre système sait exactement ce qui a été rendu, et pourquoi.

SituationrefundAmountreason conseillénote
Vous annulez avant expédition (rupture de stock)absent : totalMERCHANT_CANCELLATION« Rupture de stock »
Le client renonce avant la livraisonabsent : totalCUSTOMER_CANCELLATION« Annulation client »
Le client renvoie un articlemontant de l'articleCUSTOMER_CANCELLATION« Article retourné »
Article manquant dans le colismontant de l'articleMERCHANT_CANCELLATION« Article manquant »
Prestation réalisée en partiepart non réaliséeselon qui renoncedescription courte
Geste commercial après un retardmontant du gesteOTHER« Geste commercial »

La règle d'or : décidez du montant exact avant l'appel, avec la personne qui connaît la commande. Votre refundReference, votre note et votre refundAmount doivent raconter la même histoire.

Suivre un remboursement : statut et événements

La réponse 202 Accepted dit que la demande est enregistrée, pas que l'argent est revenu au client : un remboursement n'est pas instantané côté banque. Pour connaître l'issue, deux voies complémentaires :

  • Les événements de webhook. refund.succeeded quand le remboursement a abouti, refund.failed s'il a échoué. Si votre endpoint déclare une liste enabledEvents explicite, ajoutez-y ces deux événements — une liste vide reçoit tous les événements. Routez sur l'en-tête Chari-Event-Type et dédupliquez sur Chari-Event-Id.
  • La lecture directe. GET /v1/refunds/{reference} renvoie un remboursement à partir de votre refundReference (ou de l'identifiant attribué par la plateforme), et GET /v1/refunds liste vos remboursements, du plus récent au plus ancien.

Dans votre système, la commande passe « remboursée » à réception de refund.succeeded, pas au moment de l'appel. Entre les deux, affichez « remboursement en cours » : c'est l'état réel. Si un remboursement n'aboutit pas, vérifiez d'abord votre solde disponible — s'il ne suffit pas, l'opération est bloquée — puis contactez l'équipe si la cause n'est pas évidente.

Sans développeur, le portail suffit : chaque mouvement du compte, remboursement compris, y porte la référence de la vente, du remboursement ou du versement qui l'explique.

L'effet sur votre solde et sur le versement suivant

Rembourser un client est gratuit : aucun frais de remboursement ne s'ajoute, comme l'indique la page tarification. Le montant remboursé est déduit de votre solde disponible.

ChariPay n'est pas une banque : votre compte de paiement est tenu par Chari Money. Il complète votre banque, il ne la remplace pas. Il n'a ni découvert ni crédit : si le solde disponible ne suffit pas à couvrir le remboursement, l'opération est bloquée plutôt que de créer un découvert. Deux réflexes en découlent :

  • Avant un remboursement important, regardez votre solde disponible — dans le portail, ou par GET /v1/wallet.
  • S'il ne couvre pas le montant, attendez de nouveaux encaissements ou alimentez le compte par POST /v1/wallet/cash-ins, avec un en-tête Idempotency-Key obligatoire.

Le versement vers votre banque est une opération distincte : automatique chaque nuit dès qu'un compte de règlement est configuré dans le portail, ou par virement à la demande, et chaque versement porte une référence qui figure sur votre relevé bancaire. Un remboursement peut réduire le versement suivant, sans ligne séparée sur le relevé bancaire : vous y verrez un versement plus faible, pas une ligne « remboursement ». L'explication se trouve dans l'export du compte, pas dans le relevé. Le calendrier complet, du paiement réussi à votre banque, est dans délai de versement d'un paiement en ligne.

La ligne de remboursement dans l'export

Un remboursement n'efface pas une vente : il la suit. Dans l'export, chaque remboursement est un mouvement distinct, lié à la transaction d'origine et porteur de la référence du remboursement. Le portail distingue montant payé, frais et net, et l'export CSV reprend ces références — depuis le portail ou par GET /v1/transactions/export.csv, jusqu'à 10 000 lignes ; au-delà, découpez par période avec from et to.

Pour votre comptable, cela donne deux écritures datées : la vente, puis le remboursement. Trois réflexes rendent ce suivi simple :

  1. 1Gardez la `refundReference` dans votre système de commande : c'est elle qui relie la ligne d'export au dossier du client.
  2. 2Rapprochez le versement plus faible avec l'export de la même période, pas avec la vente remboursée.
  3. 3Convertissez les horodatages : ils sont en UTC, et le Maroc est en UTC+1. Un remboursement fait juste après minuit, heure marocaine, est daté de la veille dans l'export.

La méthode complète — écarts entre encaissé et versé, remboursements, fuseau horaire — est dans rapprocher ses encaissements.

Prévenir le client : le message à envoyer

Un remboursement que le client ne comprend pas devient un appel au service client. Envoyez un message court au moment où vous lancez l'opération, avec ce qu'il doit savoir et rien de plus :

Bonjour Amine, nous avons lancé le remboursement de 100,00 MAD sur votre commande ORD-2026-0421 (remboursement partiel : article retourné). Un remboursement n'est pas instantané côté banque : le montant vous reviendra selon le traitement de votre banque. Notre référence : refund-ORD-2026-0421-1. Nous ne vous demanderons jamais vos données de carte.

Ce que le message doit contenir : le montant, la référence de commande, la nature du remboursement (total ou partiel), la phrase sur le délai bancaire sans aucun chiffre — vous n'en maîtrisez pas la durée — et votre référence de remboursement, que le client pourra citer. Ce qu'il ne doit jamais contenir : une demande de numéro de carte, de code ou de RIB « pour accélérer ». Un remboursement se rattache au paiement d'origine et n'en a pas besoin ; un client habitué à ce que vous ne demandiez rien repère plus vite une escroquerie à votre nom.

Si votre outil le permet, un second message, plus court, quand refund.succeeded arrive, ferme la boucle. Pour la relation client en ligne au sens large — confirmations, reçus, politique de retour —, voyez le guide du paiement e-commerce au Maroc.

Questions fréquentes

Combien coûte un remboursement ?

Rien : rembourser un client est gratuit, en totalité ou partiellement, depuis le portail comme par l'API. Aucun frais de remboursement ne s'ajoute au montant rendu ; ce montant est simplement déduit de votre solde disponible. Le mode test, lui aussi gratuit et sans limite de durée, vous permet de dérouler un remboursement complet, du paiement à l'export, avant de servir de vrais clients.

Peut-on faire un remboursement partiel ?

Oui. Par l'API, ajoutez refundAmount avec le montant à rendre, en dirhams et en unités majeures ; sans ce champ, le remboursement est total. Depuis le portail, vous choisissez de la même façon entre la totalité et un montant partiel. Cas typiques : un article manquant, une prestation réalisée en partie, un geste commercial. Calculez le montant exact avant de lancer l'opération.

Que se passe-t-il si le solde ne suffit pas pour rembourser ?

L'opération est bloquée plutôt que de créer un découvert : le compte de paiement n'a ni découvert ni crédit. Vérifiez votre solde disponible dans le portail ou par GET /v1/wallet, puis attendez de nouveaux encaissements ou alimentez le compte par POST /v1/wallet/cash-ins. Entre-temps, prévenez le client que son remboursement est en préparation plutôt que de le laisser sans nouvelles.

Quand le client voit-il l'argent revenir sur sa carte ?

Un remboursement n'est pas instantané côté banque, et nous ne publions aucun délai : le retour dépend du traitement par la banque du client. De votre côté, l'événement refund.succeeded, ou la lecture par GET /v1/refunds/{reference}, vous dit que le remboursement a abouti. Dites au client que l'opération est lancée, donnez-lui votre référence, et ne promettez pas de date.

Qui peut rembourser un client dans le portail ?

Le propriétaire ou un gestionnaire habilité : ce sont eux qui déclenchent les opérations sortantes. Le caissier encaisse sans voir le solde ni les virements, et ne rembourse pas ; le comptable lit tout sans rien déclencher. Une demande reçue au comptoir remonte donc au gestionnaire. Par l'API, l'appel part avec votre clé d'API, un secret qui ne quitte jamais votre serveur.

Faut-il rembourser ou annuler un lien de paiement non payé ?

Annuler. Tant que le lien n'est pas payé, il n'y a rien à rembourser : annulez-le, et un lien annulé ne peut plus être payé. Par l'API, l'appel est POST /v1/payment-links/{reference}/cancel. Même logique pour une session de paiement non payée, avec POST /v1/payment-sessions/{sessionId}/cancel. Le remboursement ne concerne que les paiements réussis ; des deux gestes, lui seul fait bouger votre solde.

Le remboursement apparaît-il sur mon relevé bancaire ?

Pas comme une ligne séparée. Le versement vers votre banque est une opération distincte, avec sa propre référence sur votre relevé ; un remboursement peut réduire le versement suivant, sans ligne séparée sur le relevé bancaire. Le détail se lit dans l'export de votre compte de paiement, où chaque remboursement est un mouvement distinct, lié à la transaction d'origine et porteur de la référence du remboursement.

Quel motif indiquer dans un remboursement par l'API ?

Le champ reason n'accepte qu'une valeur d'énumération : MERCHANT_CANCELLATION quand vous annulez, CUSTOMER_CANCELLATION quand le client renonce, OTHER pour un autre motif ; la liste compte aussi PLATFORM_ORCHESTRATION. Un texte libre y est refusé. Mettez vos explications dans note, jusqu'à 128 caractères — « Article manquant », « Geste commercial » — et gardez la même formulation dans votre propre système.

Prochaine étape

Créez votre compte de test — Commencer en mode test — puis payez une commande avec la carte de test, remboursez-la partiellement par l'API, attendez refund.succeeded et retrouvez la ligne dans l'export. Le module « Remboursements » de la documentation détaille les trois endpoints, et relier un paiement à sa commande vous aide à retrouver l'operationId de chaque paiement.

Écrit par Équipe ChariPay.

À lire ensuite

Guide5 min de lecture

Rapprocher ses encaissements avec sa comptabilité

Rapprocher ses encaissements avec sa comptabilité : les trois écarts entre montant encaissé et versement en banque, et la méthode quotidienne qui tombe juste.

Guide14 min de lecture

Encaisser sur Shopify au Maroc

Boutique Shopify, clients marocains : accepter la carte 3-D Secure et les espèces en agence, par lien de paiement puis checkout par l'API, sans plugin.

Prêt à essayer par vous-même ?

Créez votre compte et encaissez en mode test dès aujourd'hui : c'est gratuit, sans validation à attendre. Une question ? Notre équipe répond aux commerçants comme aux développeurs.

  • Gratuit, sans engagement
  • Mode test dès l'inscription
  • Aucune validation à attendre