Tous les articles
Deep dive8 min de lecture

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.

Un smartphone à côté d'un registre papier, un cadenas en laiton fermé et une pièce qui glisse au loin, illustrant la Voided Purchases API de Google Play qui signale les commandes remboursées et rétrofacturées

Points clés

  • La Voided Purchases API, la méthode purchases.voidedpurchases.list, renvoie les commandes que Google Play a annulées, remboursées ou rétrofacturées, afin que vous puissiez bâtir un système de révocation qui coupe l'accès à ce que le client ne possède plus.
  • Seules les commandes révoquées apparaissent. Un remboursement émis par le développeur sans l'option de révocation est invisible pour cette API, donc si vous voulez retirer l'accès, vous devez rembourser avec la révocation activée.
  • La fenêtre est de 30 jours. startTime ne peut pas être plus ancien que 30 jours en arrière, donc un serveur qui reste hors service plus d'un mois perd ces commandes annulées pour de bon. Interrogez selon un calendrier.
  • voidedSource vous indique qui a annulé la commande : 0 est l'utilisateur, 1 est le développeur, 2 est Google. voidedReason vous indique pourquoi, de 0 Other jusqu'à 7 Chargeback et 8 Unacknowledged_purchase.
  • Les Real-time developer notifications envoient une VoidedPurchaseNotification à l'instant où un achat est annulé, mais traitez-la comme un signal. Appelez la Voided Purchases API pour obtenir la liste officielle avant de révoquer.
  • Identifiez les renouvellements d'abonnement par orderId, pas par purchaseToken. Un seul purchaseToken couvre chaque renouvellement d'un abonnement, donc le token seul ne peut pas distinguer deux renouvellements.
  • Les quotas sont de 6 000 requêtes par jour et de 30 requêtes dans toute fenêtre de 30 secondes, donc parcourez les résultats avec le token de continuation et interrogez par fenêtre de temps, jamais un appel par commande.

Un remboursement sur Google Play ne frappe pas à votre porte. L'argent part, le client garde l'appli ouverte, et à moins que vous n'alliez chercher, rien ne change de votre côté. La Voided Purchases API est l'endroit où vous allez chercher. Elle vous remet une liste de commandes qui ont été annulées, remboursées ou rétrofacturées, afin que vous puissiez révoquer l'accès à ce que le client ne paie plus. Pointez une tâche planifiée dessus, lisez la liste, coupez le droit d'accès. C'est toute la boucle.

Il y a un piège qui fait trébucher la plupart des équipes, et il n'est pas dans le code. Seules les commandes qui ont été révoquées apparaissent ici. Si vous remboursez un achat dans la Play Console sans cocher l'option de révocation, cette commande n'atteint jamais cette API, et votre tâche tourne proprement pendant qu'un client remboursé garde tout ce que vous lui avez vendu. Cet article parcourt l'API champ par champ, les chiffres qui la bornent et là où l'argent fuit quand vous la négligez.

Ce que la Voided Purchases API renvoie réellement

L'API répond à une seule question : quelles commandes de cette appli ont été annulées récemment. Une annulation couvre trois issues qui se terminent toutes par le client récupérant son argent. Une résiliation, un remboursement ou une rétrofacturation. Elle s'applique aux produits ponctuels dans l'appli et aux abonnements, et vous choisissez la portée avec un seul paramètre. Réglez type sur 0 et vous obtenez uniquement les achats de produits ponctuels annulés, ce qui est la valeur par défaut. Réglez-le sur 1 et vous obtenez ensemble les achats ponctuels annulés et les achats d'abonnement annulés.

Chaque entrée de la liste est un objet d'achat annulé. Les champs sont peu nombreux et chacun d'eux compte.

Les champs d'un achat annulé

ChampCe qu'il contient
orderIdL'id de commande qui identifie de façon unique un achat ponctuel, un achat d'abonnement ou un seul renouvellement d'abonnement. C'est votre clé de jointure
purchaseTokenLe token qui identifie un achat ponctuel ou un abonnement. Il ne distingue pas les renouvellements, donc utilisez orderId pour ceux-ci
purchaseTimeMillisQuand l'achat a été effectué, en millisecondes depuis l'epoch
voidedTimeMillisQuand l'achat a été résilié, remboursé ou rétrofacturé, en millisecondes depuis l'epoch
voidedSourceQui a initié l'annulation : 0 utilisateur, 1 développeur, 2 Google
voidedReasonPourquoi l'achat a été annulé, un entier de 0 à 8
voidedQuantityLa quantité annulée d'un remboursement partiel basé sur la quantité, renvoyée uniquement quand includeQuantityBasedPartialRefund est true

Lisez voidedReason avant d'agir

voidedReason est le champ qui transforme une liste brute en une décision. Un remboursement pour remords de l'acheteur et une rétrofacturation bancaire atterrissent dans la même liste, mais ce ne sont pas le même événement, et la tarification d'août rend l'un d'eux coûteux. Voici l'ensemble complet.

