Теперь каждый запрос на возврат от Apple приходит с причиной, и consumptionRequestReason показывает, как её прочитать
Начиная с WWDC24, каждый Apple CONSUMPTION_REQUEST несёт consumptionRequestReason, собственную заявленную причину клиента, по которой он хочет возврат. Значений пять, от UNINTENDED_PURCHASE до LEGAL, и каждое должно менять то, что вы отправляете в ответ в течение вашего 12-часового окна. Вот как прочитать каждое из них.

Главное
- Начиная с версии 2.11 App Store Server Notifications, представленной на WWDC24, каждое уведомление CONSUMPTION_REQUEST включает consumptionRequestReason, строку, которая указывает, почему клиент запросил возврат.
- Значений ровно пять: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL и OTHER. Apple отправляет по одному на запрос.
- Причина не решает исход возврата. Это контекст, который вы используете, чтобы выбрать свой refundPreference и данные о потреблении до закрытия 12-часового окна.
- CONSUMPTION_REQUEST теперь срабатывает и для автопродляемых подписок, а не только для расходуемых товаров, поэтому consumptionRequestReason достигает гораздо большего числа ваших возвратов, чем до WWDC24.
- Причина FULFILLMENT_ISSUE это сигнал о том, что ваша собственная доставка могла дать сбой. Оспаривание сжигает окно и приглашает чарджбэк позже. Удовлетворить его обычно дешевле.
- Вы отвечаете, вызывая Send Consumption Information в течение 12 часов с customerConsented, установленным в true, и refundPreference из GRANT_FULL, GRANT_PRORATED или DECLINE. Apple трактует ваше предпочтение как один из входных сигналов, а не как команду.
- Возврат всё равно стоит вам вычислений, вызовов API, хранилища и выплат, которые покупка уже израсходовала. Поле причины это способ тратить свою защиту только на те случаи, что стоит защищать.
Apple изменила то, как запросы на возврат попадают на ваш сервер, и множество разработчиков этого не заметили. Начиная с обновления App Store Server Notifications 2.11, представленного на WWDC24, каждое уведомление CONSUMPTION_REQUEST несёт поле под названием consumptionRequestReason. Это собственная заявленная причина клиента, по которой он просит вернуть деньги. Одна простая строка, пять возможных значений, доставленная внутри того же самого пакета, на который у вас уже есть двенадцать часов, чтобы ответить.
Причина запроса на возврат Apple сама по себе ничего не решает. Она сообщает вам, в какой из пяти очень разных ситуаций вы находитесь, чтобы вы перестали отправлять одни и те же типовые данные о потреблении и на возврат, который следует удовлетворить, и на возврат, который следует оспорить. Вот что это за поле, точные значения, которые может прислать Apple, что сигнализирует каждое из них и как оно должно менять предпочтение и доказательства, которые вы возвращаете.
Что такое consumptionRequestReason на самом деле
consumptionRequestReason это строковое поле в объекте data уведомления CONSUMPTION_REQUEST. Apple добавила его в версии 2.11 App Store Server Notifications, вместе с изменениями процесса возврата на WWDC24. До этого запрос приходил с подписанной транзакцией и без единого слова о мотиве. Вы отвечали вслепую. Теперь заявленная причина клиента путешествует вместе с запросом.
Внимательно прочитайте слово заявленная. Это причина, которую клиент выбрал, когда подавал обращение в Apple, а не факт, проверенный Apple. UNINTENDED_PURCHASE не доказывает, что покупка осталась неиспользованной, а UNSATISFIED_WITH_PURCHASE не доказывает, что продукт был сломан. Значение это линза, а не приговор. Вы по-прежнему сочетаете его с собственными записями о доставке и использовании.
Оно приходит в уведомлении, которое вы уже обрабатываете
CONSUMPTION_REQUEST это единственный процесс Apple, который вообще запрашивает у разработчика доказательства. Его аналог в Google Play это рассмотрение чарджбэка через orders.reviewrefund. Когда такой запрос приходит, у вас есть 12 часов, чтобы ответить, вызвав Send Consumption Information, PUT к эндпоинту потребления транзакций. consumptionRequestReason теперь часть того же самого уведомления, поэтому подписываться на что-то новое не нужно. Если вы уже разбираете CONSUMPTION_REQUEST, эта причина это одно поле, которое вы, скорее всего, игнорировали.
Пять причин и что каждая из них вам говорит
Apple документирует ровно пять значений. На запрос приходит одно. Вот полный набор и то, как читать каждое на практике.
| Значение | Что заявил клиент | Что это обычно означает для вас |
|---|---|---|
| UNINTENDED_PURCHASE | Он не собирался это покупать | Часто случайное или семейное нажатие. Проверьте доставку и потребление, прежде чем решать. |
| FULFILLMENT_ISSUE | Он не смог получить или воспользоваться | Указывает на вашу собственную доставку. Сверьтесь с логами, прежде чем оспаривать. |
| UNSATISFIED_WITH_PURCHASE | Он остался недоволен | Раскаяние покупателя. Здесь ваши доказательства потребления весят больше всего. |
| LEGAL | Он сослался на юридическую причину | Отнеситесь к этому как к удовлетворению. Оспаривать юридический запрос не стоит окна. |
| OTHER | Любая причина, не указанная выше | Сама по себе сигнала не несёт. Опирайтесь на данные о доставке и использовании. |
UNINTENDED_PURCHASE это корзина случайных нажатий
Это причина, которую выбирает родитель после того, как ребёнок купил 10,000 монет, или взрослый, который промахнулся по кнопке подтверждения. Она коррелирует с покупками, которые так и не были открыты или использованы. Именно поэтому важны ваши собственные данные. Если ваши записи показывают, что расходуемый товар был полностью доставлен и активно потреблён, заявление о непреднамеренной покупке и полностью израсходованный баланс не согласуются между собой, и этот разрыв стоит сообщить через consumptionPercentage.
FULFILLMENT_ISSUE указывает на вас
FULFILLMENT_ISSUE это единственная причина, которая отчасти о вашем приложении, а не о клиенте. Она означает, что клиент говорит, что не смог получить или воспользоваться тем, за что заплатил. Прежде чем рефлекторно оспаривать, поднимите свои логи доставки. Если ваш собственный сервер показывает, что право доступа так и не активировалось или кредиты так и не зачислились, клиент прав, и DECLINE это неверное предпочтение. Борьба с реальным сбоем выполнения тратит окно впустую и может подтолкнуть клиента к его банку, где чарджбэк обойдётся дороже, чем обошёлся бы возврат.
UNSATISFIED_WITH_PURCHASE это где решают доказательства
Это обычное раскаяние покупателя, и именно здесь ваши данные о потреблении работают больше всего. Продукт работал. Клиент использовал часть его или всё целиком, а теперь хочет вернуть деньги. Высокий consumptionPercentage, честный deliveryStatus со значением DELIVERED и refundPreference из DECLINE или GRANT_PRORATED это тот аргумент, который Apple просит вас привести. Отправьте цифры, а не доводы.
LEGAL и OTHER
LEGAL означает, что клиент сослался на юридическое или регуляторное право. Разумные люди могут не соглашаться, но как правило это не то окно, чтобы вести тяжбу. Удовлетворите и двигайтесь дальше. OTHER это универсальный вариант, который Apple использует, когда заявленная причина не подходит ни под одну из четырёх выше. Сама по себе она сигнала не несёт, поэтому относитесь к OTHER ровно так же, как к запросу вообще без причины: начните со своего статуса доставки и доказательств использования.

