Все статьи
Deep dive7 мин чтения

Уведомление об аннулированной покупке позволяет вашему серверу Google Play отозвать доступ в тот момент, когда происходит возврат средств

Google Play может отправить вашему серверу уведомление об аннулированной покупке в тот момент, когда покупка возвращена, оспорена или аннулирована. Оно несёт purchaseToken, orderId, productType и refundType и означает одно, отозвать доступ. Вот как его прочитать и подключить.

Рабочее место разработчика в сумерках с телефоном, на котором показан отменённый платёж, иллюстрирующее уведомление об аннулированной покупке Google Play, доходящее до сервера

Главное

  • Уведомление об аннулированной покупке это Real-time Developer Notification, которое Google Play отправляет в ваш топик Cloud Pub/Sub в тот момент, когда покупка возвращена, оспорена или иным образом аннулирована. Это push-сигнал, а не то, что нужно запрашивать опросом.
  • Уведомление несёт ровно четыре поля: `purchaseToken`, `orderId`, `productType` и `refundType`. Этого достаточно, чтобы найти точную покупку в вашей базе данных и отозвать привязанное к ней право доступа.
  • `productType` равен `1` для аннулированной подписки и `2` для аннулированной разовой покупки. `refundType` равен `1` для полного возврата и `2` для частичного возврата на основе количества, который применяется только к разовым покупкам с несколькими единицами.
  • Уведомление об аннулированной покупке означает, что клиент уже получил свои деньги обратно. Собственная рекомендация Google, отозвать доступ к связанному контенту, потому что покупатель больше не должен обладать правом доступа.
  • Уведомления об аннулированных покупках выключены, пока вы их не включите. В Play Console в разделе Monetization setup вы выбираете либо подписки плюс все аннулированные покупки, либо это плюс события разовых продуктов. Оба варианта включают аннулированные покупки.
  • Уведомление об аннулированной покупке не является одним из двух процессов возврата, которые запрашивают у вас доказательства. Это уведомление постфактум. Единственные процессы, которые принимают ваш ввод, это CONSUMPTION_REQUEST от Apple с окном в 12 часов и рассмотрение чарджбэка в Google Play через orders.reviewrefund с окном в 24 часа.
  • С August 3, 2026 Google перекладывает на разработчика цену покупки плюс банковскую комиссию за чарджбэк. Уведомление об аннулированной покупке часто становится тем, из чего ваш сервер впервые узнаёт, что аннулирование по чарджбэку состоялось, поэтому его подключение это то, что позволяет вам перестать обслуживать клиента, за которого вам больше не платят.

Возврат средств в Google Play не обязан быть тем, о чём вы узнаёте позже из отчёта. Google Play может отправить вашему серверу уведомление об аннулированной покупке в тот же миг, когда покупка аннулируется, будь то самостоятельный возврат, оформленный покупателем, возврат, предоставленный агентом поддержки, чарджбэк, навязанный банком, или возврат заказа, который вы сами оформили с включённым флагом отзыва. Сообщение крошечное, оно называет точную покупку и несёт одну инструкцию, вернуть право доступа, потому что деньги уже ушли.

Что такое уведомление об аннулированной покупке на самом деле

Уведомление об аннулированной покупке это один из типов Real-time Developer Notifications в Google Play, или RTDN. RTDN это push-канал. Google публикует сообщение в топик Cloud Pub/Sub, которым вы владеете, и ваш бэкенд получает его в считаные мгновения после события, а не узнаёт о нём при следующем плановом опросе. В этом весь смысл уведомления об аннулированной покупке по сравнению со старым путём опроса: вы узнаёте о возврате в момент, когда он происходит, а не часами позже.

Путь опроса по-прежнему существует и по-прежнему важен. Voided Purchases API позволяет вашему серверу запрашивать по вашему собственному расписанию список покупок, которые были аннулированы за некоторый промежуток времени. Эти два способа дополняют друг друга. Уведомление сообщает вам в тот миг, когда одна покупка меняет состояние; API позволяет сверять данные массово и восполнять всё, что оставило бы после себя пропущенное сообщение.