voidedReasonLabelCe que cela signifie pour vous
0OtherAucune catégorie n'a été attribuée. Révoquez et passez à autre chose
1RemorseL'acheteur a changé d'avis. Un remboursement ordinaire
2Not_receivedLe client dit ne jamais avoir reçu le produit. Vaut la peine de vérifier votre livraison
3DefectiveLe produit n'a pas fonctionné. Un signal de qualité, consignez-le
4Accidental_purchaseUn achat non intentionnel, souvent un appareil partagé
5FraudGoogle a signalé la transaction comme frauduleuse
6Friendly_fraudUne rétrofacturation où le titulaire légitime de la carte conteste un débit qu'il a lui-même effectué
7ChargebackLa banque du client a annulé le paiement. Définitif auprès de la banque, et désormais facturé chez vous
8Unacknowledged_purchaseGoogle a remboursé automatiquement un achat que votre appli n'a jamais confirmé

La fenêtre de 30 jours est le piège qui vide votre liste

La Voided Purchases API ne peut afficher que les achats annulés des 30 derniers jours. Le paramètre startTime a pour valeur par défaut l'heure actuelle moins 30 jours, et ne peut pas être réglé plus ancien que cela. endTime a pour valeur par défaut maintenant. L'endpoint est donc une fenêtre glissante d'un mois, pas une archive.

La conséquence est brutale. Si votre tâche d'interrogation tombe en panne et que personne ne le remarque pendant cinq semaines, les annulations de la première semaine ont vieilli et sont sorties de l'API. Aucun appel ne les ramène. Vous ne révoquerez pas ces commandes, et vous ne saurez même pas qu'elles ont existé, sauf si vous les avez capturées d'une autre manière. L'API est un filet de sécurité avec un trou à la taille de votre pire panne.

L'option de révocation décide si une commande apparaît même

C'est la raison la plus courante pour laquelle une équipe signale que l'API est cassée. Seules les commandes révoquées sont renvoyées. Les remboursements initiés par l'utilisateur, les résiliations, les rétrofacturations et les remboursements initiés par Google sont toujours révoqués, donc ils apparaissent toujours. Un remboursement initié par le développeur est différent. Quand vous remboursez une commande vous-même, via la Play Console ou l'Orders API, vous choisissez de la révoquer aussi ou non. Remboursez sans révoquer, et la commande est réglée avec le client mais n'apparaît jamais dans la Voided Purchases API.

La règle qui en découle est simple. Si votre intention est de retirer l'accès, remboursez avec l'option de révocation activée. Sinon, vous avez rendu l'argent et laissé la porte ouverte, et votre tâche de révocation, aussi bien écrite soit-elle, n'a rien sur quoi agir.

Comment l'interroger sans faire sauter le quota

L'endpoint est soumis à une limite de débit, et les limites sont assez basses pour qu'une boucle naïve les atteigne. Vous disposez de 6 000 requêtes par jour, comptées en heure du Pacifique, et de 30 requêtes au maximum dans toute période de 30 secondes. Ce budget convient à une interrogation par fenêtre et est hostile aux conceptions à une requête par commande.

Fenêtres d'interrogation et token de continuation

maxResults a pour valeur par défaut 1 000, qui est aussi le plafond. Quand une fenêtre contient plus d'une page d'annulations, la réponse porte un objet tokenPagination avec un nextPageToken. Repassez ce token à l'appel suivant pour parcourir les pages. Réglez startTime et endTime pour borner la fenêtre qui vous intéresse, avancez dans les pages jusqu'à épuisement du token, puis faites avancer la fenêtre. Ce schéma vous maintient à l'intérieur à la fois de la limite de rafale de 30 secondes et du plafond quotidien.

Les Real-time developer notifications comblent l'écart

Interroger chaque jour laisse encore jusqu'à un jour d'aveuglement, et la fenêtre de 30 jours punit les longs intervalles. Les Real-time developer notifications suppriment le décalage. Google publie une VoidedPurchaseNotification sur un topic Cloud Pub/Sub que vous possédez à l'instant où un achat est annulé, et votre backend la consomme en quelques secondes. Le message est petit.

Champ RTDNCe qu'il contient
purchaseTokenLe token de l'achat d'origine
orderIdL'id de commande de la transaction annulée, un nouveau par renouvellement d'abonnement
productType1 pour un abonnement, 2 pour un achat ponctuel
refundType1 pour un remboursement total, 2 pour un remboursement partiel basé sur la quantité
Une main fermant un cadenas en laiton sur une pile de reçus à côté d'un smartphone, illustrant la révocation d'accès après qu'un achat Google Play a été annulé

Ce que cela vous coûte en argent

L'API est de la plomberie, mais la raison de la câbler est une facture. Chaque annulation dans cette liste correspond à un vrai chiffre, et deux d'entre eux deviennent plus coûteux.

La facture de rétrofacturation retombe sur vous à partir du 3 août 2026

À partir du 3 août 2026, Google reporte le coût d'une rétrofacturation sur le développeur. Vous perdez le prix de l'achat et vous payez en plus les frais de rétrofacturation de la banque. Un voidedReason de 7 n'est plus seulement une vente perdue, c'est une ligne avec des frais attachés. Vous ne pouvez pas annuler une rétrofacturation, elle est définitive auprès de la banque, mais vous pouvez arrêter l'hémorragie après. Attraper l'annulation rapidement vous permet de révoquer le droit d'accès et, pour tout ce que vous êtes encore en train de fournir, d'arrêter de dépenser pour un client qui a été remboursé puis dont le paiement a été annulé.

