Tous les articles
Deep dive8 min de lecture

Apple peut annuler un remboursement déjà accordé, et un remboursement annulé que votre serveur ignore bloque un client qui a payé

Lorsque l'App Store annule un remboursement déjà accordé, il attend de votre serveur qu'il rétablisse l'accès que vous aviez révoqué. Voici comment fonctionnent les notifications de remboursement, de remboursement refusé et de remboursement annulé sur l'App Store et Google Play, et ce que chacune coûte lorsque vous l'ignorez.

Un cadenas lumineux sur un téléphone à côté d'un relevé bancaire et d'une clé hors de portée, symbolisant un remboursement annulé qui bloque un client qui a payé

Points clés

  • L'App Store envoie une notification REFUND_REVERSED lorsqu'il annule un remboursement qu'il avait précédemment accordé parce que le client l'a contesté, et l'instruction d'Apple est explicite : si votre application a révoqué du contenu ou des services, elle doit les rétablir.
  • Une notification REFUND signifie que l'App Store a déjà remboursé la transaction, votre serveur doit donc révoquer le droit d'accès. Une notification REFUND_DECLINED signifie qu'Apple a refusé la demande, et le client conserve à la fois son accès et son paiement.
  • Si vous révoquez lors d'un remboursement mais ne gérez jamais l'annulation, un client dont le paiement est rétabli reste bloqué. Cela se traduit par un ticket d'assistance, un avis une étoile, et sur Google Play une frustration qui peut se transformer en rétrofacturation qui vous coûte désormais de l'argent.
  • Le revocationReason d'Apple vous indique pourquoi le remboursement a eu lieu : value 1 signifie qu'Apple a remboursé en raison d'un problème réel ou perçu dans votre application, value 0 signifie une autre raison, comme un achat accidentel.
  • Google Play n'a pas de notification d'annulation. Il envoie une VoidedPurchaseNotification lorsqu'un achat est annulé et une PendingRefundReviewNotification distincte pour les rétrofacturations, et vous rapprochez le reste avec le modèle pull de la Voided Purchases API.
  • Google Play vous accorde 24 heures pour répondre à une PendingRefundReviewNotification en appelant orders.reviewrefund, et il n'enregistre que votre premier appel. À partir du 3 août 2026, une rétrofacturation perdue coûte au développeur le prix moins les frais de service de Google, plus les frais de la banque.
  • Traitez les notifications de remboursement de l'App Store de manière idempotente. Les livraisons en double sont normales, associez donc chaque révocation et chaque rétablissement à l'id de transaction et faites d'une notification répétée une opération sans effet.

Un remboursement n'est pas toujours le dernier mot. L'App Store peut annuler un remboursement déjà accordé, après que le client l'a contesté, et lorsque ce remboursement annulé arrive sur votre serveur, il porte une seule instruction : rendez l'accès. La plupart des équipes câblent la simple notification REFUND, coupent l'accès au client et s'arrêtent là. Elles ne construisent jamais l'autre moitié. Ainsi, lorsque l'annulation arrive, rien ne s'exécute, et un client qui paie à nouveau reste bloqué et privé de ce qu'il a acheté. Voici comment fonctionne l'ensemble complet des notifications de remboursement sur l'App Store et Google Play, et ce que chacune vous coûte lorsque vous l'ignorez.

L'App Store envoie trois notifications de remboursement, pas une

La plupart des traitements de remboursement sont conçus pour un seul événement : l'argent est reparti, coupez l'accès au client. Le flux App Store Server Notifications V2 transporte en réalité trois résultats de remboursement distincts, et ils demandent trois choses différentes. Deux d'entre eux modifient ce à quoi un client peut accéder. L'un d'eux annule le premier. Voici l'ensemble complet, dans les propres mots d'Apple.

NotificationSignificationCe que fait votre serveur
CONSUMPTION_REQUESTLe client a demandé un remboursement et Apple veut des données de consommationEnvoyez la charge utile de consommation dans les 12 heures
REFUNDL'App Store a remboursé la transactionRévoquez le droit d'accès pour cette transaction
REFUND_DECLINEDL'App Store a refusé la demande de remboursementRien ; le client conserve l'accès et le paiement
REFUND_REVERSEDL'App Store a annulé un remboursement qu'il avait accordéRétablissez le contenu ou le service que vous avez révoqué

