Un achat en attente ressemble à une vente, mais l'argent n'est pas arrivé, et l'accorder trop tôt revient à donner le produit
L'App Store comme Google Play ont un état d'achat en attente, une commande que la boutique a acceptée mais pas encore débitée. Débloquez-la avant que le paiement soit encaissé et chacun de ceux qui échouent est un coût sec. Voici comment fonctionnent les achats en attente sur chaque boutique, ce que coûte un achat accordé à tort, et comment les gérer sans fuite.

Points clés
- Un achat en attente est une vraie commande que la boutique a acceptée mais pas encore débitée. Votre code voit un nouvel achat, mais l'argent n'est pas arrivé, et il pourrait ne jamais arriver.
- N'accordez le droit d'accès que lorsque l'état est PURCHASED sur Google Play, ou lorsque la transaction est terminée sur Apple. Ne débloquez jamais sur un état PENDING ni sur le résultat en attente d'Apple.
- Sur Google Play, les paiements en espèces en magasin, les virements bancaires et une partie de la facturation par l'opérateur sont réglés hors ligne, si bien que l'achat revient en PENDING, pas en PURCHASED, jusqu'à ce que le client paie vraiment.
- Sur Apple, un achat en attente est le plus souvent Ask to Buy, où un organisateur familial doit l'approuver. L'approbation peut prendre des heures ou des jours, et la transaction terminée arrive plus tard via Transaction.updates.
- Si vous débloquez sur une commande en attente qui s'annule ensuite, vous avez dépensé du calcul, des appels d'API, du stockage ou le versement d'un consommable pour un débit qui n'a jamais été encaissé. Contrairement à un remboursement, il n'y a pas d'argent à récupérer, car rien n'a jamais été perçu.
- La boutique vous prévient quand une commande en attente échoue. Google envoie ONE_TIME_PRODUCT_CANCELED, type 2, ou SUBSCRIPTION_PENDING_PURCHASE_CANCELED, type 20. Apple, tout simplement, ne livre jamais de transaction terminée.
- Une commande en attente peut devenir une vraie vente pendant que votre app est fermée, alors revérifiez au retour : appelez queryPurchasesAsync() dans onResume() sur Google Play, et continuez d'écouter Transaction.updates sur Apple.
Quelqu'un appuie sur acheter dans votre app. Vos journaux montrent une nouvelle commande, votre écouteur de facturation se déclenche, et vous remettez la marchandise. Sur la plupart des achats, c'est exactement ce qu'il faut. Sur un achat en attente, c'est une erreur, car la commande existe mais pas l'argent. Le client a choisi un moyen de paiement qui se règle plus tard, la boutique attend toujours d'être payée, et vous venez de livrer une fonctionnalité payante pour un débit qui ne sera peut-être jamais encaissé. C'est le cousin discret d'un remboursement. Ici, rien n'est annulé, car rien n'a jamais été perçu. Vous avez simplement donné le produit.
Un achat en attente est une vraie commande dans un état pas encore payé, et l'App Store comme Google Play en ont un. Les deux boutiques vous disent clairement d'attendre. Le piège, c'est qu'une commande en attente ressemble presque à s'y méprendre à une commande terminée dans votre code, si bien qu'une intégration qui traite chaque nouvel achat comme une vente livre de la marchandise sur des commandes que la boutique tente encore d'encaisser. Gérez-la correctement et vous ne perdez rien. Gérez-la mal et chaque paiement lent qui échoue est un coût sec, livré à vos frais.
Ce qu'est vraiment un achat en attente
Un achat en attente est une commande que la boutique a enregistrée mais pas encore débitée. L'acheteur a lancé le flux, la boutique l'a acceptée, et le règlement se produit quelque part que votre app ne peut pas voir. Google Play appelle cela l'état PENDING. Apple parle d'une transaction en attente, ou différée. Des noms différents, un même fait : la boutique garde une commande ouverte pendant qu'elle attend d'être payée, et elle vous a dit de ne pas traiter cette commande comme de l'argent.
Google Play : le paiement se produit ailleurs
Certains moyens de paiement se règlent hors ligne. L'espèce dans un magasin physique, les virements bancaires et une partie de la facturation par l'opérateur exigent des étapes supplémentaires entre l'appui et le débit. Quand un client en choisit un, Google renvoie l'achat dans l'état PENDING au lieu de PURCHASED. Pour un paiement en espèces, le client reçoit un code par notification et par e-mail, l'apporte dans un magasin participant et paie à la caisse. Jusque-là, Google n'a rien encaissé, et vous non plus. La règle de Google tient en une ligne : utilisez getPurchaseState() et n'accordez le droit d'accès que lorsque l'état est PURCHASED. Elle vous dit aussi de ne pas confirmer un achat tant qu'il est en PENDING, car la confirmation appartient à une commande payée, pas à une commande promise.
Apple : l'achat attend l'appui de quelqu'un d'autre
L'état en attente d'Apple signifie que la transaction a besoin d'une action externe avant de pouvoir se terminer. La plus fréquente est Ask to Buy, où un enfant lance un achat et un organisateur familial doit l'approuver. Dans StoreKit 2, l'appel d'achat renvoie Product.PurchaseResult.pending. Dans l'ancien StoreKit, la transaction est signalée comme différée. Dans tous les cas, Apple n'a débité personne, et la transaction terminée, si elle vient, arrive de façon asynchrone via Transaction.updates. Montrez au client un état d'attente et ne débloquez rien tant que la transaction terminée n'a pas atterri.
Pourquoi accorder un achat en attente vous coûte de l'argent réel
La perte ici n'est pas du type remboursement, où l'argent que vous aviez comptabilisé est repris. C'est pire sur un point précis : il n'y a pas d'argent à reprendre, car rien n'a jamais été perçu.
Vous livrez, et la boutique n'encaisse jamais
Quand vous débloquez sur une commande en attente qui s'annule ensuite, vous avez déjà dépensé pour la servir. Le calcul qui a exécuté la fonctionnalité, les appels d'API tiers que vous avez payés, le stockage que vous avez alloué, et pour un consommable le versement réel de ce que vous avez vendu. Tout cela sort par la porte sur une commande qui n'a produit aucun revenu. Un remboursement part au moins d'un débit qui a eu lieu. Un achat en attente accordé à tort n'a jamais eu le moindre débit, si bien qu'il n'apparaît même pas comme de l'argent qui sort. Il apparaît comme rien, ce qui est justement pourquoi il est facile à manquer et facile à répéter.
Le signal d'annulation, et ce qu'il signifie
La boutique vous prévient bien quand une commande en attente meurt. Sur Google Play, un produit unique qui échoue envoie une notification ONE_TIME_PRODUCT_CANCELED, type 2, et un abonnement qui était en attente envoie SUBSCRIPTION_PENDING_PURCHASE_CANCELED, type 20. Quand ces mêmes commandes aboutissent au contraire, vous recevez ONE_TIME_PRODUCT_PURCHASED, type 1, ou SUBSCRIPTION_PURCHASED, type 4. Sur Apple, il n'y a pas d'événement d'annulation à capter, car une transaction différée qui est refusée ne devient tout simplement jamais une transaction terminée. Si vous avez débloqué trop tôt, ce silence est la facture.
| Question | Google Play | Apple |
|---|---|---|
| Ce qui la déclenche | Espèces, virement bancaire, une partie de la facturation par l'opérateur | Approbation Ask to Buy, ou autre action requise |
| État que vous voyez | PurchaseState PENDING | résultat en attente, ou une transaction différée |
| Accordez l'accès quand | L'état est PURCHASED | La transaction est terminée |
| Elle a abouti | ONE_TIME_PRODUCT_PURCHASED (1), SUBSCRIPTION_PURCHASED (4) | Transaction terminée via Transaction.updates |
| Elle a échoué | ONE_TIME_PRODUCT_CANCELED (2), SUBSCRIPTION_PENDING_PURCHASE_CANCELED (20) | Aucune transaction terminée n'arrive jamais |
| De l'argent a-t-il été perçu | Non, pas avant PURCHASED | Non, pas avant que la transaction se termine |
La fenêtre, et qui attend qui
Un achat en attente n'est pas un chrono contre lequel vous courez. C'est un chrono qui, de votre côté, n'a pas démarré.
Google Play donne au client des jours, pas des minutes
Un paiement en espèces ou par virement bancaire se règle selon le calendrier du client, pas le vôtre. La commande reste en PENDING jusqu'à ce que le client paie ou que la fenêtre expire et que Google l'annule. Votre propre fenêtre de confirmation de trois jours, celle qui rembourse automatiquement un achat que vous ne confirmez pas, ne commence même pas tant que l'achat n'est pas passé de PENDING à PURCHASED. Il n'y a donc aucune urgence à servir une commande en attente. Il y a seulement la discipline d'attendre que l'état change.
L'approbation d'Apple est sur le téléphone de l'organisateur familial
Une demande Ask to Buy arrive sur l'appareil de l'organisateur sous forme d'une invite qu'il approuve ou refuse quand il y arrive. Cela peut être des minutes, des heures ou un jour plus tard, et votre app ne peut pas presser les choses. Le seul comportement correct est de refléter l'état d'attente et de laisser StoreKit vous remettre la transaction terminée si et quand l'approbation arrive.