Оно едет внутри Real-time Developer Notification

Уведомление об аннулированной покупке никогда не приходит само по себе. Оно находится внутри обёртки DeveloperNotification, и эта обёртка доставляется в виде единой строки в кодировке base64 в поле data сообщения Pub/Sub. Ваш обработчик декодирует эту строку в JSON, прежде чем сможет что-либо прочитать. Обёртка всегда называет приложение и время события и содержит ровно один объект уведомления из пяти, которые определяет Google. Они взаимоисключающие, поэтому сообщение, несущее voidedPurchaseNotification, не будет нести также событие подписки или разовой покупки.

Поле обёрткиЧто оно содержит
versionВерсия схемы уведомления, например 1.0
packageNameПриложение, которому принадлежит событие, например com.acme.app
eventTimeMillisКогда произошло событие, в миллисекундах с начала эпохи
Один из пяти объектов уведомленияoneTimeProductNotification, subscriptionNotification, voidedPurchaseNotification, pendingRefundReviewNotification или testNotification. В одном сообщении присутствует только один

Четыре поля, которые оно несёт

Уберите обёртку, и само уведомление об аннулированной покупке это четыре поля. Это намеренно скупо. Позиция Google такова, что если всё, что вам нужно, это найти нужную покупку и скорректировать право доступа, этих четырёх достаточно, и вам не нужно обращаться обратно к какому-либо API, чтобы действовать.

ПолеЧто этоКак вы его используете
purchaseTokenТокен, выданный устройству в момент покупки товараВаш первичный ключ. Сопоставьте его с записью о покупке, которую вы сохранили при выдаче права доступа
orderIdИдентификатор заказа, показанный покупателю, например GS.0000-0000-0000Второй, читаемый человеком ключ для поддержки и сверки
productTypeБыла ли аннулированная позиция подпиской или разовой покупкойНаправьте на нужный путь отзыва
refundTypeБыло ли аннулирование полным возвратом или частичным возвратом на основе количестваРешите, отзывать всё или только возвращённое количество

productType сообщает, что было аннулировано

productType это небольшое целое число, и оно определяет, какой из ваших путей отзыва выбрать. Аннулирование подписки должно свернуть продолжающийся доступ; аннулирование разовой покупки просто убирает одно право доступа.

Значение `productType`КонстантаЗначение
1PRODUCT_TYPE_SUBSCRIPTIONБыла аннулирована покупка подписки
2PRODUCT_TYPE_ONE_TIMEБыла аннулирована разовая покупка

refundType сообщает, сколько вернулось

refundType отделяет чистый полный возврат от частичного. Частичный случай узок. Он появляется только тогда, когда у разовой покупки с несколькими единицами возвращена часть, но не всё её количество.

Значение `refundType`КонстантаЗначение
1REFUND_TYPE_FULL_REFUNDПокупка была аннулирована полностью
2REFUND_TYPE_QUANTITY_BASED_PARTIAL_REFUNDБыла аннулирована часть покупки с несколькими единицами

Сначала включите его, иначе оно никогда не придёт

Уведомления об аннулированных покупках по умолчанию не поступают. Вы один раз включаете RTDN в Play Console и направляете его на топик Pub/Sub, которым вы управляете. Переключатель находится в разделе Monetize, затем Monetization setup, в секции Real-time developer notifications в верхней части страницы. Отметьте Enable real-time notifications, затем вставьте полное имя вашего топика в виде projects/{project_id}/topics/{topic_name} и используйте Send Test Message, чтобы убедиться, что канал работает, прежде чем доверять ему.