REFUND, celle que toutes les équipes gèrent

Lorsque l'App Store traite un remboursement, il envoie une notification REFUND à l'URL que vous configurez, et la définition d'Apple est claire : elle « indique que l'App Store a remboursé avec succès une transaction pour un In-App Purchase consommable, un In-App Purchase non consommable, un abonnement à renouvellement automatique ou un abonnement sans renouvellement ». Vous enregistrez la transaction remboursée, révoquez ce qu'elle a acheté, et Apple vous demande d'informer le client de ce qui a changé au moyen d'un message contextuel dans l'application. C'est la notification que tout le monde câble en premier, et souvent la seule.

REFUND_DECLINED, celle qui n'exige rien de vous

REFUND_DECLINED signifie exactement ce qu'elle dit : « l'App Store a refusé une demande de remboursement ». Le client a demandé, Apple a dit non, et la transaction demeure. Rien ne change concernant l'accès du client, votre logique de droits d'accès ne fait donc rien ici. La valeur de cette notification est comptable. Elle clôt une demande de remboursement à laquelle vous avez peut-être répondu par un CONSUMPTION_REQUEST, et elle confirme que le client dispose toujours de ce qu'il a payé. Traitez-la comme un enregistrement, pas comme une action.

REFUND_REVERSED, celle qui prend les équipes au dépourvu

C'est la notification que la plupart des pipelines de remboursement ne gèrent jamais. La définition d'Apple est sans ambiguïté : REFUND_REVERSED « indique que l'App Store a annulé un remboursement précédemment accordé en raison d'un litige soulevé par le client. Si votre application a révoqué du contenu ou des services à la suite du remboursement concerné, elle doit les rétablir ». Lisez cela deux fois. Apple a accordé un remboursement au client, vous avez révoqué l'accès, puis Apple a décidé que le remboursement ne devait pas tenir et l'a retiré. Le paiement est de nouveau actif. Le client a payé, et si votre serveur ne sait que révoquer, il reste bloqué. Un remboursement annulé est le seul événement de remboursement qui redonne l'accès, et c'est celui que presque personne ne prévoit.

Ce qu'un remboursement annulé vous coûte réellement

Une annulation manquée n'est pas une erreur d'arrondi. Suivez l'argent dans les deux sens, car se tromper sur l'une ou l'autre moitié a un prix.

Manquez l'annulation et vous laissez un client payant bloqué. Apple a rétabli le paiement, le client a donc de nouveau déboursé, et votre application lui refuse ce qu'il a acheté. Le coût immédiat, c'est le temps d'assistance et un remboursement commercial que vous devrez peut-être émettre vous-même, cette fois sans commission de la boutique pour l'atténuer. Le coût plus lent, c'est l'avis négatif et le désabonnement, et sur Google Play cette même frustration liée au blocage est précisément ce qui se transforme en rétrofacturation.

Manquez le remboursement initial et vous continuez à servir un client qui n'a rien payé. L'erreur miroir, c'est de ne jamais révoquer du tout. Un client remboursé qui continue de générer des images, d'appeler vos API et de remplir votre stockage accumule des coûts réels sur une vente qui a été annulée. Le calcul, les appels tiers et le stockage sont de l'argent que vous avez déjà dépensé, et rien de tout cela ne revient avec le remboursement.

  • Coût d'assistance : un humain répondant à un ticket concernant un accès que votre propre code a supprimé et jamais rétabli.
  • Remboursements commerciaux : rembourser de l'argent à un client que vous avez bloqué à tort, sans commission de la boutique restituée sur un geste manuel.
  • Dépenses gaspillées : calcul, appels d'API et stockage consommés par un compte remboursé que vous n'avez jamais coupé.
  • Risque de rétrofacturation : sur Google Play, un client qui se sent facturé deux fois peut contester, et un litige perdu retombe désormais sur vous.

