Il existe un endpoint qui renvoie tout l'historique des remboursements App Store d'un client, et voici ce qu'il retourne
L'endpoint Get Refund History d'Apple renvoie l'historique complet des remboursements App Store d'un client sous forme de transactions signées. Voici chaque champ, comment le jeton revision pagine, pourquoi il fonctionne par client et non par app, et ce que vous coûte un remboursement que vous manquez.

Points clés
- Get Refund History est un endpoint de l'App Store Server API qui renvoie les achats intégrés remboursés d'un client pour votre app sous forme de liste de transactions signées, pour que vous puissiez rapprocher les remboursements et révoquer l'accès même quand une notification ne vous est jamais parvenue.
- Vous appelez GET /inApps/v2/refund/lookup/{transactionId} avec n'importe quel id de transaction de ce client, et Apple renvoie ses remboursements pour tous les types d'achat de votre app, pas seulement celui que vous avez demandé.
- La réponse comporte trois champs : signedTransactions, jusqu'à 20 transactions JWS par page triées du remboursement le plus ancien en premier, plus un jeton revision et un booléen hasMore pour la pagination.
- Conservez le jeton revision final. Renvoyez-le la prochaine fois et Apple ne renvoie que les remboursements plus récents que ce point, ce qui transforme un vidage complet de l'historique en une courte liste de nouvelles lignes à chaque exécution.
- Chaque transaction décodée porte revocationDate et revocationReason. Un revocationReason de 1 signifie que le client a été remboursé pour un problème réel ou perçu dans votre app, et 0 signifie une autre raison, comme un achat accidentel.
- L'endpoint fonctionne par client, pas par app. Il n'existe aucun appel unique qui liste tous les remboursements de toute votre app, vous rapprochez donc par compte à partir d'un id de transaction, ou vous lisez votre flux de notifications REFUND pour la vue à l'échelle de l'app.
- La raison de le mettre en place, c'est l'argent. Un remboursement que vous ne détectez jamais garde un compte actif, et vous continuez à payer le calcul, les appels à l'API du modèle, le stockage et les reversements pour un client qu'App Store a déjà remboursé.
Apple conserve un enregistrement interrogeable de chaque remboursement qu'elle a accordé sur le compte d'un client pour votre app, et un seul appel le renvoie. L'endpoint s'appelle Get Refund History, il fait partie de l'App Store Server API, et il vous remet l'historique complet des remboursements App Store de ce client sous forme de liste de transactions signées. Vous passez un id de transaction, vous récupérez ce qu'Apple a remboursé, et vous le rapprochez de ce que vous avez encore activé.
Voici pourquoi cela en vaut la peine. Un remboursement que vous ne voyez jamais est un remboursement que vous continuez à payer. L'argent est déjà parti, mais le compte reste actif, et chaque heure où il l'est, vous continuez à dépenser en calcul, appels à l'API du modèle, stockage et tout reversement lié à ce client. Vos notifications de remboursement sont censées attraper cela dès que ça se produit. Get Refund History est le filet de sécurité pour quand elles échouent, après une panne, un déploiement qui a perdu un webhook, ou un cas de support où vous avez besoin de la vue d'ensemble en un seul appel.
Ce que renvoie l'endpoint d'historique des remboursements App Store
Vous appelez GET /inApps/v2/refund/lookup/{transactionId} sur l'App Store Server API, signé avec le même JWT que vous utilisez pour tous les autres appels. L'id de transaction dans le chemin peut être n'importe quelle transaction du client. Apple le lit comme une identité, pas comme un filtre, et renvoie les achats remboursés de ce client dans toute votre app : consommables, non consommables, abonnements à renouvellement automatique et non renouvelables sans distinction. L'ancienne V1 de cet endpoint renvoyait jusqu'à 50 remboursements en une seule réponse et est obsolète. La version actuelle pagine, vous gérez donc les clients aux longs historiques sans une charge géante.
La réponse comporte trois champs
| Champ | Ce qu'il contient |
|---|---|
| signedTransactions | Jusqu'à 20 transactions remboursées pour ce client, chacune un JWS signé que vous vérifiez et décodez. Triées du remboursement le plus ancien en premier, par revocationDate. Un tableau vide signifie que le client n'a aucun remboursement dans votre app |
| revision | Un jeton de pagination. Renvoyez-le pour obtenir la page suivante, et conservez le dernier pour ne récupérer que les nouveaux remboursements la prochaine fois |
| hasMore | Vrai quand Apple détient plus de transactions remboursées que cette page n'en a renvoyé, vous rappelez donc avec le revision |
Ce qu'une transaction remboursée vous apprend
Chaque entrée de signedTransactions est un JWS. Vérifiez-le contre la chaîne de certificats d'Apple, décodez-le, et vous avez une charge utile de transaction ordinaire avec les champs de remboursement renseignés. Ce sont ceux qui comptent ici.
| Champ | Ce qu'il vous apprend |
|---|---|
| transactionId | L'id de la transaction remboursée, votre clé de jointure vers l'achat que vous avez enregistré |
| originalTransactionId | L'id du premier achat de la chaîne, comment vous reliez les renouvellements d'un abonnement |
| productId | Le produit qui a été remboursé, pour que vous révoquiez le bon droit et rien d'autre |
| revocationDate | L'heure UNIX, en millisecondes, à laquelle Apple a remboursé la transaction |
| revocationReason | Pourquoi Apple l'a remboursé. 1 signifie un problème réel ou perçu avec votre app, 0 signifie une autre raison, comme un achat accidentel |
| price, currency | Le montant, en milliunits, et son code de devise ISO 4217, pour que vous puissiez totaliser l'argent rendu |
| appAccountToken | L'UUID que vous avez attaché à l'achat, le moyen le plus propre de rattacher un remboursement à votre propre utilisateur |
Le jeton revision est ce qui vous évite de relire toute la liste
La façon naïve d'utiliser cet endpoint est de rechercher un client et de parcourir chaque page à chaque fois. Ça marche, et sur un client avec cinquante remboursements, ce sont cinquante lignes que vous connaissiez déjà plus la seule nouvelle. Le jeton revision existe pour éliminer ce gaspillage. Chaque réponse porte un revision. Quand hasMore est vrai, vous le renvoyez pour obtenir la page suivante. Quand vous atteignez la fin, vous conservez le dernier revision que vous avez vu.
Ce que cet endpoint ne fera pas
Il y a une attente à abandonner avant de construire dessus. Get Refund History fonctionne par client, pas par app. Vous ne pouvez pas lui demander tous les remboursements que votre app a subis la semaine dernière. Il répond à une question, quels remboursements ce compte a-t-il, et vous devez arriver avec un id de transaction de ce compte pour la poser. Les développeurs se heurtent à ce mur en permanence et partent chercher un endpoint de remboursements à l'échelle de l'app qui n'existe pas.
La vue à l'échelle de l'app se trouve ailleurs. Votre flux App Store Server Notifications envoie une notification REFUND au moment où Apple accorde chacune, et Get Notification History vous permet de rejouer ce flux filtré sur les types de remboursement sur une plage de dates. La division est donc nette. Les notifications et leur historique vous donnent le flux à l'échelle de l'app. Get Refund History vous donne la liste faisant autorité d'un compte, à la demande, ce qui est ce que vous voulez à un guichet de support ou après une panne.

