Ketika pembelian Google Play direfund atau di-chargeback, Voided Purchases API adalah cara Anda mengetahuinya
Google Play membatalkan sebuah pembelian secara diam-diam ketika pembelian itu direfund atau di-chargeback. Voided Purchases API adalah daftar pesanan tersebut, sehingga Anda bisa mencabut akses. Berikut setiap field, jendela 30 hari, opsi revoke yang menyembunyikan pesanan, dan berapa biayanya.

Poin utama
- Voided Purchases API, yaitu metode purchases.voidedpurchases.list, mengembalikan pesanan yang dibatalkan, direfund, atau di-chargeback oleh Google Play, sehingga Anda bisa membangun sistem pencabutan yang memutus akses ke hal yang tidak lagi dimiliki pelanggan.
- Hanya pesanan yang direvoke yang muncul. Refund dari developer yang dilakukan tanpa opsi revoke tidak terlihat oleh API ini, jadi jika Anda ingin menarik akses, Anda harus melakukan refund dengan revoke diaktifkan.
- Jendelanya adalah 30 hari. startTime tidak boleh lebih lama dari 30 hari yang lalu, sehingga server yang mati lebih lama dari sebulan kehilangan pesanan yang dibatalkan itu selamanya. Lakukan polling sesuai jadwal.
- voidedSource memberi tahu Anda siapa yang membatalkan pesanan: 0 adalah pengguna, 1 adalah developer, 2 adalah Google. voidedReason memberi tahu Anda alasannya, dari 0 Other hingga 7 Chargeback dan 8 Unacknowledged_purchase.
- Real-time developer notifications mengirimkan VoidedPurchaseNotification pada saat sebuah pembelian dibatalkan, tetapi perlakukan itu sebagai sinyal. Panggil Voided Purchases API untuk mendapatkan daftar yang otoritatif sebelum Anda mencabut akses.
- Identifikasi perpanjangan langganan berdasarkan orderId, bukan purchaseToken. Satu purchaseToken mencakup setiap perpanjangan sebuah langganan, jadi token itu sendiri tidak bisa membedakan dua perpanjangan.
- Kuotanya adalah 6,000 kueri per hari dan 30 kueri dalam setiap jendela 30 detik, jadi telusuri hasil per halaman dengan continuation token dan kueri berdasarkan jendela waktu, jangan pernah satu panggilan per pesanan.
Sebuah refund di Google Play tidak mengetuk pintu Anda. Uangnya berpindah, pelanggan tetap membuka aplikasi, dan kecuali Anda memeriksanya, tidak ada yang berubah di sisi Anda. Voided Purchases API adalah tempat Anda memeriksanya. API ini memberi Anda daftar pesanan yang dibatalkan, direfund, atau di-chargeback, sehingga Anda bisa mencabut akses ke hal yang tidak lagi dibayar pelanggan. Arahkan sebuah scheduled job ke sana, baca daftarnya, putus entitlement-nya. Itulah keseluruhan alurnya.
Ada satu jebakan yang menyandung sebagian besar tim, dan itu bukan di dalam kode. Hanya pesanan yang direvoke yang muncul di sini. Jika Anda merefund sebuah pembelian di Play Console tanpa mencentang opsi revoke, pesanan itu tidak akan pernah sampai ke API ini, dan job Anda berjalan mulus sementara pelanggan yang direfund tetap menyimpan semua yang Anda jual kepadanya. Artikel ini membahas API ini field demi field, angka-angka yang membatasinya, dan di mana uang bocor ketika Anda melewatkannya.
Apa yang sebenarnya dikembalikan Voided Purchases API
API ini menjawab satu pertanyaan: pesanan mana untuk aplikasi ini yang baru-baru ini dibatalkan. Sebuah pembatalan (void) mencakup tiga hasil yang semuanya berakhir dengan pelanggan mendapatkan uangnya kembali. Sebuah cancellation, sebuah refund, atau sebuah chargeback. Ini berlaku untuk produk dalam aplikasi sekali beli dan untuk langganan, dan Anda memilih cakupannya dengan satu parameter. Setel type ke 0 dan Anda hanya mendapatkan pembelian produk dalam aplikasi yang dibatalkan, yang merupakan default. Setel ke 1 dan Anda mendapatkan pembelian dalam aplikasi yang dibatalkan dan pembelian langganan yang dibatalkan sekaligus.
Setiap entri dalam daftar adalah sebuah objek voided purchase. Field-nya sedikit dan setiap field penting.
Field pada sebuah voided purchase
| Field | Apa isinya |
|---|---|
| orderId | Order id yang secara unik mengidentifikasi sebuah pembelian sekali beli, sebuah pembelian langganan, atau satu perpanjangan langganan tunggal. Ini adalah kunci join Anda |
| purchaseToken | Token yang mengidentifikasi sebuah pembelian sekali beli atau sebuah langganan. Token ini tidak membedakan perpanjangan, jadi gunakan orderId untuk itu |
| purchaseTimeMillis | Kapan pembelian dilakukan, dalam milidetik sejak epoch |
| voidedTimeMillis | Kapan pembelian dibatalkan, direfund, atau di-chargeback, dalam milidetik sejak epoch |
| voidedSource | Siapa yang memulai pembatalan: 0 pengguna, 1 developer, 2 Google |
| voidedReason | Mengapa pembelian dibatalkan, sebuah bilangan bulat dari 0 hingga 8 |
| voidedQuantity | Jumlah yang dibatalkan dari partial refund berbasis kuantitas, dikembalikan hanya ketika includeQuantityBasedPartialRefund bernilai true |
Baca voidedReason sebelum Anda bertindak
voidedReason adalah field yang mengubah daftar mentah menjadi sebuah keputusan. Sebuah refund karena penyesalan pembeli dan sebuah chargeback bank sama-sama masuk ke daftar yang sama, tetapi keduanya bukan peristiwa yang sama, dan harga baru di bulan Agustus membuat salah satunya mahal. Berikut himpunan lengkapnya.
| voidedReason | Label | Apa artinya bagi Anda |
|---|---|---|
| 0 | Other | Tidak ada kategori yang ditetapkan. Cabut akses dan lanjutkan |
| 1 | Remorse | Pembeli berubah pikiran. Sebuah refund biasa |
| 2 | Not_received | Pelanggan mengatakan mereka tidak pernah menerima produk. Perlu memeriksa pengiriman Anda |
| 3 | Defective | Produk tidak berfungsi. Sebuah sinyal kualitas, catat itu |
| 4 | Accidental_purchase | Sebuah pembelian tak disengaja, sering kali pada perangkat yang dipakai bersama |
| 5 | Fraud | Google menandai transaksi sebagai penipuan |
| 6 | Friendly_fraud | Sebuah chargeback di mana pemegang kartu yang sah menyanggah tagihan yang mereka buat sendiri |
| 7 | Chargeback | Bank pelanggan membalikkan pembayaran. Final di pihak bank, dan kini ditagihkan kepada Anda |
| 8 | Unacknowledged_purchase | Google secara otomatis merefund sebuah pembelian yang tidak pernah diakui (acknowledge) oleh aplikasi Anda |
Jendela 30 hari adalah jebakan yang mengosongkan daftar Anda
Voided Purchases API hanya bisa menampilkan pembelian yang dibatalkan dari 30 hari terakhir. Parameter startTime secara default bernilai waktu saat ini dikurangi 30 hari, dan tidak bisa disetel lebih lama dari itu. endTime secara default bernilai sekarang. Jadi endpoint ini adalah jendela satu bulan yang bergulir, bukan sebuah arsip.
Konsekuensinya gamblang. Jika polling job Anda rusak dan tidak ada yang menyadarinya selama lima minggu, pembatalan dari minggu pertama sudah kedaluwarsa dari API. Tidak ada panggilan yang bisa membawanya kembali. Anda tidak akan mencabut pesanan itu, dan Anda bahkan tidak akan tahu bahwa pesanan itu pernah ada kecuali Anda menangkapnya dengan cara lain. API ini adalah jaring pengaman dengan lubang seukuran gangguan terburuk Anda.
Opsi revoke menentukan apakah sebuah pesanan bahkan muncul
Ini adalah alasan paling umum sebuah tim melaporkan API ini rusak. Hanya pesanan yang direvoke yang dikembalikan. Refund yang dimulai pengguna, pembatalan, chargeback, dan refund yang dimulai Google selalu direvoke, jadi selalu muncul. Refund yang dimulai developer berbeda. Ketika Anda merefund sebuah pesanan sendiri, melalui Play Console atau Orders API, Anda memilih apakah juga akan merevoke-nya. Refund tanpa revoke, dan pesanan itu selesai dengan pelanggan tetapi tidak pernah muncul di Voided Purchases API.
Aturan yang mengikutinya sederhana. Jika niat Anda adalah menarik akses, lakukan refund dengan opsi revoke aktif. Jika tidak, Anda sudah mengembalikan uang dan membiarkan pintu terbuka, dan revocation job Anda, sebaik apa pun ditulis, tidak punya apa pun untuk ditindaklanjuti.
Cara melakukan polling tanpa melampaui kuota
Endpoint ini memiliki rate limit, dan batasnya cukup rendah sehingga loop yang naif akan menabraknya. Anda mendapatkan 6,000 kueri per hari, dihitung dalam Pacific Time, dan tidak lebih dari 30 kueri dalam setiap periode 30 detik. Anggaran itu memadai untuk polling berbasis jendela dan tidak ramah bagi desain satu-permintaan-per-pesanan.
Jendela kueri dan continuation token
maxResults secara default bernilai 1,000, yang juga merupakan batas atasnya. Ketika sebuah jendela memuat lebih dari satu halaman pembatalan, respons membawa sebuah objek tokenPagination dengan nextPageToken. Kirimkan kembali token itu pada panggilan berikutnya untuk menelusuri halaman-halaman. Setel startTime dan endTime untuk membatasi jendela yang Anda pedulikan, telusuri halaman hingga token habis, lalu majukan jendelanya. Pola itu menjaga Anda tetap di dalam batas burst 30 detik dan batas harian sekaligus.
Real-time developer notifications menutup celahnya
Polling setiap hari masih menyisakan hingga satu hari kebutaan, dan jendela 30 hari menghukum celah yang panjang. Real-time developer notifications menghilangkan jeda itu. Google mempublikasikan sebuah VoidedPurchaseNotification ke sebuah topik Cloud Pub/Sub milik Anda pada saat sebuah pembelian dibatalkan, dan backend Anda mengonsumsinya dalam hitungan detik. Pesannya kecil.
| RTDN field | Apa isinya |
|---|---|
| purchaseToken | Token dari pembelian aslinya |
| orderId | Order id untuk transaksi yang dibatalkan, satu yang baru untuk setiap perpanjangan langganan |
| productType | 1 untuk sebuah langganan, 2 untuk sebuah pembelian sekali beli |
| refundType | 1 untuk refund penuh, 2 untuk partial refund berbasis kuantitas |

