Коли покупку в Google Play повертають або оскаржують через chargeback, Voided Purchases API це те, як ви про це дізнаєтесь
Google Play тихо анулює покупку, коли її повертають або оскаржують через chargeback. Voided Purchases API це список таких замовлень, щоб ви могли відкликати доступ. Ось кожне поле, вікно у 30 днів, опція revoke, що приховує замовлення, і скільки це коштує.

Головне
- Voided Purchases API, метод purchases.voidedpurchases.list, повертає замовлення, які Google Play скасував, повернув або оскаржив через chargeback, щоб ви могли побудувати систему відкликання, яка відрізає доступ до того, чим клієнт більше не володіє.
- З'являються лише відкликані замовлення. Повернення, здійснене розробником без опції revoke, невидиме для цього API, тож якщо ви хочете забрати доступ, вам потрібно робити повернення з увімкненою опцією revoke.
- Вікно становить 30 днів. startTime не може бути старішим за 30 днів тому, тож сервер, який не працює довше місяця, назавжди втрачає ці анульовані замовлення. Опитуйте за розкладом.
- voidedSource каже вам, хто анулював замовлення: 0 це користувач, 1 це розробник, 2 це Google. voidedReason каже вам чому, від 0 Other до 7 Chargeback і 8 Unacknowledged_purchase.
- Real-time developer notifications надсилають VoidedPurchaseNotification тієї миті, коли покупку анульовано, але ставтеся до цього як до сигналу. Викликайте Voided Purchases API за авторитетним списком, перш ніж відкликати.
- Ідентифікуйте поновлення підписки за orderId, а не за purchaseToken. Один purchaseToken охоплює кожне поновлення підписки, тож самого токена недостатньо, щоб відрізнити два поновлення.
- Квоти становлять 6,000 запитів на день і 30 запитів у будь-якому 30-секундному вікні, тож гортайте результати за допомогою continuation token і робіть запити за часовим вікном, ніколи не один виклик на замовлення.
Повернення коштів у Google Play не стукає до ваших дверей. Гроші рухаються, клієнт тримає застосунок відкритим, і якщо ви не підете шукати, у вас нічого не зміниться. Voided Purchases API це те місце, куди ви йдете шукати. Він видає вам список замовлень, які були скасовані, повернені або оскаржені через chargeback, щоб ви могли відкликати доступ до того, за що клієнт більше не платить. Спрямуйте на нього заплановане завдання, прочитайте список, обріжте право доступу. Це весь цикл.
Є одна пастка, яка збиває з пантелику більшість команд, і вона не в коді. Тут з'являються лише замовлення, які були відкликані. Якщо ви повертаєте покупку в Play Console, не поставивши галочку опції revoke, це замовлення ніколи не досягне цього API, і ваше завдання відпрацює чисто, поки клієнт із поверненням зберігає все, що ви йому продали. Ця стаття проходить API поле за полем, числа, що його обмежують, і місця, де витікають гроші, коли ви це пропускаєте.
Що насправді повертає Voided Purchases API
API відповідає на одне питання: які замовлення для цього застосунку були анульовані нещодавно. Анулювання охоплює три результати, що всі закінчуються тим, що клієнт отримує свої гроші назад. Скасування, повернення або chargeback. Воно застосовується до одноразових продуктів у застосунку та до підписок, і ви обираєте обсяг одним параметром. Встановіть type на 0, і ви отримаєте лише анульовані покупки продуктів у застосунку, це значення за замовчуванням. Встановіть його на 1, і ви отримаєте анульовані покупки в застосунку та анульовані покупки підписок разом.
Кожен запис у списку це об'єкт анульованої покупки. Полів небагато, і кожне з них має значення.
Поля анульованої покупки
| Поле | Що воно містить |
|---|---|
| orderId | Ідентифікатор замовлення, що унікально визначає одноразову покупку, покупку підписки або одне поновлення підписки. Це ваш ключ для join |
| purchaseToken | Токен, що ідентифікує одноразову покупку або підписку. Він не розрізняє поновлення, тож для них використовуйте orderId |
| purchaseTimeMillis | Коли покупку було здійснено, у мілісекундах від епохи |
| voidedTimeMillis | Коли покупку було скасовано, повернено або оскаржено через chargeback, у мілісекундах від епохи |
| voidedSource | Хто ініціював анулювання: 0 користувач, 1 розробник, 2 Google |
| voidedReason | Чому покупку було анульовано, ціле число від 0 до 8 |
| voidedQuantity | Анульована кількість від часткового повернення на основі кількості, повертається лише коли includeQuantityBasedPartialRefund дорівнює true |
Прочитайте voidedReason, перш ніж діяти
voidedReason це поле, що перетворює сирий список на рішення. Повернення через каяття покупця і chargeback від банку обидва потрапляють до одного списку, але це не одна й та сама подія, і серпневе ціноутворення робить одне з них дорогим. Ось повний набір.
| voidedReason | Label | Що це означає для вас |
|---|---|---|
| 0 | Other | Категорію не призначено. Відкличте і рухайтеся далі |
| 1 | Remorse | Покупець передумав. Звичайне повернення |
| 2 | Not_received | Клієнт каже, що ніколи не отримав продукт. Варто перевірити вашу доставку |
| 3 | Defective | Продукт не працював. Сигнал якості, зафіксуйте його |
| 4 | Accidental_purchase | Ненавмисна покупка, часто зі спільного пристрою |
| 5 | Fraud | Google позначив транзакцію як шахрайську |
| 6 | Friendly_fraud | chargeback, коли законний власник картки оскаржує платіж, який він сам здійснив |
| 7 | Chargeback | Банк клієнта скасував платіж. Остаточно з банком, і тепер виставляється вам |
| 8 | Unacknowledged_purchase | Google автоматично повернув кошти за покупку, яку ваш застосунок так і не підтвердив (acknowledge) |
Вікно у 30 днів це пастка, що спорожнює ваш список
Voided Purchases API може показувати лише анульовані покупки за останні 30 днів. Параметр startTime за замовчуванням дорівнює поточному часу мінус 30 днів, і його не можна встановити старішим за це. endTime за замовчуванням дорівнює зараз. Тож ця кінцева точка це рухоме одномісячне вікно, а не архів.
Наслідок прямолінійний. Якщо ваше завдання опитування зламається і ніхто цього не помітить п'ять тижнів, анулювання з першого тижня випадуть з API за давністю. Немає виклику, який поверне їх назад. Ви не відкличете ті замовлення, і ви навіть не знатимете, що вони існували, якщо не зафіксували їх якимось іншим способом. API це страхувальна сітка з діркою розміром із ваш найгірший збій.
Опція revoke вирішує, чи взагалі з'явиться замовлення
Це найпоширеніша причина, чому команда повідомляє, що API зламаний. Повертаються лише відкликані замовлення. Повернення, ініційовані користувачем, скасування, chargeback і повернення, ініційовані Google, завжди відкликаються, тож вони завжди з'являються. Повернення, ініційоване розробником, це інша річ. Коли ви повертаєте замовлення самі, через Play Console або Orders API, ви обираєте, чи також відкликати його. Поверніть без revoke, і замовлення врегульоване з клієнтом, але ніколи не спливає у Voided Purchases API.
Правило, що з цього випливає, просте. Якщо ваш намір забрати доступ, робіть повернення з увімкненою опцією revoke. Інакше ви віддали гроші і залишили двері відчиненими, а вашому завданню відкликання, хоч би як добре воно було написане, немає над чим працювати.
Як опитувати його, не зачепивши квоту
Кінцева точка має обмеження швидкості, і ліміти достатньо низькі, щоб наївний цикл їх досяг. Ви отримуєте 6,000 запитів на день, що рахуються за тихоокеанським часом, і не більше 30 запитів у будь-який 30-секундний період. Цього бюджету достатньо для віконного опитування і він ворожий до дизайнів один запит на замовлення.
Вікна запитів і continuation token
maxResults за замовчуванням дорівнює 1,000, що також є стелею. Коли вікно містить більше однієї сторінки анулювань, відповідь несе об'єкт tokenPagination із nextPageToken. Передайте цей токен назад у наступному виклику, щоб пройти сторінки. Встановіть startTime і endTime, щоб обмежити вікно, яке вас цікавить, гортайте, доки токен не закінчиться, потім просувайте вікно. Цей шаблон тримає вас у межах як 30-секундного ліміту сплеску, так і денної межі.
Real-time developer notifications закривають розрив
Опитування щодня все одно залишає до доби сліпоти, а вікно у 30 днів карає за довгі проміжки. Real-time developer notifications усувають затримку. Google публікує VoidedPurchaseNotification у Cloud Pub/Sub topic, яким ви володієте, тієї миті, коли покупку анульовано, і ваш бекенд споживає його за лічені секунди. Повідомлення маленьке.
| Поле RTDN | Що воно містить |
|---|---|
| purchaseToken | Токен з початкової покупки |
| orderId | Ідентифікатор замовлення для анульованої транзакції, новий на кожне поновлення підписки |
| productType | 1 для підписки, 2 для одноразової покупки |
| refundType | 1 для повного повернення, 2 для часткового повернення на основі кількості |