Переключатель содержимого это место, где люди упускают аннулированные покупки. Оба варианта их включают, поэтому вы не можете случайно отказаться от возвратов, сохранив подписки.

  • Get notifications for subscriptions and all voided purchases. Вы получаете события подписок и каждую аннулированную покупку, но не события покупки разовых продуктов.
  • Get all notifications for subscriptions and one-time products. Вы получаете вышеперечисленное плюс события разовых продуктов, такие как ONE_TIME_PRODUCT_PURCHASED и ONE_TIME_PRODUCT_CANCELED.
Кредитная карта, лежащая лицевой стороной вниз рядом с бумажным чеком, символизирующая аннулированную покупку в Google Play

Во что это обходится вам, в деньгах

Аннулирование это убыток, уже зафиксированный к тому моменту, когда уведомление доходит до вас. Цена продажи ушла, как и всё, что вы потратили на обслуживание этого клиента. Если он генерировал изображения, выполнял вызовы к вашим моделям, использовал хранилище или инициировал выплату третьей стороне, эти затраты были оплачены реальными деньгами и не возвращаются вместе с возвратом. Уведомление не может ничего из этого вернуть. Что оно может сделать, так это остановить кровотечение с этого момента, и в этом вся причина действовать быстро.

Кровотечение сильнее всего на подписках и сильнее всего на чарджбэках. Подписка, которую вы не отозвали, продолжает обходиться вам в обслуживание, месяц за месяцем, для клиента, который больше не платит. А чарджбэк это самый дорогой вид аннулирования. С August 3, 2026 в документации Google указано, что чарджбэк перекладывает на разработчика цену покупки плюс комиссию банка. Уведомление об аннулированной покупке часто оказывается первым местом, где ваши собственные системы узнают, что чарджбэк завершился, поэтому обработчик, который отзывает доступ на месте, это то, что не даёт потерянной продаже превратиться в потерянную продажу плюс недели бесплатного обслуживания.

Как обработать уведомление об аннулированной покупке, шаг за шагом

Проверьте и устраните дубликаты сообщения

  • Убедитесь, что сообщение Pub/Sub пришло от Google и нацелено на топик, который вы настроили, затем декодируйте поле data из base64, чтобы получить JSON DeveloperNotification.
  • Используйте messageId из Pub/Sub для отбрасывания дубликатов. Google предупреждает, что одно и то же уведомление может быть доставлено более одного раза, поэтому относитесь к повторной доставке как к норме и сделайте свой обработчик идемпотентным.
  • Подтверждайте получение сообщения только после того, как надёжно его записали, чтобы сбой в середине обработки не потерял событие.

Найдите покупку

  • Сопоставьте purchaseToken с покупкой, которую вы сохранили, когда впервые выдали право доступа. В качестве запасного варианта используйте orderId для поисков в поддержке и ручной сверки.
  • Прочитайте productType, чтобы выбрать путь отзыва подписки или разовой покупки, и прочитайте refundType, чтобы решить между полным отзывом и частичным.

Отзовите и запишите

  • Удалите право доступа. Для полного возврата отрежьте доступ к товару. Для частичного возврата на основе количества уменьшите выданное количество на возвращённую величину и оставьте остальное нетронутым.
  • Запишите, что вы сделали и когда, с ключами purchaseToken и orderId. Эта запись это то, что позволяет вам ответить на обращение в поддержку позже, и то, что позволяет Voided Purchases API чисто свериться с вашим собственным состоянием.

Где оно находится среди других сигналов о возврате

Уведомление об аннулированной покупке это извещение, а не переговоры. Оно сообщает вам об исходе, который уже решён. Стоит увидеть его рядом с сигналами, с которыми его легко спутать, потому что лишь некоторые из них вообще спрашивают вашу сторону истории.

СигналНаправлениеПринимает ли ваш ввод
Уведомление об аннулированной покупке (RTDN)Google отправляет на ваш серверНет. Оно сообщает об аннулировании, которое уже произошло
Voided Purchases APIВаш сервер запрашивает у GoogleНет. Это список прошлых аннулирований только для чтения
pendingRefundReviewNotification (RTDN)Google отправляет на ваш серверДа, косвенно. Оно отмечает чарджбэк, который вы затем оспариваете через orders.reviewrefund в течение 24 часов
Apple CONSUMPTION_REQUESTApple запрашивает у вашего сервераДа. Вы отвечаете через Send Consumption Information в течение 12 часов