Le remboursement annulé et le remboursement simple sont le même flux de webhook pointant dans des directions opposées. Gérez l'un et ignorez l'autre, et vous payez des deux côtés.

Une main ramenant un reçu papier sur un bureau, symbolisant un remboursement annulé qui défait un remboursement App Store sur lequel votre serveur a déjà agi

Pourquoi Apple annule un remboursement, et comment lire revocationReason

Une annulation n'est pas aléatoire. Apple la lie à « un litige soulevé par le client », c'est-à-dire le client contestant après coup la décision de remboursement. Lorsque le remboursement a été accordé pour la première fois, la transaction portait un revocationDate et un revocationReason, et cette raison mérite d'être lue avant que quoi que ce soit en aval n'agisse dessus.

  • revocationReason 1 : l'App Store a remboursé « en raison d'un problème réel ou perçu dans votre application ». C'est un signal concernant votre produit, pas seulement ce client.
  • revocationReason 0 : l'App Store a remboursé « pour d'autres raisons, par exemple un achat accidentel ». Aucun signal de qualité de l'application associé.

Lorsqu'un REFUND_REVERSED arrive pour cette transaction, la révocation est en train d'être défaite. Votre logique de rétablissement doit rechercher l'id de transaction d'origine, confirmer que vous l'avez révoqué, et remettre le droit d'accès exactement tel qu'il était.

Google Play n'envoie pas d'annulation, vous devez donc procéder à un rapprochement

Le modèle de Google Play est différent, et cette différence compte si vous faites passer les deux boutiques par un même gestionnaire de webhook. Il n'existe aucun équivalent Google de REFUND_REVERSED. Les notifications développeur en temps réel de Google répartissent les événements de remboursement en deux messages, et les annulations sont gérées par rapprochement, non par une notification push.

La notification d'achat annulé

Lorsqu'un achat Google Play est annulé, votre serveur reçoit une VoidedPurchaseNotification. Elle indique le purchaseToken et l'orderId, un productType d'abonnement ou d'achat unique, et un refundType qui est soit une annulation complète, soit un remboursement partiel basé sur la quantité pour les achats multi-quantités. Google affirme que ces données suffisent à trouver le bon achat et à ajuster le droit d'accès. Pour tout le reste, il vous oriente vers la Voided Purchases API, un modèle pull qui liste les commandes annulées dans une plage d'horodatage que vous interrogez.

L'examen de la rétrofacturation, et son délai de 24 heures

Les rétrofacturations arrivent par un message différent, la PendingRefundReviewNotification. Lorsqu'un client conteste un paiement auprès de sa banque, Google Play envoie cette notification et déclenche un compte à rebours. Vous disposez de 24 heures pour appeler orders.reviewrefund avec une préférence de remboursement et toute preuve d'utilisation, afin que Google puisse contester une rétrofacturation illégitime en votre nom. Google enregistre votre premier appel et ignore les suivants. C'est l'équivalent Google du CONSUMPTION_REQUEST d'Apple, la seule fenêtre où votre version d'un litige compte.

Comme il n'y a pas de notification push d'annulation, une rétrofacturation que Google conteste et gagne n'arrive pas sous la forme d'un événement de rétablissement soigné. Vous la rapprochez avec la Voided Purchases API et vos propres enregistrements. La leçon est la même que sur l'App Store : une commande annulée n'est pas toujours définitive, et l'état de vos droits d'accès doit pouvoir revenir en arrière, pas seulement avancer.

Événement de remboursementApp StoreGoogle Play
Remboursement accordéNotification REFUNDVoidedPurchaseNotification
Remboursement refuséNotification REFUND_DECLINEDAucun message distinct
Remboursement annuléNotification REFUND_REVERSEDAucune notification push ; rapprochement via la Voided Purchases API
Fenêtre de preuve de litigeCONSUMPTION_REQUEST, 12 heuresPendingRefundReviewNotification, 24 heures
Qui peut émettre le remboursementApple uniquementGoogle, ou vous depuis l'onglet Commandes

Comment traiter chaque notification de remboursement sans bloquer qui que ce soit

