Потоки событий
В Adapty вы будете получать различные события подписки на протяжении всего пути пользователя в вашем приложении. Приведённые ниже сценарии подписки описывают типичные ситуации и помогают понять, какие события Adapty генерирует при оформлении, отмене или возобновлении подписки.
Обратите внимание, что Apple обрабатывает платежи за подписку за несколько часов до фактического начала или продления. В схемах ниже мы показываем начало/продление подписки и списание средств как одновременные события, чтобы диаграммы были понятнее. Кроме того, события, связанные с одним и тем же действием, происходят одновременно и могут отображаться в вашем Event Feed в произвольном порядке, который может отличаться от последовательности, показанной на наших диаграммах.
Жизненный цикл подписки
Поток первоначальной покупки
Этот поток срабатывает, когда пользователь впервые оформляет подписку без пробного периода. В этом случае создаются следующие события:
- Subscription started
- Access level updated — для предоставления пользователю доступа
Когда наступает дата обновления подписки, она продлевается. При этом создаются следующие события:
- Subscription renewal — для начала нового периода подписки
- Access level updated — для обновления даты истечения подписки и продления доступа ещё на один период Ситуации, когда платёж не прошёл или пользователь отменил продление, описаны в Billing Issue Outcome Flow и Subscription Cancellation Flow соответственно.
Поток отмены подписки
Когда пользователь отменяет подписку, создаются следующие события:
- Subscription renewal canceled — указывает, что подписка остаётся активной до конца текущего периода, после чего пользователь потеряет доступ
- Access level updated — создаётся для отключения автопродления уровня доступа
После окончания подписки срабатывает событие Subscription expired (churned), фиксирующее завершение подписки.
Если возврат средств одобрен, следующее событие заменяет Subscription expired (churned):
- Subscription refunded — завершает подписку и предоставляет информацию о возврате средств
В Stripe подписку можно отменить немедленно, не дожидаясь окончания оплаченного периода. В этом случае все события создаются одновременно:
- Subscription renewal cancelled
- Subscription expired (churned)
- Access Level updated — для отзыва доступа у пользователя Если возврат средств одобрен, также срабатывает событие Subscription refunded.
Поток реактивации подписки
Если пользователь отменяет подписку, она истекает, а затем он повторно покупает ту же подписку, будет создано событие Subscription renewed. Даже если между периодами доступа есть разрыв, Adapty рассматривает это как единую цепочку транзакций, связанных через vendor_original_transaction_id. Поэтому повторная покупка считается продлением.
Событие Access level updated будет создано дважды:
- в момент окончания подписки — чтобы отозвать доступ пользователя
- в момент повторной покупки подписки — чтобы предоставить доступ
Поток приостановки подписки (только Android)
Этот поток применяется, когда пользователь приостанавливает и затем возобновляет подписку на Android.
Приостановка подписки имеет отложенный эффект. Если пользователь приостанавливает подписку до её продления, подписка остаётся активной, и пользователь сохраняет оплаченный доступ до конца расчётного периода.
-
Когда пользователь приостанавливает подписку, срабатывает событие Subscription paused (Android only).
-
По окончании периода подписки Adapty вызывает событие Access level updated, чтобы отозвать доступ пользователя.
-
Когда пользователь возобновляет подписку, срабатывают следующие события:
- Subscription renewed
- Access level updated — для восстановления доступа пользователя
Все эти подписки относятся к одной цепочке транзакций, связанных одним vendor_original_transaction_id.
Потоки пробного периода
Если в вашем приложении используются пробные периоды, вы будете получать дополнительные события, связанные с пробным периодом.
Поток с успешной конвертацией пробного периода
Самый распространённый сценарий: пользователь начинает пробный период, привязывает карту и успешно переходит на обычную подписку по его окончании. В этот момент создаются следующие события:
- Trial started — фиксирует начало пробного периода
- Access level updated — предоставляет доступ
Событие Trial converted создаётся в момент, когда начинается обычная подписка.
Пробный период без успешной конвертации
Если пользователь отменяет пробный период до его конвертации в подписку, в момент отмены создаются следующие события:
- Trial renewal cancelled — отключает автоматическую конвертацию пробного периода в подписку
- Access level updated — отключает продление доступа
Пользователь сохраняет доступ до конца пробного периода, после чего создаётся событие Trial expired, фиксирующее его окончание.
Возобновление подписки после истёкшего пробного периода
Если пробный период завершился (из-за проблем с оплатой или отмены), а пользователь позже оформил подписку, создаются следующие события:
- Access level updated — открывает доступ пользователю
- Trial converted
Даже если между пробным периодом и подпиской прошло время, Adapty связывает их через vendor_original_transaction_id. Это преобразование рассматривается как часть непрерывной цепочки транзакций, начавшейся с пробного периода с нулевой ценой. Именно поэтому создаётся событие Trial converted, а не Subscription started.
Изменения продукта
В этом разделе описаны любые изменения активных подписок: обновления до более дорогого тарифа, переход на более дешёвый или покупка продукта из другой группы.
Немедленная смена продукта
После того как пользователь меняет продукт, изменение может вступить в силу сразу — до окончания текущей подписки (как правило, при апгрейде или замене продукта). В момент такой смены:
- Уровень доступа изменяется, и создаются два события Access level updated:
- для отзыва доступа к первому продукту.
- для предоставления доступа ко второму продукту.
- Старая подписка завершается, и выплачивается возврат средств (создаётся событие Subscription refunded с
cancellation_reason=upgraded). Обратите внимание: событие Subscription expired (churned) при этом не создаётся — его заменяет событие Subscription refunded. - Новая подписка начинается (для нового продукта создаётся событие Subscription started).
Если пользователь понижает уровень подписки, первая подписка продолжается до конца оплаченного периода, а когда она заканчивается, её заменяет новая подписка более низкого уровня. В этом случае сразу создаётся только событие Access level updated, отключающее автопродление доступа. Все остальные события создаются в момент фактической замены подписки:
- Создаётся ещё одно событие Access level updated — чтобы предоставить доступ ко второму продукту.
- Создаётся событие Subscription expired (churned) — чтобы завершить подписку на первый продукт.
- Создаётся событие Subscription started — чтобы начать новую подписку на новый продукт.
Отложенный сценарий смены продукта
Существует также вариант, когда пользователь меняет продукт в момент продления подписки. Этот вариант очень похож на предыдущий: сразу создаётся одно событие Access level updated, которое отключает автопродление доступа для старого продукта. Все остальные события создаются в момент, когда пользователь меняет подписку и это изменение отражается в системе:
- Создаётся ещё одно событие Access level updated, чтобы открыть доступ для второго продукта.
- Создаётся событие Subscription expired (churned), чтобы завершить подписку на первый продукт.
- Создаётся событие Subscription started, чтобы начать новую подписку на новый продукт.
Процесс обработки проблем с оплатой
Если попытка конвертировать триал или продлить подписку завершается неудачей из-за проблем с оплатой, дальнейший ход событий зависит от того, включён ли льготный период.
При наличии льготного периода: если оплата проходит успешно, триал конвертируется или подписка продлевается. Если нет — стор продолжает попытки списать средства, и если они все равно не увенчались успехом, стор завершает триал или подписку самостоятельно.
Таким образом, в момент возникновения проблемы с оплатой в Adapty создаются следующие события:
- Billing issue detected
- Entered grace period (если льготный период включён)
- Access level updated для предоставления доступа до конца льготного периода
Если платёж впоследствии проходит успешно, Adapty фиксирует событие Trial converted или Subscription renewed, и пользователь не теряет доступ.
Если платёж в итоге не проходит и стор отменяет подписку, Adapty генерирует следующие события:
- Trial expired или Subscription expired (churned) с
cancellation_reason: billing_error - Access level updated для отзыва доступа пользователя
Без льготного периода период повторных попыток списания (когда стор продолжает пытаться снять средства с пользователя) начинается немедленно. Если оплата так и не прошла до конца льготного периода, порядок событий тот же: они создаются в момент, когда стор автоматически завершает подписку:
-
Событие Trial expired или Subscription expired (churned) с
cancellation_reasonравнымbilling_error -
Access level updated — уровень доступа пользователя отзывается
Потоки совместного использования покупок между аккаунтами пользователей
Когда Customer User ID iOS, Android, React Native, Flutter и Unity пытается восстановить или продлить подписку, уже привязанную к другому Customer User ID iOS, Android, React Native, Flutter и Unity , настройка Sharing paid access between user accounts в Adapty определяет, как управляется доступ. Порядок действий будет зависеть от выбранного варианта.
Для транзакций Apple Family Sharing (in_app_ownership_type=FAMILY_SHARED) срабатывает только событие Access level updated — перечисленные ниже события подписки для конкретных продуктов не отправляются. Полная матрица событий — в разделе Apple Family Sharing.
Перенос уровня доступа на нового пользователя
Рекомендуемый вариант — перенести уровень доступа на нового пользователя. Это сохраняет историю транзакций исходного пользователя и обеспечивает корректную аналитику. Будет создано только 2 события Access level updated:
- для отзыва уровня доступа у первого пользователя
- для предоставления уровня доступа второму пользователю
Ниже приведена разбивка полей, связанных с назначением уровня доступа и его передачей, в событиях, генерируемых в этом сценарии:
- Пользователь A: уровень доступа обновлён (отправляется, когда пользователь A оформляет подписку в приложении)
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": null
}
- User A: Уровень доступа обновлён (отправляется при переустановке приложения и входе User B, что отзывает доступ у User A)
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": false,
},
"profiles_sharing_access_level": null
}
-
Пользователь B: уровень доступа обновлён (отправляется, когда пользователь B входит в систему и доступ предоставляется)
{ "profile_id": "00000000-0000-0000-0000-000000000001", "customer_user_id": UserB, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": null }
Общий доступ между пользователями
Этот вариант позволяет нескольким пользователям совместно использовать один уровень доступа, если их устройство привязано к одному Apple/Google ID. Это удобно, когда пользователь переустанавливает приложение и входит с другим email — он по-прежнему сохранит доступ к предыдущей покупке. При этом несколько идентифицированных пользователей могут разделять один уровень доступа. Пока уровень доступа общий, все транзакции записываются под оригинальным Customer User ID iOS, Android, React Native, Flutter, и Unity , чтобы сохранить полную историю транзакций и аналитику. Таким образом, будет создано только 1 событие: Access level updated — для предоставления доступа второму пользователю.
Ниже описаны поля, связанные с назначением и передачей уровня доступа в событиях, генерируемых в этом сценарии:
Пользователь B: Access level updated (отправляется при входе пользователя B и предоставлении доступа)
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": [
{
"profile_id": "00000000-0000-0000-0000-000000000001,
"customer_user_id": UserB
}
]
}
Доступ не передаётся между пользователями
При этой настройке только первый профиль пользователя, получивший уровень доступа, сохраняет его навсегда. Это идеально подходит для случаев, когда покупки должны быть привязаны к единственному Customer User ID iOS, Android, React Native, Flutter, и Unity .