Все статьи
Подробный разбор8 мин чтения

Возврат через Advanced Commerce API остаётся единственным способом, которым iOS-разработчик может инициировать возврат, и окончательное решение всё равно за Apple

Большинство iOS-разработчиков не могут вернуть деньги клиенту. Приложения на Advanced Commerce API от Apple могут запросить возврат, отозвать подписку или вернуть произвольную сумму. Разбираем, как работает каждый endpoint, в чём Apple всё ещё может отказать и где теряются деньги.

Женщина за столом в домашнем кабинете просматривает на iPad рядом с ноутбуком большую библиотеку аудиокниг и курсов. Это приложение с большим каталогом, которое может отправить Apple запрос на возврат через Advanced Commerce API

Главное

  • В июне 2026 года инженер Apple заявил, что разработчик не может напрямую оформить возврат за обычную покупку в App Store. Единственное, что может сделать разработчик, это отправить данные о потреблении и refundPreference в ответ на CONSUMPTION_REQUEST.
  • Приложения, одобренные для Advanced Commerce API от Apple, получают endpoint Request Transaction Refund, который просит App Store вернуть деньги за разовый платёж или транзакцию подписки, а также endpoints Revoke Subscription и Cancel a Subscription.
  • Чтобы вызывать endpoints Advanced Commerce API для возврата, отзыва и отмены, Account Holder разработчика должен подписать Advanced Commerce API Addendum. По словам Apple, если последняя версия не принята, вызов вернёт ошибку.
  • Endpoint Request Transaction Refund принимает refundType со значением FULL, PRORATED или CUSTOM, а refundAmount в тысячных долях денежной единицы допускается только с CUSTOM. По словам Apple, сумма должна включать налог во всех регионах, кроме Канады и США.
  • Поле refundRiskingPreference по умолчанию равно true. Это позволяет App Store отправить CONSUMPTION_REQUEST по запросу на возврат, который подал сам разработчик. Apple просит ответить в течение 12 часов.
  • Endpoints Advanced Commerce API для возврата, отзыва и отмены ограничены в продакшене 5 запросами в секунду на приложение, а в sandbox доступно 10 процентов от этого лимита.
  • После успешного вызова Revoke Subscription Apple отправляет уведомление REFUND и предписывает прекращать доступ с даты revocationDate, но не раньше, чем придёт уведомление.

Обычные iOS-разработчики не могут вернуть деньги клиенту. В июне 2026 года App Store Commerce Engineer ответил на вопрос на форуме разработчиков одной фразой: в настоящее время разработчик не может напрямую оформить возврат. Есть одно исключение, и оно находится внутри Advanced Commerce API. Приложения, которые Apple к нему допускает, могут отправить запрос на возврат через Advanced Commerce API, отозвать подписку с возвратом денег или запросить произвольную сумму. Переводить ли деньги, по-прежнему решает Apple.

Что такое Advanced Commerce API и кто его получает

Apple выпустила Advanced Commerce API 23 января 2025 года. Он обрабатывает встроенные покупки Apple для исключительно больших каталогов: произвольных разовых покупок, подписок и подписок с дополнительными опциями. Вы не создаёте каждый продукт в App Store Connect. Вы определяете SKU на своём сервере и передаёте их Apple в момент покупки.

Доступ выдаётся отдельно для каждого приложения. Вы заполняете форму заявки, а страница Apple о соответствии требованиям называет три бизнес-модели, которые должны быть основой приложения:

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

Apple также разрешает подать заявку, если API требуется для другой программы. Его требует Mini Apps Partner Program, которая выплачивает участникам 85% от соответствующих продаж встроенных покупок в размещённых мини-приложениях.

Endpoints для возвратов появились позже, и для них нужна подпись

Версия 1.1 от 24 марта 2025 года добавила Request Transaction Refund и Revoke Subscription. Страница программы Apple говорит, что приложения с контентом по подписке также могут получить право на API Cancel, Revoke и Refund, чтобы обрабатывать отмены, проверять контент после покупки и управлять каталогами. Страница каждого endpoint добавляет одно и то же условие: ваш Account Holder должен подписать Advanced Commerce API Addendum, а если последняя версия не принята, вызов вернёт ошибку. Сценарии использования каждого endpoint перечислены в Addendum, а не в документации.

Три endpoint рядом