Vous n'avez pas besoin de pipelines distincts par boutique. Vous avez besoin d'un gestionnaire capable de déplacer un droit d'accès dans les deux sens et qui traite chaque message comme potentiellement dupliqué.

  • Construisez le rétablissement, pas seulement la révocation. Pour chaque chemin qui supprime l'accès sur un REFUND, écrivez l'inverse qui le restaure sur un REFUND_REVERSED, associé au même id de transaction.
  • Rendez-le idempotent. Les deux boutiques peuvent livrer la même notification plusieurs fois, associez donc chaque révocation et chaque rétablissement à l'id de transaction ou de commande et faites d'une répétition une opération sans effet.
  • Lisez la raison avant d'agir. Utilisez revocationReason pour distinguer un remboursement lié à la qualité de l'application d'un remboursement accidentel, et orientez ceux liés à la qualité vers la personne responsable de la qualité du produit.
  • Répondez aux fenêtres de preuve à temps. Envoyez les données de consommation d'Apple dans les 12 heures suivant un CONSUMPTION_REQUEST, et appelez orders.reviewrefund dans les 24 heures suivant une PendingRefundReviewNotification.
  • Conservez chaque événement. Gardez REFUND_DECLINED et les notifications brutes, afin qu'une annulation arrivant plus tard puisse être associée au remboursement qu'elle défait.

Rien de tout cela ne change le fait qu'un remboursement ait lieu. Cela change le fait que le client, de l'autre côté d'un remboursement annulé, remarque un jour que votre serveur s'est trompé.

Questions fréquentes

Qu'est-ce qu'une notification REFUND_REVERSED sur l'App Store ?
C'est l'App Store qui indique à votre serveur qu'il a annulé un remboursement précédemment accordé, parce que le client l'a contesté. L'instruction d'Apple est explicite : si votre application a révoqué du contenu ou des services à la suite de ce remboursement, elle doit les rétablir. Le paiement est de nouveau actif, le client doit donc récupérer son accès.
Que dois-je faire lorsque je reçois une notification REFUND_DECLINED ?
Rien concernant l'accès du client. REFUND_DECLINED signifie que l'App Store a refusé la demande de remboursement, la transaction demeure donc et le client conserve ce qu'il a payé. Traitez-la comme un enregistrement qui clôt la demande de remboursement, souvent une demande à laquelle vous avez répondu par un CONSUMPTION_REQUEST.
Google Play envoie-t-il une notification lorsqu'un remboursement ou une rétrofacturation est annulé ?
Non. Google Play n'a pas d'équivalent du REFUND_REVERSED d'Apple. Il envoie une VoidedPurchaseNotification lorsqu'un achat est annulé et une PendingRefundReviewNotification pour les rétrofacturations, mais une rétrofacturation contestée que Google gagne ne vous est pas renvoyée par notification push. Vous la rapprochez à l'aide de la Voided Purchases API et de vos propres enregistrements.
De combien de temps est-ce que je dispose pour répondre à une rétrofacturation Google Play ?
24 heures. Lorsque Google Play envoie une PendingRefundReviewNotification, vous disposez de 24 heures pour appeler orders.reviewrefund avec une préférence de remboursement et une preuve d'utilisation. Google n'enregistre que votre premier appel. À partir du 3 août 2026, une rétrofacturation perdue coûte au développeur le prix moins les frais de service de Google, plus les frais de la banque.
Que m'indique revocationReason sur une transaction App Store remboursée ?
Il vous indique pourquoi Apple a remboursé. Value 1 signifie qu'Apple a remboursé en raison d'un problème réel ou perçu dans votre application, ce qui est un signal produit. Value 0 signifie une autre raison, comme un achat accidentel. Le lire vous permet de distinguer les remboursements qui pointent vers un bug de ceux qui sont ordinaires.

Sources et lectures complémentaires

RefundHalt

Le pilote automatique des remboursements pour l'App Store et Google Play

Poursuivre la lecture

La prochaine demande de remboursement est déjà en route.

Configurez RefundHalt dans le temps qu'il vous faudrait pour lire un nouvel e-mail d'assistance au sujet d'un remboursement que vous n'avez pas pu contester.