Мысль, за которую стоит держаться, проста. В обоих магазинах есть ровно два процесса возврата, где у разработчика есть право голоса, CONSUMPTION_REQUEST от Apple и рассмотрение чарджбэка в Google Play. Уведомление об аннулированной покупке не относится ни к одному из них. К тому времени, когда оно доходит до вас, решение уже позади, и единственное, что остаётся в ваших руках, это то, насколько быстро вы отзовёте доступ.

Частые вопросы

Что означает уведомление об аннулированной покупке в Google Play?
Оно означает, что покупка была возвращена, оспорена через чарджбэк или иным образом аннулирована, и клиент получил свои деньги обратно. Рекомендация Google, отозвать доступ к связанному контенту, потому что покупатель больше не должен обладать правом доступа. Уведомление называет точную покупку через её `purchaseToken` и `orderId`.
Какие поля содержит уведомление об аннулированной покупке Google Play?
Четыре: `purchaseToken`, `orderId`, `productType` и `refundType`. `productType` равен `1` для подписки и `2` для разовой покупки. `refundType` равен `1` для полного возврата и `2` для частичного возврата на основе количества по покупке с несколькими единицами.
Как включить уведомления об аннулированных покупках?
В Play Console откройте Monetize, затем Monetization setup, и в секции Real-time developer notifications отметьте Enable real-time notifications, затем введите имя вашего топика Cloud Pub/Sub. Оба варианта содержимого, подписки плюс все аннулированные покупки, и это плюс события разовых продуктов, включают аннулированные покупки.
В чём разница между уведомлением об аннулированной покупке и Voided Purchases API?
Уведомление это push-сигнал, доставляемый в реальном времени через Cloud Pub/Sub в тот момент, когда покупка аннулируется. Voided Purchases API это путь опроса, к которому ваш сервер обращается по своему собственному расписанию, чтобы перечислить аннулирования за промежуток времени. Используйте уведомление, чтобы реагировать мгновенно, и API, чтобы сверять и восполнять данные.
Позволяет ли уведомление об аннулированной покупке оспорить возврат?
Нет. Это извещение постфактум о решении, которое уже принято. Единственный процесс Google Play, который принимает ваш ввод, это рассмотрение чарджбэка через `orders.reviewrefund`, на который у вас есть 24 часа, чтобы ответить, а у Apple это CONSUMPTION_REQUEST с окном в 12 часов.

Источники и дополнительное чтение

RefundHalt

Автопилот возвратов для App Store и Google Play

Читайте дальше

Playbook7 мин чтения

Вы можете сами вернуть деньги за заказ в Google Play, и сделав это до возвратного платежа, вы сэкономите банковскую комиссию

Вы можете вернуть деньги за любой заказ в Google Play моложе three years одним вызовом API, с отзывом доступа или без него. Сделав это самостоятельно, прежде чем спор превратится в возвратный платеж, вы экономите банковскую комиссию, которая с August 3, 2026 ложится на разработчиков. Вот как работает orders.refund.

Deep dive7 мин чтения

Функция Apple Send Consumption Information теперь запрашивает пять полей, а не двенадцать, и вот каждое из них

Когда клиент запрашивает у Apple возврат средств, полезная нагрузка Send Consumption Information это ваш ответ. Apple сократила её с двенадцати полей до пяти: три обязательных и два необязательных. Здесь каждое поле, значения, которые оно принимает, и 12-часовое окно, в течение которого его нужно отправить.

Следующий запрос на возврат уже в пути.

Настройте RefundHalt за то время, что уходит на чтение очередного письма в поддержку о возврате, который вы не успели оспорить.