Потоки событий
В 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.
Если пользователь нажимает Restore Purchases, но уже имеет доступ в том же профиле, восстановление не выполняется и вебхуки не отправляются. События из этого раздела срабатывают только тогда, когда доступ фактически переходит между профилями.
Чтобы быстро понять, какие события срабатывают, когда второй профиль подключает существующую подписку, воспользуйтесь этой таблицей. В следующих разделах приведены полные JSON-пейлоады для каждого сценария.
| Событие | Включено (по умолчанию) | Перенести уровень доступа на нового пользователя | Отключено |
|---|---|---|---|
Новый профиль: Access level updated (is_active=true) | Срабатывает | Срабатывает | Не срабатывает |
Старый профиль: Access level updated (is_active=false) | Не срабатывает — оба профиля сохраняют доступ | Срабатывает, когда новое идентифицированное устройство передаёт транзакцию | Не срабатывает — исходный профиль сохраняет доступ |
Поле profiles_sharing_access_level в новом событии | Перечисляет другие профили, которые совместно используют уровень доступа | null | Не применимо — событие не срабатывает |
Продления, возвраты и истечения срока действия переданной подписки продолжают генерировать события subscription_renewed, subscription_refunded и subscription_expired для того профиля, который в данный момент владеет уровнем доступа. Само событие передачи не генерирует событие subscription_started, поскольку новая транзакция не записывается — изменяется только атрибуция. |
Подробнее о контрактах для каждого режима см. в разделе Практический справочник.
Перенос уровня доступа на нового пользователя
Рекомендуемый вариант — перенести уровень доступа на нового пользователя. Это сохраняет историю транзакций исходного пользователя и обеспечивает корректность аналитики. При этом будет создано всего 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
}
- Пользователь A: уровень доступа обновлён (отправляется при переустановке приложения и входе пользователя B, что отзывает доступ пользователя 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 .