Cancel a SubscriptionRevoke SubscriptionRequest Transaction Refund
ПутьadvancedCommerce/v1/subscription/cancel/{transactionId}advancedCommerce/v1/subscription/revoke/{transactionId}advancedCommerce/v1/transaction/requestRefund/{transactionId}
ОхватАвтопродлеваемые подпискиПодписка и все её позицииРазовые платежи и транзакции подписок
Возврат денегНетFULL или PRORATEDFULL, PRORATED или CUSTOM, по каждому SKU
ДоступСохраняется до конца периодаПрекращается в revocationDateЗадаётся для каждой позиции флагом revoke
Лимит в продакшене5 в секунду5 в секунду5 в секунду

Cancel a Subscription останавливает следующее списание

Cancel отключает автопродление. По словам Apple, клиент сохраняет доступ до конца текущего периода. Ничего не возвращается. Это правильный вызов, когда клиент хочет уйти и уже использовал оплаченное время.

Revoke Subscription прекращает всё сразу

Revoke устанавливает автопродление в false и отзывает подписку с полным или пропорциональным возвратом. Тело запроса содержит refundReason, refundRiskingPreference, refundType и requestInfo. Затем Apple отправляет уведомление REFUND на ваш endpoint App Store Server Notifications V2. Указание Apple конкретное: отключайте доступ с даты revocationDate из этого уведомления и не отключайте его до того, как уведомление придёт.

Request Transaction Refund работает по позициям

Это точный инструмент. Вы отправляете список позиций, и в каждой указаны SKU, refundReason, refundType и флаг revoke. С CUSTOM вы также передаёте refundAmount в тысячных долях денежной единицы, то есть 4990 означает 4,99. Если отправить сумму с FULL или PRORATED, Apple отклонит запрос с ошибкой 4000155. Ответ содержит подписанную транзакцию, а для подписок ещё и подписанные данные о продлении.

Apple принимает такие значения refundReason: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL, OTHER и MODIFY_ITEMS_REFUND. Седьмое значение, SIMULATE_REFUND_DECLINE, предназначено только для тестирования в sandbox и TestFlight. Оно существует потому, что App Store может отказать.

Apple может отклонить даже ваш собственный запрос на возврат

Название endpoint честное. Это запрос. Два поля показывают, где на самом деле принимается решение.

refundRiskingPreference открывает дорогу проверке потребления

Apple описывает refundRiskingPreference как признак того, запросит ли App Store у вас данные о потреблении для решения о возврате. По умолчанию значение true. Если оно true, вы получаете CONSUMPTION_REQUEST по собственному запросу на возврат и отвечаете через Send Consumption Information. Apple просит разработчиков ответить в течение 12 часов после получения CONSUMPTION_REQUEST. Установите false, и это уведомление не придёт.

Ошибки, которые означают отказ

ОшибкаКодЧто говорит Apple
AlreadyRefundedError4030021По транзакции уже сделан возврат
PendingRefundError4000181По транзакции есть ожидающие возвраты
TransactionNotRefundableError4030024Транзакция не подлежит возврату
TransactionCannotBeRefundedContactSupportError4030025Клиент может обратиться в Apple Support
RefundAmountWithoutCustomError4000155Сумма отправлена без CUSTOM

К PendingRefundError нужно готовиться заранее. Вероятная причина: клиент уже обратился к Apple через Report a Problem до того, как отреагировала ваша поддержка. Правила Apple и так требуют, чтобы у этих приложений был путь к возврату внутри приложения, ссылка Report a Problem или API beginRefundRequest, поэтому обе двери открыты одновременно.

Разработчик держит iPhone над распечатанным журналом транзакций и проверяет, какую позицию должен покрыть возврат через Advanced Commerce API

Во сколько вам обходится возврат через Advanced Commerce API

Вернуть деньги по своей инициативе кажется дешевле, чем спорить. Но это всё равно расход, а API позволяет легко повторять некоторые ошибки в больших масштабах.

Налог внутри произвольной суммы

По словам Apple, запрошенный refundAmount должен включать налог во всех регионах, кроме Канады и США. Команда, которая рассчитывает возврат CUSTOM от цены SKU без налога, недоплатит клиентам во всех остальных витринах, а потом потратит время поддержки на исправление каждого случая.

Расходы, которые не возвращаются

  • Выплаты: в каталоге авторов или у хоста мини-приложений доля автора часто выплачивается при продаже. Возврат клиенту её не вернёт.
  • Лицензии на контент: отчисления правообладателю за аудиокнигу или курс могут, в зависимости от договора, начисляться уже при доступе, и возврат их не отменяет.
  • Вычисления: стриминг, транскодирование и вся серверная работа по покупке уже в вашем счёте.
  • Вызовы API: сторонние сервисы с оплатой за запрос, от распознавания речи до инференса моделей, остаются оплаченными после возврата.