Vous continuez de payer pour servir un client remboursé

Le prix de l'achat est perdu à l'instant où une annulation apparaît. Ce que vous contrôlez encore, c'est le coût de continuer à livrer. Chaque heure où un droit d'accès remboursé reste actif, vous continuez de payer pour les choses que le client ne finance plus : le calcul, les appels d'API de modèles, le stockage et tout reversement à un créateur ou partenaire lié à son usage. Un système de révocation piloté par cette API est votre moyen de couper ce compteur. Négligez-le, et vous financez le produit pour des gens que la boutique a déjà indemnisés.

La fraude amicale est un motif qui vaut la peine d'être suivi

Un voidedReason de 5 ou 6 n'est pas un cas isolé. La fraude et la fraude amicale se regroupent par compte, par appareil et parfois par promotion. L'API vous donne le voidedSource et le voidedReason sur chaque annulation, ce qui suffit à suivre l'abus par compte plutôt qu'à traiter chaque annulation comme un coût isolé. Un client qui fait deux rétrofacturations vous dit quelque chose que le premier remboursement n'a pas dit.

Le câblage à la façon RefundHalt

Le modèle est petit une fois que vous tenez toutes les pièces. Écoutez la VoidedPurchaseNotification en temps réel pour que rien n'attende un jour entier. Appelez la Voided Purchases API comme source de vérité, avec pour clé orderId afin que les renouvellements d'abonnement ne soient jamais confondus. Lisez le voidedSource et le voidedReason pour qu'une rétrofacturation soit traitée différemment d'un remboursement pour remords. Interrogez selon un calendrier assez serré pour que la fenêtre de 30 jours ne morde jamais, et remboursez avec l'option de révocation activée chaque fois que votre intention est de couper l'accès.

C'est la partie que RefundHalt exécute pour vous. Il consomme les notifications en temps réel, rapproche chaque annulation avec l'API, révoque la commande exacte plutôt que le produit entier, et sépare une rétrofacturation bancaire d'un remboursement ordinaire pour que les coûteuses soient signalées, pas enterrées. Vous obtenez un accès révoqué en quelques secondes et un enregistrement de qui a annulé quoi et pourquoi, sans avoir à monter vous-même un pipeline Pub/Sub et une tâche d'interrogation.

Questions fréquentes

Pourquoi mes commandes remboursées n'apparaissent-elles pas dans la Voided Purchases API ?
Parce que seules les commandes révoquées sont renvoyées. Les remboursements d'utilisateur, les résiliations, les rétrofacturations et les remboursements initiés par Google sont toujours révoqués et apparaissent toujours. Un remboursement initié par le développeur n'apparaît que si vous avez aussi choisi l'option de révocation. Si vous avez remboursé une commande sans la révoquer, la commande est réglée mais invisible pour cette API, donc remboursez avec la révocation activée chaque fois que vous comptez retirer l'accès.
Jusqu'où remonte la Voided Purchases API ?
Trente jours. Le paramètre startTime a pour valeur par défaut l'heure actuelle moins 30 jours et ne peut pas être réglé plus ancien que cela, donc l'endpoint est une fenêtre glissante d'un mois plutôt qu'une archive. Une commande annulée qui dépasse les 30 jours est perdue pour l'API sans aucun moyen de la récupérer, c'est pourquoi vous interrogez selon un calendrier et le renforcez avec des notifications en temps réel.
Dois-je utiliser les Real-time developer notifications ou la Voided Purchases API pour révoquer l'accès ?
Utilisez les deux. La VoidedPurchaseNotification arrive en quelques secondes et vous dit de regarder, mais la propre recommandation de Google est de la traiter comme un signal, pas comme une source de vérité. Appelez la Voided Purchases API pour confirmer l'état actuel, puis révoquez. La notification supprime le décalage, et l'API vous donne le voidedSource et le voidedReason officiels sur lesquels agir.
Comment distinguer une rétrofacturation d'un remboursement ordinaire dans l'API ?
Lisez le champ voidedReason. Une valeur de 7 est une rétrofacturation, ce qui signifie que la banque du client a annulé le paiement, et 6 est une fraude amicale. Une valeur de 1 est un remboursement pour remords. Cela importe parce qu'à partir du 3 août 2026, Google reporte le prix d'achat de la rétrofacturation et les frais de la banque sur le développeur, donc un voidedReason de 7 vous coûte plus qu'un simple remboursement.
La Voided Purchases API couvre-t-elle les abonnements ?
Oui. Réglez le paramètre type sur 1 pour obtenir à la fois les achats ponctuels annulés et les achats d'abonnement annulés. La valeur par défaut, type 0, ne renvoie que les achats de produits ponctuels. Pour les abonnements, identifiez la période annulée exacte par orderId, car un seul purchaseToken couvre chaque renouvellement et un nouveau orderId est généré pour chaque transaction de renouvellement.

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.