Comment gérer les achats en attente sans fuite
Tout le travail se résume à quatre habitudes. Aucune n'est difficile, et en sauter une seule est par où l'argent s'en va.
Accordez sur l'état payé, jamais sur l'état en attente
Sur Google Play, vérifiez getPurchaseState() et n'accordez que sur PURCHASED, et ne confirmez pas un achat tant qu'il est en PENDING. Sur Apple, ne débloquez que sur une transaction terminée et jamais sur le résultat en attente. Cette seule règle referme toute la fuite. Tout le reste consiste à vous assurer que vous remarquez bien l'arrivée de l'état payé.
Revérifiez quand l'app revient
Le passage de en attente à payé se produit souvent pendant que votre app ne tourne pas. Sur Google Play, appelez queryPurchasesAsync() dans votre gestionnaire onResume() pour récupérer les commandes passées en PURCHASED en arrière-plan, et gardez votre écouteur de Real-time Developer Notifications comme source de vérité côté serveur. Sur Apple, écoutez Transaction.updates pendant toute la vie de l'app, car une transaction approuvée peut arriver bien après le retour de l'appel d'achat d'origine.
Activez la prise en charge des achats en attente et testez les deux issues
Google exige que vous appeliez enablePendingPurchases() quand vous construisez le BillingClient, et prendre en charge les transactions en attente pour les produits uniques est obligatoire, pas facultatif. Testez-le avant de publier. Les testeurs sous licence obtiennent deux instruments de test supplémentaires pour les formes de paiement différé, où le paiement se termine automatiquement ou s'annule automatiquement après quelques minutes, pour que vous puissiez observer de bout en bout aussi bien le chemin du paiement que celui de l'échec.
Dites au client que la commande n'est pas terminée
Un acheteur en attente est un vrai client au milieu d'un achat, pas un échec. Montrez-lui que la commande attend son paiement ou une approbation, et donnez-lui un chemin clair pour revenir la terminer. Un état en attente silencieux perd des ventes qu'un état bien étiqueté récupère, car la plupart de ces acheteurs veulent encore la chose et n'ont plus qu'une étape à faire.
Les mêmes flux de Real-time Developer Notifications et d'App Store Server Notifications que RefundHalt lit déjà pour les remboursements et les rétrofacturations portent aussi ces signaux. La notification d'achat qui dit qu'une commande en attente a enfin été encaissée, et la notification d'annulation qui dit que non, atterrissent dans votre tableau de bord à côté du reste de vos événements de revenu, si bien qu'une commande en attente qui a échoué est quelque chose que vous pouvez voir au lieu de quelque chose que vous avez payé par accident.
La version courte
Un achat en attente est une commande sans paiement, et les deux boutiques sont explicites sur le fait que vous devez attendre. Google Play renvoie les commandes en espèces, par virement bancaire et une partie de la facturation par l'opérateur dans un état PENDING et vous dit de n'accorder l'accès que sur PURCHASED. Apple renvoie une transaction en attente ou différée pour Ask to Buy et d'autres actions requises et livre la transaction terminée plus tard via Transaction.updates. Débloquez sur l'état payé, revérifiez quand votre app reprend, activez et testez la prise en charge des achats en attente, et étiquetez la commande en attente pour le client. Faites cela et un achat en attente ne vous coûte rien. Sautez-le et vous livrez un produit payant pour un débit qui n'est jamais venu, ce qui est la seule perte sans reçu à pointer du doigt.
Questions fréquentes
- Qu'est-ce qu'un achat en attente ?
- Un achat en attente est une commande que la boutique a acceptée mais pas encore débitée. Sur Google Play, c'est l'état d'achat PENDING, utilisé pour les moyens de paiement qui se règlent plus tard comme les espèces, le virement bancaire et une partie de la facturation par l'opérateur. Sur Apple, c'est une transaction en attente ou différée, le plus souvent un achat Ask to Buy attendant l'approbation d'un organisateur familial. Dans les deux cas, aucun argent n'a encore été perçu, vous ne devez donc pas accorder l'accès.
- Dois-je accorder l'accès pendant qu'un achat est en attente ?
- Non. N'accordez le droit d'accès que lorsque l'état est PURCHASED sur Google Play, ou lorsque la transaction est terminée sur Apple. Si vous débloquez une fonctionnalité pendant que la commande est encore en attente et que le paiement n'est jamais encaissé, vous avez livré le produit gratuitement, et il n'y a aucun débit à annuler puisqu'aucun n'a jamais été fait.
- Quels moyens de paiement provoquent un achat en attente sur Google Play ?
- Les moyens de paiement qui se règlent hors ligne. Les paiements en espèces dans un magasin physique, les virements bancaires et certaines options de facturation par l'opérateur exigent des étapes supplémentaires entre l'appui et le débit, si bien que Google renvoie l'achat dans l'état PENDING au lieu de PURCHASED. Pour un paiement en espèces, le client reçoit un code par notification et e-mail, puis paie dans un magasin participant.
- Qu'est-ce qu'Ask to Buy, et quel est son rapport avec les achats en attente ?
- Ask to Buy est la fonctionnalité Family Sharing d'Apple qui permet à un enfant de demander un achat qu'un organisateur familial doit approuver. Tant que la demande attend, l'achat est dans l'état en attente d'Apple, renvoyé comme Product.PurchaseResult.pending dans StoreKit 2 ou comme une transaction différée dans l'ancien StoreKit. La transaction terminée n'arrive, via Transaction.updates, que si et quand l'organisateur l'approuve.
- Que se passe-t-il si un achat en attente n'est jamais payé ?
- La commande est annulée et aucun argent ne change de mains. Sur Google Play, vous recevez une notification ONE_TIME_PRODUCT_CANCELED, type 2, pour un produit unique, ou SUBSCRIPTION_PENDING_PURCHASE_CANCELED, type 20, pour un abonnement. Sur Apple, la transaction différée ne devient tout simplement jamais une transaction terminée. Si vous aviez déjà accordé l'accès, c'est le moment où la perte devient réelle.
- Un achat en attente est-il la même chose qu'un remboursement ?
- Non. Un remboursement annule un paiement qui a réellement été perçu. Un achat en attente qui échoue n'a jamais été débité au départ, il n'y a donc rien à annuler et rien n'apparaît dans un rapport de remboursements. Si vous l'avez débloqué trop tôt, le coût est le calcul, les appels d'API, le stockage ou le consommable que vous avez dépensés à servir une commande qui n'a produit aucun revenu.
Sources et lectures complémentaires
- Android Developers: Integrate the Google Play Billing Library (PENDING purchase state, grant entitlement only on PURCHASED, enablePendingPurchases, queryPurchasesAsync, cash payment code flow, three-day acknowledgement window begins on transition to PURCHASED)
- Android Developers: Real-time developer notifications reference (OneTimeProductNotification ONE_TIME_PRODUCT_PURCHASED=1 and ONE_TIME_PRODUCT_CANCELED=2; SubscriptionNotification SUBSCRIPTION_PURCHASED=4 and SUBSCRIPTION_PENDING_PURCHASE_CANCELED=20)
- Android Developers: Test Google Play Billing (license testers get delayed-payment test instruments that auto-complete or auto-cancel for testing pending transactions)
- Apple Developer: Product.PurchaseResult (the pending case, returned when a purchase needs action such as Ask to Buy approval before it completes)
- Apple Developer: SKPaymentTransactionState.deferred (a transaction whose final status is pending an external action such as Ask to Buy)
- Apple Developer: Transaction.updates (StoreKit delivers transaction updates, including ones approved later, asynchronously)
RefundHalt
Le pilote automatique des remboursements pour l'App Store et Google Play
Poursuivre la lecture
Les renouvellements échouent plus souvent que les clients n'annulent, et cette attrition involontaire est un revenu que vous pouvez encore récupérer
Une carte refusée, et non un clic sur annuler, met fin à une grande partie des abonnements, et la boutique continue d'essayer de percevoir pendant des semaines. Voici comment fonctionnent le délai de grâce de facturation, la nouvelle tentative de facturation et la suspension de compte sur l'App Store et Google Play, et ce que l'attrition involontaire vous coûte vraiment.
Les achats intégrés non autorisés par des enfants sont remboursés au parent presque à chaque fois, et c'est vous qui en supportez le coût
Quand un enfant achète un pack de pièces sur le téléphone d'un parent, Apple comme Google le remboursent, et ni l'un ni l'autre ne vous demande votre avis. Les régulateurs l'ont voulu ainsi. Voici comment fonctionnent ces remboursements d'achats intégrés non autorisés sur chaque store, la fenêtre de 15 minutes où l'argent part, et ce qu'un seul de ces achats vous coûte réellement.