У що це вам обходиться у грошах
API це сантехніка, але причина під'єднати його це рахунок. Кожне анулювання в тому списку відповідає реальному числу, і два з них стають дорожчими.
Рахунок за chargeback лягає на вас із 3 серпня 2026 року
Починаючи з 3 серпня 2026 року, Google перекладає вартість chargeback на розробника. Ви втрачаєте ціну покупки і зверху сплачуєте банківську комісію за chargeback. voidedReason зі значенням 7 більше не просто втрачений продаж, це рядок витрат із прикріпленою комісією. Ви не можете скасувати chargeback, він остаточний з банком, але ви можете зупинити кровотечу після нього. Швидке виявлення анулювання дозволяє вам відкликати право доступу і, для всього, що ви ще доставляєте, припинити витрати на клієнта, якому повернули кошти, а потім скасували платіж.
Ви продовжуєте платити за обслуговування клієнта, якому повернули кошти
Ціна покупки зникає тієї миті, коли з'являється анулювання. Що ви ще контролюєте, це вартість подальшої доставки. Кожну годину, доки право доступу з поверненням залишається активним, ви продовжуєте платити за речі, які клієнт більше не фінансує: обчислення, виклики API моделі, сховище і будь-яку виплату творцю чи партнеру, прив'язану до його використання. Система відкликання, керована цим API, це те, як ви вимикаєте той лічильник. Пропустіть її, і ви фінансуєте продукт для людей, з якими магазин уже розрахувався.
Friendly fraud це патерн, за яким варто стежити
voidedReason зі значенням 5 або 6 не є одноразовим. Fraud і friendly fraud групуються за обліковим записом, за пристроєм, а іноді за промоакцією. API дає вам voidedSource і voidedReason на кожному анулюванні, чого достатньо, щоб відстежувати зловживання за обліковим записом, замість того щоб трактувати кожне скасування як окрему витрату. Клієнт, який робить chargeback двічі, каже вам щось, чого не сказало перше повернення.
Як під'єднати це способом RefundHalt
Модель невелика, коли ви тримаєте всі частини. Слухайте VoidedPurchaseNotification у реальному часі, щоб ніщо не чекало цілу добу. Викликайте Voided Purchases API як джерело істини, прив'язане до orderId, щоб поновлення підписок ніколи не плуталися. Читайте voidedSource і voidedReason, щоб chargeback оброблявся інакше, ніж повернення через каяття. Опитуйте за розкладом, достатньо щільним, щоб вікно у 30 днів ніколи не кусало, і робіть повернення з увімкненою опцією revoke щоразу, коли ваш намір відрізати доступ.
Це та частина, яку RefundHalt виконує за вас. Він споживає повідомлення в реальному часі, звіряє кожне анулювання з API, відкликає точне замовлення, а не весь продукт, і відділяє банківський chargeback від звичайного повернення, щоб дорогі були позначені, а не поховані. Ви отримуєте доступ, відкликаний за секунди, і запис про те, хто що і чому анулював, без потреби самостійно розгортати конвеєр Pub/Sub і завдання опитування.
Поширені запитання
- Чому мої повернені замовлення не показуються у Voided Purchases API?
- Бо повертаються лише відкликані замовлення. Повернення користувачів, скасування, chargeback і повернення, ініційовані Google, завжди відкликаються і завжди з'являються. Повернення, ініційоване розробником, з'являється лише якщо ви також обрали опцію revoke. Якщо ви повернули замовлення без відкликання, замовлення врегульоване, але невидиме для цього API, тож робіть повернення з увімкненим revoke щоразу, коли маєте намір забрати доступ.
- Наскільки далеко назад сягає Voided Purchases API?
- Тридцять днів. Параметр startTime за замовчуванням дорівнює поточному часу мінус 30 днів і не може бути встановлений старішим за це, тож кінцева точка це рухоме одномісячне вікно, а не архів. Анульоване замовлення, яке за давністю переходить межу 30 днів, зникає з API без способу його отримати, ось чому ви опитуєте за розкладом і підкріплюєте це real-time notifications.
- Чи слід використовувати real-time developer notifications, чи Voided Purchases API, щоб відкликати доступ?
- Використовуйте обидва. VoidedPurchaseNotification надходить за лічені секунди і каже вам подивитися, але власна настанова Google це ставитися до нього як до сигналу, а не джерела істини. Викликайте Voided Purchases API, щоб підтвердити поточний стан, потім відкликайте. Повідомлення усуває затримку, а API дає вам авторитетні voidedSource і voidedReason, щоб діяти.
- Як мені відрізнити chargeback від звичайного повернення в API?
- Прочитайте поле voidedReason. Значення 7 це chargeback, що означає, що банк клієнта скасував платіж, а 6 це friendly fraud. Значення 1 це повернення через каяття. Це важливо, бо з 3 серпня 2026 року Google передає розробнику ціну покупки за chargeback і банківську комісію, тож voidedReason зі значенням 7 коштує вам більше, ніж звичайне повернення.
- Чи охоплює Voided Purchases API підписки?
- Так. Встановіть параметр type на 1, щоб отримати як анульовані покупки в застосунку, так і анульовані покупки підписок. За замовчуванням, type 0, повертає лише покупки продуктів у застосунку. Для підписок ідентифікуйте точний анульований період за orderId, бо один purchaseToken охоплює кожне поновлення, а для кожної транзакції поновлення генерується новий orderId.
Джерела та додаткове читання
- 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
Автопілот повернень для App Store і Google Play
Читайте далі
Три сповіщення про повернення коштів у App Store надходять після рішення Apple, а REFUND_REVERSED повертає продаж назад
Apple надсилає чотири повідомлення про повернення коштів через App Store Server Notifications V2, і більшість застосунків обробляють лише два. REFUND каже відкликати доступ, REFUND_DECLINED означає зберегти продаж, а REFUND_REVERSED повертає продаж назад і просить відновити те, що ви забрали. Ось що вимагає кожне з них.
Кожен запит на повернення від Apple тепер має причину, а consumptionRequestReason це те, як її прочитати
Від WWDC24 кожен запит Apple CONSUMPTION_REQUEST несе consumptionRequestReason, тобто зазначену самим клієнтом причину бажання отримати повернення. Є п'ять значень, від UNINTENDED_PURCHASE до LEGAL, і кожне має змінювати те, що ви надсилаєте у відповідь у своєму вікні 12 годин. Ось як прочитати кожне з них.