Berapa biayanya bagi Anda dalam bentuk uang
API ini adalah pipa saluran, tetapi alasan untuk memasangnya adalah tagihan. Setiap pembatalan dalam daftar itu memetakan ke sebuah angka nyata, dan dua di antaranya menjadi lebih mahal.
Tagihan chargeback jatuh ke Anda mulai 3 Agustus 2026
Mulai 3 Agustus 2026, Google mengalihkan biaya sebuah chargeback ke developer. Anda kehilangan harga pembelian dan Anda membayar biaya chargeback bank di atasnya. voidedReason bernilai 7 tidak lagi sekadar penjualan yang hilang, itu adalah sebuah item baris dengan biaya yang menyertainya. Anda tidak bisa membalikkan sebuah chargeback, itu final di pihak bank, tetapi Anda bisa menghentikan pendarahan setelahnya. Menangkap pembatalan dengan cepat memungkinkan Anda mencabut entitlement dan, untuk apa pun yang masih Anda kirimkan, berhenti membelanjakan untuk pelanggan yang direfund lalu dibalikkan.
Anda terus membayar untuk melayani pelanggan yang sudah direfund
Harga pembelian lenyap begitu sebuah pembatalan muncul. Yang masih Anda kendalikan adalah biaya untuk terus memberikan layanan. Setiap jam sebuah entitlement yang direfund tetap aktif, Anda terus membayar untuk hal-hal yang tidak lagi didanai pelanggan: komputasi, panggilan API model, penyimpanan, dan pembayaran kreator atau mitra apa pun yang terkait dengan penggunaan mereka. Sebuah sistem pencabutan yang digerakkan oleh API ini adalah cara Anda mematikan meteran itu. Lewati itu, dan Anda mendanai produk untuk orang-orang yang sudah dipulihkan oleh toko.
Friendly fraud adalah pola yang layak ditelusuri trennya
voidedReason bernilai 5 atau 6 bukan kejadian sekali saja. Fraud dan friendly fraud mengelompok berdasarkan akun, berdasarkan perangkat, dan terkadang berdasarkan promosi. API memberi Anda voidedSource dan voidedReason pada setiap pembatalan, yang cukup untuk menelusuri tren penyalahgunaan berdasarkan akun alih-alih memperlakukan setiap pembalikan sebagai biaya yang terisolasi. Seorang pelanggan yang melakukan chargeback dua kali memberi tahu Anda sesuatu yang tidak disampaikan oleh refund pertama.
Memasangnya dengan cara RefundHalt
Modelnya kecil begitu Anda memegang semua kepingannya. Dengarkan VoidedPurchaseNotification secara real time agar tidak ada yang menunggu satu hari penuh. Panggil Voided Purchases API sebagai sumber kebenaran, dengan kunci orderId agar perpanjangan langganan tidak pernah tertukar. Baca voidedSource dan voidedReason agar sebuah chargeback ditangani berbeda dari sebuah refund penyesalan. Lakukan polling dengan jadwal yang cukup rapat sehingga jendela 30 hari tidak pernah menggigit, dan refund dengan opsi revoke aktif kapan pun niat Anda adalah memutus akses.
Ini adalah bagian yang dijalankan RefundHalt untuk Anda. RefundHalt mengonsumsi notifikasi real-time, merekonsiliasi setiap pembatalan terhadap API, mencabut pesanan yang tepat alih-alih seluruh produk, dan memisahkan sebuah chargeback bank dari sebuah refund biasa sehingga yang mahal ditandai, bukan terkubur. Anda mendapatkan akses yang dicabut dalam hitungan detik dan sebuah catatan tentang siapa yang membatalkan apa dan mengapa, tanpa perlu membangun sendiri sebuah pipeline Pub/Sub dan sebuah polling job.
Pertanyaan yang sering diajukan
- Mengapa pesanan saya yang sudah direfund tidak muncul di Voided Purchases API?
- Karena hanya pesanan yang direvoke yang dikembalikan. Refund pengguna, pembatalan, chargeback, dan refund yang dimulai Google selalu direvoke dan selalu muncul. Refund yang dimulai developer hanya muncul jika Anda juga memilih opsi revoke. Jika Anda merefund sebuah pesanan tanpa merevoke-nya, pesanan itu selesai tetapi tidak terlihat oleh API ini, jadi lakukan refund dengan revoke aktif kapan pun Anda berniat menarik akses.
- Seberapa jauh ke belakang Voided Purchases API menjangkau?
- Tiga puluh hari. Parameter startTime secara default bernilai waktu saat ini dikurangi 30 hari dan tidak bisa disetel lebih lama dari itu, jadi endpoint ini adalah jendela satu bulan yang bergulir alih-alih sebuah arsip. Sebuah pesanan yang dibatalkan yang melewati 30 hari lenyap dari API tanpa cara untuk mengambilnya kembali, itulah sebabnya Anda melakukan polling sesuai jadwal dan mendukungnya dengan notifikasi real-time.
- Haruskah saya menggunakan real-time developer notifications atau Voided Purchases API untuk mencabut akses?
- Gunakan keduanya. VoidedPurchaseNotification tiba dalam hitungan detik dan menyuruh Anda melihat, tetapi panduan Google sendiri adalah memperlakukannya sebagai sinyal, bukan sumber kebenaran. Panggil Voided Purchases API untuk mengonfirmasi keadaan saat ini, lalu cabut akses. Notifikasi menghilangkan jeda, dan API memberi Anda voidedSource dan voidedReason otoritatif untuk ditindaklanjuti.
- Bagaimana cara membedakan sebuah chargeback dari sebuah refund biasa di API?
- Baca field voidedReason. Nilai 7 adalah sebuah chargeback, yang berarti bank pelanggan membalikkan pembayaran, dan 6 adalah friendly fraud. Nilai 1 adalah sebuah refund penyesalan. Ini penting karena mulai 3 Agustus 2026 Google membebankan harga pembelian chargeback dan biaya bank kepada developer, sehingga voidedReason bernilai 7 membuat Anda merugi lebih besar daripada sebuah refund biasa.
- Apakah Voided Purchases API mencakup langganan?
- Ya. Setel parameter type ke 1 untuk mendapatkan baik pembelian dalam aplikasi yang dibatalkan maupun pembelian langganan yang dibatalkan. Default-nya, type 0, hanya mengembalikan pembelian produk dalam aplikasi. Untuk langganan, identifikasi periode yang tepat yang dibatalkan berdasarkan orderId, karena satu purchaseToken mencakup setiap perpanjangan dan sebuah orderId baru dihasilkan untuk setiap transaksi perpanjangan.
Sumber dan bacaan lanjutan
- 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
Autopilot refund untuk App Store dan Google Play
Baca selanjutnya
Tiga notifikasi pengembalian dana App Store tiba setelah Apple memutuskan, dan REFUND_REVERSED mengembalikan penjualan kepada Anda
Apple mengirim empat pesan pengembalian dana melalui App Store Server Notifications V2, dan sebagian besar aplikasi hanya menangani dua. REFUND meminta Anda mencabut, REFUND_DECLINED berarti pertahankan penjualan, dan REFUND_REVERSED mengembalikan penjualan dan meminta Anda memulihkan apa yang telah Anda ambil. Inilah yang dibutuhkan masing-masing.
Setiap permintaan refund Apple kini disertai alasan, dan consumptionRequestReason adalah cara Anda membacanya
Sejak WWDC24, setiap CONSUMPTION_REQUEST dari Apple membawa consumptionRequestReason, yaitu alasan yang dinyatakan sendiri oleh pelanggan mengapa mereka ingin refund. Ada lima nilai, dari UNINTENDED_PURCHASE hingga LEGAL, dan masing-masing seharusnya mengubah apa yang Anda kirim kembali dalam jendela 12 jam Anda. Berikut cara membaca setiap nilainya.