Как причина меняет ваш ответ, поле за полем
Вы отвечаете на CONSUMPTION_REQUEST, вызывая Send Consumption Information с телом ConsumptionRequest. Причина должна формировать три поля в этом теле.
customerConsented должен быть true
Apple принимает отправку только когда customerConsented равен true, то есть клиент согласился поделиться данными о потреблении. Если у вас нет этого согласия, вы вообще не можете отправлять данные, независимо от причины. Нет согласия, нет доказательств, и запрос решается без ваших цифр.
deliveryStatus и consumptionPercentage несут факты
deliveryStatus сообщает, доставили ли вы работающую покупку. Если это что-либо, кроме DELIVERED, Apple требует, чтобы consumptionPercentage был равен 0. Когда вы всё же доставили, consumptionPercentage это целое число в milliunits от 0 до 100,000, где 100,000 означает, что клиент использовал покупку целиком. Эта пара это ваше фактическое ядро, и именно она должна нести дело FULFILLMENT_ISSUE или UNSATISFIED_WITH_PURCHASE, а не сама причина.
refundPreference это ваш единственный рычаг
refundPreference это то, где вы заявляете, чего хотите. Apple документирует три значения: GRANT_FULL, GRANT_PRORATED и DECLINE. Прочитайте причину, взвесьте её относительно своих данных, затем выбирайте. FULFILLMENT_ISSUE с провалившейся доставкой в ваших логах склоняется к GRANT_FULL. UNSATISFIED_WITH_PURCHASE на полностью потреблённом продукте склоняется к DECLINE или GRANT_PRORATED. LEGAL склоняется к GRANT_FULL.
Во что на самом деле обходится вам возврат
Поле причины имеет значение, потому что возврат редко бывает просто вычетом продажи из вашей бухгалтерии. За расходуемый товар, который уже отработал, вы заплатили, чтобы его предоставить. Пакет кредитов, который вызвал платный API инференса, партия сгенерированных изображений, сжегшая время GPU, сохранённый экспорт, который лежит в вашем счёте за хранилище, выплата автору, которую вы уже отправили: эти затраты остаются потраченными, когда покупка отменяется. Магазин возвращает деньги клиенту. Он не возвращает ваши вычисления.
Вот почему причину стоит читать. Допустим, клиент купил 5,000 кредитов, каждый из которых запускает платный вызов API, потратил 4,000 из них, а затем подал обращение под UNSATISFIED_WITH_PURCHASE. Ваш deliveryStatus равен DELIVERED, ваш consumptionPercentage равен 80,000 milliunits, и предпочтение DECLINE или GRANT_PRORATED это разница между тем, чтобы съесть счёт за API и вернуть большую его часть. Теперь смените причину на FULFILLMENT_ISSUE с логами, показывающими, что кредиты так и не зачислились, и честный, более дешёвый ход это GRANT_FULL, прежде чем клиент обострит ситуацию через свой банк.
Как читать причину, не переусердствуя
Ловушка в том, чтобы принимать причину за доказательство. UNINTENDED_PURCHASE это не признание в том, что продукт остался неиспользованным, а LEGAL это не всегда подлинное юридическое требование. Причина сужает ситуацию. Ваши логи доставки и записи о потреблении её разрешают. Когда они согласуются с клиентом, удовлетворяйте рано и дёшево. Когда они противоречат клиенту, это противоречие, выраженное как deliveryStatus и consumptionPercentage, это самое сильное, что вы можете отправить. RefundHalt читает consumptionRequestReason на каждом CONSUMPTION_REQUEST и автоматически сочетает его с вашими реальными данными об использовании, так что каждая причина получает тот ответ, которого заслуживает, внутри 12-часового окна.
Изменение небольшое и его легко пропустить, но оно сдвинуло разговор о возвратах в вашу пользу. Apple теперь говорит вам почему, до того как вы отвечаете. Используйте это.
Частые вопросы
- Что такое consumptionRequestReason?
- consumptionRequestReason это строковое поле, которое Apple включает в каждое уведомление CONSUMPTION_REQUEST, добавленное в версии 2.11 App Store Server Notifications на WWDC24. Оно заявляет собственную причину клиента для запроса возврата, давая вам контекст, прежде чем вы ответите данными о потреблении внутри 12-часового окна.
- Какие возможные значения у consumptionRequestReason?
- Их пять: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL и OTHER. Apple отправляет ровно одно на каждый запрос на возврат. Каждое указывает на разную ситуацию, от случайного нажатия до заявленной юридической причины, и каждое должно формировать refundPreference и данные о потреблении, которые вы отправляете в ответ.
- Решает ли причина возврата, оставлю ли я деньги себе?
- Нет. consumptionRequestReason это контекст, а не приговор. Apple всё равно принимает решение о возврате, взвешивая ваш refundPreference, ваш deliveryStatus и consumptionPercentage, а также историю клиента. Причина подсказывает вам, какое дело выстраивать. А выстраивают его ваши данные о доставке и использовании.
- Сколько времени у меня есть на ответ на CONSUMPTION_REQUEST?
- У вас есть 12 часов с момента получения уведомления CONSUMPTION_REQUEST, чтобы вызвать Send Consumption Information. Вызов должен установить customerConsented в true, иначе Apple его отклонит. Пропустите окно, и возврат решится без каких-либо ваших данных.
- Появляется ли consumptionRequestReason при возвратах по подпискам?
- Да. То же обновление WWDC24, которое добавило consumptionRequestReason, также начало отправлять CONSUMPTION_REQUEST для автопродляемых подписок, а не только для расходуемых товаров. Для большинства приложений это означает, что поле причины теперь достигает возвратов, которые важнее всего с финансовой точки зрения.
Источники и дополнительное чтение
RefundHalt
Автопилот возвратов для App Store и Google Play
Читайте дальше
Разбор возвратного платежа в Google Play дает вам 24 часа на защиту, вот что нужно отправить
Когда банк отзывает платеж в Google Play, Google отправляет на ваш сервер PendingRefundReviewNotification и запускает 24-часовой отсчет. Ответьте через API ReviewRefund с предпочтением по возврату и реальными доказательствами потребления, или спор решится без вас. Вот весь процесс, поле за полем.
Прикрепляйте appAccountToken к каждой покупке в App Store, иначе вы не сможете защитить возврат
Apple присылает вашему серверу CONSUMPTION_REQUEST, когда клиент просит возврат, но в транзакции нет данных о том, кто он. appAccountToken это UUID, который связывает покупку с вашим пользователем. Установите его, и вы сможете ответить Apple реальными данными. Пропустите, и вам останется только гадать.