Quando un acquisto su Google Play viene rimborsato o subisce un chargeback, la Voided Purchases API è come lo scopri
Google Play annulla un acquisto in silenzio quando viene rimborsato o subisce un chargeback. La Voided Purchases API è l'elenco di quegli ordini, così puoi revocare l'accesso. Ecco ogni campo, la finestra di 30 giorni, l'opzione di revoca che nasconde gli ordini e quanto costa.

Punti chiave
- La Voided Purchases API, il metodo purchases.voidedpurchases.list, restituisce gli ordini che Google Play ha annullato, rimborsato o soggetto a chargeback, così puoi costruire un sistema di revoca che taglia l'accesso a ciò che il cliente non possiede più.
- Compaiono solo gli ordini revocati. Un rimborso emesso da uno sviluppatore senza l'opzione di revoca è invisibile a questa API, quindi se vuoi togliere l'accesso, devi rimborsare con la revoca attivata.
- La finestra è di 30 giorni. startTime non può essere più vecchio di 30 giorni fa, quindi un server che resta inattivo per più di un mese perde per sempre quegli ordini annullati. Interroga secondo una pianificazione.
- voidedSource ti dice chi ha annullato l'ordine: 0 è l'utente, 1 è lo sviluppatore, 2 è Google. voidedReason ti dice perché, da 0 Other fino a 7 Chargeback e 8 Unacknowledged_purchase.
- Le Real-time developer notifications inviano una VoidedPurchaseNotification nel momento in cui un acquisto viene annullato, ma trattala come un segnale. Chiama la Voided Purchases API per l'elenco autorevole prima di revocare.
- Identifica i rinnovi degli abbonamenti tramite orderId, non purchaseToken. Un solo purchaseToken copre ogni rinnovo di un abbonamento, quindi il token da solo non può distinguere due rinnovi.
- Le quote sono 6,000 query al giorno e 30 query in qualsiasi finestra di 30 secondi, quindi scorri i risultati con il token di continuazione e interroga per finestra temporale, mai una chiamata per ordine.
Un rimborso su Google Play non bussa alla tua porta. Il denaro si muove, il cliente tiene l'app aperta e, a meno che tu non vada a cercare, dalla tua parte non cambia nulla. La Voided Purchases API è dove vai a cercare. Ti consegna un elenco di ordini che sono stati annullati, rimborsati o soggetti a chargeback, così puoi revocare l'accesso a ciò che il cliente non paga più. Punta un job pianificato su di essa, leggi l'elenco, taglia il diritto. Questo è tutto il ciclo.
C'è un'insidia che fa inciampare la maggior parte dei team, e non è nel codice. Qui compaiono solo gli ordini che sono stati revocati. Se rimborsi un acquisto nella Play Console senza selezionare l'opzione di revoca, quell'ordine non raggiunge mai questa API, e il tuo job gira pulito mentre un cliente rimborsato conserva tutto ciò che gli hai venduto. Questo articolo percorre l'API campo per campo, i numeri che la delimitano e dove si perde il denaro quando la salti.
Cosa restituisce davvero la Voided Purchases API
L'API risponde a una sola domanda: quali ordini di questa app sono stati annullati di recente. Un annullamento copre tre esiti che finiscono tutti con il cliente che riottiene i propri soldi. Una cancellazione, un rimborso o un chargeback. Si applica ai prodotti in-app una tantum e agli abbonamenti, e scegli l'ambito con un singolo parametro. Imposta type a 0 e ottieni solo gli acquisti di prodotti in-app annullati, che è il valore predefinito. Impostalo a 1 e ottieni insieme gli acquisti in-app annullati e gli acquisti di abbonamenti annullati.
Ogni voce dell'elenco è un oggetto voided purchase. I campi sono pochi e ognuno di essi conta.
I campi di un voided purchase
| Campo | Cosa contiene |
|---|---|
| orderId | L'id ordine che identifica in modo univoco un acquisto una tantum, un acquisto di abbonamento o un singolo rinnovo di abbonamento. Questa è la tua chiave di join |
| purchaseToken | Il token che identifica un acquisto una tantum o un abbonamento. Non distingue i rinnovi, quindi usa orderId per quelli |
| purchaseTimeMillis | Quando è stato effettuato l'acquisto, in millisecondi dall'epoch |
| voidedTimeMillis | Quando l'acquisto è stato annullato, rimborsato o soggetto a chargeback, in millisecondi dall'epoch |
| voidedSource | Chi ha avviato l'annullamento: 0 utente, 1 sviluppatore, 2 Google |
| voidedReason | Perché l'acquisto è stato annullato, un intero da 0 a 8 |
| voidedQuantity | La quantità annullata da un rimborso parziale basato sulla quantità, restituita solo quando includeQuantityBasedPartialRefund è true |
Leggi voidedReason prima di agire
voidedReason è il campo che trasforma un elenco grezzo in una decisione. Un rimborso per pentimento dell'acquirente e un chargeback bancario finiscono entrambi nello stesso elenco, ma non sono lo stesso evento, e i prezzi di agosto ne rendono uno costoso. Ecco l'insieme completo.
| voidedReason | Etichetta | Cosa significa per te |
|---|---|---|
| 0 | Other | Nessuna categoria assegnata. Revoca e vai avanti |
| 1 | Remorse | L'acquirente ha cambiato idea. Un rimborso ordinario |
| 2 | Not_received | Il cliente dice di non aver mai ricevuto il prodotto. Vale la pena controllare la tua consegna |
| 3 | Defective | Il prodotto non ha funzionato. Un segnale di qualità, registralo |
| 4 | Accidental_purchase | Un acquisto involontario, spesso un dispositivo condiviso |
| 5 | Fraud | Google ha segnalato la transazione come fraudolenta |
| 6 | Friendly_fraud | Un chargeback in cui il legittimo titolare della carta contesta un addebito che ha effettuato |
| 7 | Chargeback | La banca del cliente ha stornato il pagamento. Definitivo con la banca, e ora addebitato a te |
| 8 | Unacknowledged_purchase | Google ha rimborsato automaticamente un acquisto che la tua app non ha mai confermato |
La finestra di 30 giorni è la trappola che svuota il tuo elenco
La Voided Purchases API può mostrare solo gli acquisti annullati degli ultimi 30 giorni. Il parametro startTime ha come valore predefinito l'ora corrente meno 30 giorni, e non può essere impostato più vecchio di così. endTime ha come valore predefinito adesso. Quindi l'endpoint è una finestra mobile di un mese, non un archivio.
La conseguenza è netta. Se il tuo job di polling si rompe e nessuno se ne accorge per cinque settimane, gli annullamenti della prima settimana sono scaduti dall'API. Non c'è alcuna chiamata che li riporti indietro. Non revocherai quegli ordini, e non saprai nemmeno che sono esistiti a meno che tu non li abbia catturati in qualche altro modo. L'API è una rete di sicurezza con un buco della dimensione del tuo peggior disservizio.
L'opzione di revoca decide se un ordine compare del tutto
Questo è il motivo più comune per cui un team segnala l'API come difettosa. Vengono restituiti solo gli ordini revocati. I rimborsi avviati dall'utente, le cancellazioni, i chargeback e i rimborsi avviati da Google vengono sempre revocati, quindi compaiono sempre. Un rimborso avviato dallo sviluppatore è diverso. Quando rimborsi un ordine tu stesso, tramite la Play Console o le Orders API, scegli se revocarlo anche. Rimborsa senza revoca, e l'ordine è saldato con il cliente ma non emerge mai nella Voided Purchases API.
La regola che ne consegue è semplice. Se la tua intenzione è togliere l'accesso, rimborsa con l'opzione di revoca attivata. Altrimenti hai restituito il denaro e lasciato la porta aperta, e il tuo job di revoca, per quanto ben scritto, non ha nulla su cui agire.
Come interrogarla senza far scattare la quota
L'endpoint ha un limite di frequenza, e i limiti sono abbastanza bassi da far scattare un loop ingenuo. Ottieni 6,000 query al giorno, conteggiate in ora del Pacifico, e non più di 30 query in un qualsiasi periodo di 30 secondi. Quel budget va bene per il polling a finestre ed è ostile ai progetti con una richiesta per ordine.
Finestre di query e il token di continuazione
maxResults ha come valore predefinito 1,000, che è anche il tetto massimo. Quando una finestra contiene più di una pagina di annullamenti, la risposta porta un oggetto tokenPagination con un nextPageToken. Passa quel token nella chiamata successiva per scorrere le pagine. Imposta startTime e endTime per delimitare la finestra che ti interessa, scorri le pagine finché il token non si esaurisce, poi avanza la finestra. Quel pattern ti tiene dentro sia il limite di burst di 30 secondi sia il tetto giornaliero.
Le Real-time developer notifications colmano il divario
Interrogare ogni giorno lascia comunque fino a un giorno di cecità, e la finestra di 30 giorni punisce le lunghe interruzioni. Le Real-time developer notifications eliminano il ritardo. Google pubblica una VoidedPurchaseNotification su un topic Cloud Pub/Sub di tua proprietà nel momento in cui un acquisto viene annullato, e il tuo backend la consuma in pochi secondi. Il messaggio è piccolo.
| Campo RTDN | Cosa contiene |
|---|---|
| purchaseToken | Il token dell'acquisto originale |
| orderId | L'id ordine della transazione annullata, uno nuovo per ogni rinnovo di abbonamento |
| productType | 1 per un abbonamento, 2 per un acquisto una tantum |
| refundType | 1 per un rimborso totale, 2 per un rimborso parziale basato sulla quantità |