Полный возврат, когда имелась в виду одна позиция

Revoke Subscription возвращает деньги и прекращает всю подписку вместе с дополнительными опциями. Если клиент оспаривает только одну опцию, Request Transaction Refund позволяет вернуть только этот SKU, с флагом revoke лишь для этой позиции. Вызов Revoke Subscription из-за жалобы на одну позицию возвращает и выручку за базовый тариф.

Чек-лист перед включением

  • Убедитесь, что ваш Account Holder принял текущую версию Advanced Commerce API Addendum, и настройте оповещение на ошибку, которая приходит, когда принятие истекает.
  • Генерируйте новый requestReferenceId в формате UUID для каждого запроса и используйте тот же повторно только при повторе вызова, завершившегося по тайм-ауту.
  • Ставьте вызовы возвратов в очередь. Лимит составляет 5 в секунду на приложение, а ответ 429 содержит заголовок Retry-After в миллисекундах UNIX.
  • Тестируйте отказы в sandbox с SIMULATE_REFUND_DECLINE и помните, что лимиты sandbox составляют 10 процентов от продакшена.
  • Решайте вопрос с refundRiskingPreference в каждом случае отдельно и держите наготове обработчик данных о потреблении на 12-часовое окно, если значение остаётся true.
  • Прекращайте доступ только после прихода уведомления REFUND, с его revocationDate.
  • Записывайте причину, сумму и SKU каждого запроса, чтобы видеть собственную долю возвратов раньше, чем её увидит Apple.

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

Может ли iOS-разработчик напрямую вернуть деньги клиенту?
Не за обычную покупку в App Store. В июне 2026 года инженер Apple заявил, что разработчик не может напрямую оформить возврат. Приложения, одобренные для Advanced Commerce API и подписавшие Addendum, могут запросить его через endpoint Request Transaction Refund, но решение всё равно принимает Apple.
Чем Cancel отличается от Revoke в Advanced Commerce API?
Cancel отключает автопродление, и клиент сохраняет доступ до конца периода, без возврата. Revoke сразу прекращает подписку и все её позиции и возвращает полную или пропорциональную сумму. После Revoke Apple отправляет уведомление REFUND.
Можно ли вернуть произвольную сумму через Advanced Commerce API?
Да. Установите refundType в CUSTOM и передайте refundAmount в тысячных долях денежной единицы. По словам Apple, сумма должна включать налог во всех регионах, кроме Канады и США, а отправка суммы с FULL или PRORATED возвращает ошибку 4000155.
Получу ли я CONSUMPTION_REQUEST по возврату, который запросил сам?
Можете получить. refundRiskingPreference по умолчанию равно true, поэтому App Store может запросить у вас данные о потреблении через CONSUMPTION_REQUEST, и Apple просит ответить в течение 12 часов. Установите false, и, по словам Apple, это уведомление не будет отправлено.
Почему мой запрос на возврат через Advanced Commerce API не прошёл?
Проверьте код ошибки. 4030021 означает, что по транзакции уже сделан возврат, 4000181 означает, что возврат уже ожидает обработки, 4030024 означает, что транзакция не подлежит возврату, а 4030025 означает, что клиенту следует обратиться в Apple Support. Неподписанный или устаревший Addendum тоже приводит к ошибке.

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

RefundHalt

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

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

Руководство8 мин чтения

Чрезмерные запросы на возврат обходятся дороже самих возвратов: оба магазина приложений считают их сигналом качества

Правило 5.6.4 Apple прямо называет чрезмерные запросы на возврат признаком того, что приложение не соответствует стандартам качества, а соглашение Google о распространении позволяет удалять приложения новых разработчиков по доле возвратов. Разбираем, что пишет каждый магазин, во что обходится удаление и как не попасть под удар.

Подробный разбор8 мин чтения

Проверяйте серверные уведомления App Store, прежде чем реагировать на возврат, ведь отправить запрос на ваш URL вебхука может кто угодно

Уведомление о возврате остается обычным HTTPS-запросом, пока вы не проверили его подпись. Рассказываем, как проверять серверные уведомления App Store и сообщения RTDN из Google Play, что подписывает каждый магазин и во что обходится поддельный или ошибочно отклоненный возврат.

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

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