Ce qu'un remboursement manqué vous coûte en argent
L'endpoint, c'est la plomberie. La facture est la raison pour laquelle vous posez le tuyau. Chaque remboursement de cette liste est de l'argent déjà rendu, et la seule variable qui reste sous votre contrôle est combien de temps vous continuez à dépenser sur un compte qui ne paie plus.
Vous continuez à payer pour servir un compte remboursé
Le prix d'achat est parti à l'instant où Apple accorde le remboursement. Ce qui continue de tourner, c'est le coût de la livraison. Pour une app qui fait un vrai travail par utilisateur, c'est le calcul, les appels à l'API du modèle, le stockage et tout reversement à un créateur ou un partenaire lié à son usage. Un client remboursé dont vous ne coupez jamais l'accès est un abonnement que vous financez de votre poche. Rapprocher avec Get Refund History et révoquer selon ce que vous trouvez, c'est ainsi que vous coupez ce compteur quand une notification est passée à travers.
Une raison de remboursement de 1 est un rapport de défaut déguisé
revocationReason vous coûte deux fois si vous l'ignorez. Le premier coût est le remboursement lui-même. Le second est chaque remboursement futur dû à la même cause. Quand un produit revient sans cesse avec revocationReason 1, un problème réel ou perçu dans votre app, Apple vous remet un échantillon étiqueté de ce qui pousse les clients à demander leur argent. Suivez la tendance par produit et vous pourrez colmater la fuite au lieu de la payer un remboursement à la fois.
Le détecter tard vaut quand même mieux que de ne pas le détecter
Une rétrofacturation est définitive avec la banque et, sur l'autre store, elle entraîne désormais des frais que le développeur absorbe. Un remboursement App Store, ce n'est pas cela. Il est réglé, mais le droit vous appartient, à révoquer dès que vous le savez. Donc même un remboursement que vous trouvez avec des jours de retard via cet endpoint vaut la peine d'être trouvé. Vous ne pouvez pas récupérer l'argent, mais vous pouvez arrêter la dépense qui tournait encore derrière.
Comment cela s'articule avec les notifications, et avec Google
Voyez les pièces comme un seul système. La notification REFUND est le signal en direct, poussé vers votre serveur au fur et à mesure qu'Apple décide. Get Refund History est la source de vérité en mode pull pour un seul client, l'appel que vous faites quand le push a échoué ou quand une personne a besoin du compte complet sous les yeux. Du côté de Google Play, la forme est la même idée avec des noms différents : une VoidedPurchaseNotification est poussée en temps réel, et la Voided Purchases API est la liste que vous tirez. Les deux stores vous donnent un flux et un registre. L'erreur est de ne se fier qu'au flux, car les flux tombent.
La mise en place à la manière de RefundHalt
La boucle est courte une fois chaque pièce en place. Prenez une notification REFUND comme déclencheur. Rapprochez avec Get Refund History pour qu'un webhook perdu ne laisse jamais un compte remboursé actif. Décodez chaque transaction, rattachez-la par appAccountToken ou transactionId à votre utilisateur, lisez revocationReason pour qu'un remboursement dû à un défaut soit signalé et pas seulement classé, et révoquez le droit exact plutôt que tout le compte. Paginez avec le jeton revision pour lire les nouveaux remboursements, pas les anciens.
C'est la partie que RefundHalt exécute pour vous. Il écoute les notifications de remboursement, se rabat sur Get Refund History quand il lui faut la liste faisant autorité, vérifie chaque transaction signée, révoque l'achat précis, et conserve le revision pour que chaque passage ne lise que ce qui a changé. Vous obtenez l'accès coupé en quelques secondes et un enregistrement propre de qui a été remboursé, pour quoi et pourquoi, sans avoir à monter vous-même le polling et la vérification JWS.
Questions fréquentes
- Comment voir tous les remboursements de toute mon app, et pas seulement d'un client ?
- Vous ne pouvez pas avec Get Refund History, car il fonctionne par client et a besoin d'un id de transaction du compte concerné. Pour la vue à l'échelle de l'app, utilisez votre flux App Store Server Notifications, qui envoie une notification REFUND pour chaque remboursement au moment où Apple l'accorde, et Get Notification History pour rejouer ce flux filtré sur les types de remboursement sur une plage de dates.
- Combien de remboursements l'endpoint Get Refund History renvoie-t-il ?
- La version actuelle renvoie jusqu'à 20 transactions remboursées par page, triées du remboursement le plus ancien en premier, et pagine le reste avec un jeton revision quand hasMore est vrai. L'endpoint V1 obsolète renvoyait jusqu'à 50 en une seule réponse. Il n'y a pas de plafond sur le total, un client avec un long historique s'étale simplement sur plus de pages.
- À quoi sert le jeton revision ?
- C'est ainsi que vous paginez et que vous évitez de relire tout l'historique d'un client à chaque fois. Chaque réponse inclut un revision. Vous le renvoyez pour récupérer la page suivante, et vous conservez le dernier afin que votre prochaine recherche ne renvoie que les remboursements plus récents que ce point. Cela réduit un rapprochement planifié à une courte liste de nouvelles lignes.
- Que signifie revocationReason dans une transaction remboursée ?
- C'est la raison pour laquelle Apple a remboursé la transaction. Une valeur de 1 signifie que le client a été remboursé à cause d'un problème réel ou perçu dans votre app, et 0 signifie une autre raison, comme un achat accidentel. revocationDate vous dit quand le remboursement a eu lieu, en millisecondes UNIX. Lire revocationReason vous permet de distinguer un défaut de produit d'un remboursement ponctuel de regret.
- En ai-je encore besoin si je gère déjà les notifications REFUND ?
- Oui, comme filet de sécurité. Les notifications sont le signal en direct, mais un push peut échouer à arriver pendant une panne, un mauvais déploiement ou un changement de webhook, et un remboursement manqué laisse un compte remboursé actif et vous coûtant de l'argent. Get Refund History est la source de vérité en mode pull avec laquelle vous rapprochez pour que rien ne reste activé qu'Apple a déjà remboursé.
Sources et lectures complémentaires
- Apple Developer: Get Refund History (App Store Server API)
- Apple Developer: RefundHistoryResponse
- Apple Developer: JWSTransactionDecodedPayload (revocationDate, revocationReason)
- Apple Developer: Get Refund History V1 (deprecated)
- Apple Developer: App Store Server Notifications V2 notificationType (REFUND)
- Apple Developer: Support customers and handle refunds (WWDC21)
RefundHalt
Le pilote automatique des remboursements pour l'App Store et Google Play
Poursuivre la lecture
Votre app peut afficher une feuille de demande de remboursement dans l'app, et voici ce qu'Apple fait après que le client a touché envoyer
La demande de remboursement dans l'app d'Apple permet à un client de demander un remboursement sans quitter votre app, sur une feuille qu'Apple construit et examine. Voici ce que renvoie beginRefundRequest, les horloges du CONSUMPTION_REQUEST et des 48 heures qu'elle déclenche sur votre serveur, et si le bouton vaut la peine d'être publié.
Quand un achat Google Play est remboursé ou fait l'objet d'une rétrofacturation, la Voided Purchases API est votre moyen de le savoir
Google Play annule un achat en silence lorsqu'il est remboursé ou fait l'objet d'une rétrofacturation. La Voided Purchases API est la liste de ces commandes, afin que vous puissiez révoquer l'accès. Voici chaque champ, la fenêtre de 30 jours, l'option de révocation qui masque des commandes et ce que cela coûte.