Cosa ti costa in denaro
L'API è impiantistica, ma la ragione per collegarla è una fattura. Ogni annullamento in quell'elenco corrisponde a un numero reale, e due di essi stanno diventando più costosi.
La fattura del chargeback ricade su di te dal 3 agosto 2026
A partire dal 3 agosto 2026, Google sposta il costo di un chargeback sullo sviluppatore. Perdi il prezzo d'acquisto e paghi in più la commissione di chargeback della banca. Un voidedReason pari a 7 non è più solo una vendita persa, è una voce di costo con una commissione allegata. Non puoi annullare un chargeback, è definitivo con la banca, ma puoi fermare l'emorragia dopo. Cogliere l'annullamento in fretta ti permette di revocare il diritto e, per tutto ciò che stai ancora erogando, di smettere di spendere per un cliente che è stato rimborsato e poi stornato.
Continui a pagare per servire un cliente rimborsato
Il prezzo d'acquisto è perso nel momento in cui compare un annullamento. Ciò che controlli ancora è il costo di continuare a erogare. Ogni ora in cui un diritto rimborsato resta attivo, continui a pagare per le cose che il cliente non finanzia più: calcolo, chiamate alle API dei modelli, archiviazione, e qualsiasi pagamento a creatori o partner legato al suo utilizzo. Un sistema di revoca guidato da questa API è il modo per spegnere quel contatore. Saltalo, e finanzi il prodotto per persone che lo store ha già risarcito.
Il friendly fraud è uno schema di cui vale la pena seguire l'andamento
Un voidedReason pari a 5 o 6 non è un caso isolato. Fraud e friendly fraud si concentrano per account, per dispositivo e a volte per promozione. L'API ti fornisce voidedSource e voidedReason su ogni annullamento, il che basta a seguire l'andamento degli abusi per account invece di trattare ogni storno come un costo isolato. Un cliente che fa due chargeback ti sta dicendo qualcosa che il primo rimborso non aveva detto.
Collegarla alla maniera di RefundHalt
Il modello è piccolo una volta che hai in mano tutti i pezzi. Resta in ascolto delle VoidedPurchaseNotification in tempo reale così che nulla aspetti un giorno intero. Chiama la Voided Purchases API come fonte di verità, con chiave orderId così che i rinnovi degli abbonamenti non vengano mai confusi. Leggi voidedSource e voidedReason così che un chargeback venga gestito diversamente da un rimborso per pentimento. Interroga con una pianificazione abbastanza serrata da non far mai mordere la finestra di 30 giorni, e rimborsa con l'opzione di revoca attivata ogni volta che la tua intenzione è tagliare l'accesso.
Questa è la parte che RefundHalt gestisce per te. Consuma le notifiche in tempo reale, riconcilia ogni annullamento con l'API, revoca l'ordine esatto invece dell'intero prodotto, e separa un chargeback bancario da un rimborso ordinario così che quelli costosi vengano segnalati, non sepolti. Ottieni l'accesso revocato in pochi secondi e un registro di chi ha annullato cosa e perché, senza dover allestire tu stesso una pipeline Pub/Sub e un job di polling.
Domande frequenti
- Perché i miei ordini rimborsati non compaiono nella Voided Purchases API?
- Perché vengono restituiti solo gli ordini revocati. I rimborsi degli utenti, le cancellazioni, i chargeback e i rimborsi avviati da Google vengono sempre revocati e compaiono sempre. Un rimborso avviato dallo sviluppatore compare solo se hai scelto anche l'opzione di revoca. Se hai rimborsato un ordine senza revocarlo, l'ordine è saldato ma invisibile a questa API, quindi rimborsa con la revoca attivata ogni volta che intendi togliere l'accesso.
- Fino a quanto indietro arriva la Voided Purchases API?
- Trenta giorni. Il parametro startTime ha come valore predefinito l'ora corrente meno 30 giorni e non può essere impostato più vecchio di così, quindi l'endpoint è una finestra mobile di un mese piuttosto che un archivio. Un ordine annullato che supera i 30 giorni sparisce dall'API senza alcun modo di recuperarlo, ed è per questo che interroghi secondo una pianificazione e la supporti con notifiche in tempo reale.
- Dovrei usare le Real-time developer notifications o la Voided Purchases API per revocare l'accesso?
- Usa entrambe. La VoidedPurchaseNotification arriva in pochi secondi e ti dice di guardare, ma la stessa guida di Google è di trattarla come un segnale, non come una fonte di verità. Chiama la Voided Purchases API per confermare lo stato attuale, poi revoca. La notifica elimina il ritardo, e l'API ti fornisce l'autorevole voidedSource e voidedReason su cui agire.
- Come distinguo un chargeback da un rimborso ordinario nell'API?
- Leggi il campo voidedReason. Un valore di 7 è un chargeback, cioè la banca del cliente ha stornato il pagamento, e 6 è friendly fraud. Un valore di 1 è un rimborso per pentimento. Questo conta perché dal 3 agosto 2026 Google trasferisce allo sviluppatore il prezzo d'acquisto del chargeback e la commissione bancaria, quindi un voidedReason pari a 7 ti costa più di un semplice rimborso.
- La Voided Purchases API copre gli abbonamenti?
- Sì. Imposta il parametro type a 1 per ottenere sia gli acquisti in-app annullati sia gli acquisti di abbonamenti annullati. Il valore predefinito, type 0, restituisce solo gli acquisti di prodotti in-app. Per gli abbonamenti, identifica il periodo annullato esatto tramite orderId, perché un solo purchaseToken copre ogni rinnovo e un nuovo orderId viene generato per ogni transazione di rinnovo.
Fonti e approfondimenti
- Google Play Developer API: Voided Purchases API guide
- Google Play Developer API: purchases.voidedpurchases.list method
- Google Play Developer API: purchases.voidedpurchases resource (voidedSource and voidedReason)
- Android Developers: Real-time developer notifications reference (VoidedPurchaseNotification)
- Android Developers: Fight fraud and abuse with Play Billing
RefundHalt
Il pilota automatico dei rimborsi per App Store e Google Play
Continua a leggere
Tre notifiche di rimborso dell'App Store arrivano dopo la decisione di Apple, e REFUND_REVERSED ti restituisce la vendita
Apple invia quattro messaggi di rimborso tramite App Store Server Notifications V2, e la maggior parte delle app ne gestisce solo due. REFUND ti dice di revocare, REFUND_DECLINED significa mantenere la vendita, e REFUND_REVERSED ti restituisce la vendita e ti chiede di ripristinare ciò che hai tolto. Ecco cosa richiede ciascuna.
Ogni richiesta di rimborso Apple ora arriva con un motivo, e consumptionRequestReason è come lo leggi
Dalla WWDC24, ogni CONSUMPTION_REQUEST di Apple contiene un consumptionRequestReason, il motivo dichiarato dal cliente stesso per volere un rimborso. Ci sono cinque valori, da UNINTENDED_PURCHASE a LEGAL, e ognuno dovrebbe cambiare ciò che rimandi indietro entro la tua finestra di 12 hours. Ecco come leggere ognuno di essi.