Жизненный цикл подписки

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

Как управлять жизненным циклом подписок с автоматическим продлением

Когда статус подписки пользователя меняется, ваш сервер получает сообщение SubscriptionNotification.

subs-auto-renew-state
Рисунок 1. состояния жизненного цикла и события перехода для покупок подписок с автоматическим продлением.

Чтобы обновить статус в серверной части, вызовите API purchases.subscriptionsv2.get с токеном покупки, включенным в уведомление. Эта конечная точка предоставляет актуальный статус подписки на основе токена покупки и считается источником достоверных данных для управления подписками.

Токен покупки действителен с момента оформления подписки до 60 дней после ее окончания. После этой даты токен покупки нельзя использовать для вызова Google Play Developer API.

Новые покупки подписок с автоматическим продлением

Когда пользователь оформляет подписку, клиенту RTDN отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED. Независимо от того, получили ли вы это уведомление или зарегистрировали новую покупку в приложении с помощью PurchasesUpdatedListener или вручную извлекли покупки в методе onResume() приложения, вам следует обработать новую покупку в защищенном бэкенде. Для этого выполните следующие действия:

  1. Отправьте запрос к конечной точке purchases.subscriptionsv2.get, чтобы получить ресурс подписки с ее текущим статусом.
  2. Убедитесь, что в поле subscriptionState указано значение SUBSCRIPTION_STATE_ACTIVE.
  3. Подтвердите покупку.
  4. Предоставьте пользователю доступ к контенту. Аккаунт пользователя, связанный с покупкой, можно идентифицировать с помощью объекта ExternalAccountIdentifiers из ресурса подписки, если идентификаторы были заданы во время покупки с помощью setObfuscatedAccountId и setObfuscatedProfileId.

Поле offerPhase в объекте SubscriptionPurchaseLineItem содержит информацию о текущем периоде подписки, например о бесплатном пробном периоде или начальной цене.

Библиотека Play Платежей также включает метод подтверждения подписки acknowledgePurchase() и метод проверки статуса подтверждения isAcknowledged(). Однако для повышения безопасности мы рекомендуем обрабатывать покупки на сервере.

Ресурс подписки для новых покупок выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_PENDING", // need to acknowledge new purchases
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      },
      "offerPhase": {
        "freeTrial": {}
      }
    }
  ],
}

Продление подписки

Для автоматически продлеваемых подписок без рассрочки при продлении отправляется уведомление SUBSCRIPTION_RENEWED. Для подписок с рассрочкой уведомление SUBSCRIPTION_RENEWED отправляется каждый раз, когда в дату оплаты списывается платеж. Убедитесь, что у пользователя по-прежнему есть право на подписку, а затем обновите ее статус, используя новое значение expiryTime, указанное в ресурсе подписки, который возвращает Google Play Developer API. Ресурс подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      },
      "offerPhase": {
        "basePrice": {}
      }
    }
  ]
}

Подтверждать продление подписки не нужно.

Льготный период

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

Метод queryPurchasesAsync() продолжает возвращать покупки, которые находятся в льготном периоде. Если ваше приложение использует только queryPurchasesAsync, чтобы проверить, есть ли у пользователя подписка, то оно должно автоматически обрабатывать льготные периоды, поскольку такие подписки показываются как активные в библиотеке Play Платежей.

Синхронизация статуса подписки с вашей внутренней системой позволяет вам лучше отслеживать отклоненные платежи и получать больше информации, чтобы снизить количество непреднамеренных отказов. Слушайте сообщения SubscriptionNotification с типом SUBSCRIPTION_IN_GRACE_PERIOD, чтобы получать уведомления о том, что пользователь перешел на льготный период. Пока действует льготный период, ресурс подписки содержит autoRenewEnabled = true. Google Play динамически продлевает значение expiryTime, пока не истечет льготный период, поскольку право на использование должно действовать до тех пор, пока пользователь не отменит подписку или не закончится максимальный льготный период. Значение поля subscriptionState в этот период – SUBSCRIPTION_STATE_IN_GRACE_PERIOD. Ресурс подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_IN_GRACE_PERIOD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

Пользователи, у которых действует льготный период, получают уведомление об отклоненном платеже и предложение устранить проблему со способом оплаты в Google Play. Когда у пользователя начинается льготный период, предложите ему исправить способ оплаты, если проблема возникла не по его вине. Проще всего это сделать с помощью API для сообщений в приложении. Если вы вызовете этот API, когда пользователь откроет ваше приложение, он увидит сообщение от Google Play о том, что платеж отклонен. В этом сообщении также есть ссылка на контент, которая позволяет пользователю исправить способ оплаты в Google Play.

Как только пользователь исправит способ оплаты, подписка будет продлена с исходной датой продления. Вы можете обработать продление, как описано в разделе Продление.

Если пользователь не устранит проблему со способом оплаты в течение льготного периода, подписка будет временно заблокирована, а доступ к ней – закрыт.

Доступ и восстановление в течение льготного периода

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

Рисунок 2. Хронология подписки, для которой был предоставлен льготный период и которая была восстановлена до его окончания.

Важно помнить следующее:

  • В течение льготного периода пользователь должен сохранять доступ к преимуществам подписки.
  • Если подписка возобновляется в течение льготного периода, дата продления не сбрасывается.
  • Если вы измените льготный период, это не повлияет на пользователей, для которых он уже действует. Для продления подписки, для которых после изменения начнется льготный период, будет действовать новый льготный период. Например, если вы увеличите льготный период с 7 до 14 дней, то для пользователей, которые войдут в него после изменения, он будет составлять 14 дней.
  • Подписка останется активной, и вы не получите уведомление о льготном периоде в режиме реального времени, пока не закончится скрытый льготный период.

Льготный период беззвучного режима

Вы можете установить льготный период в 0 дней, но Google Play подождет как минимум 1 день, чтобы у пользователя было достаточно времени для повторной попытки оплаты. Этот период позволяет избежать проблем с обработкой платежей. В течение этих 24 часов подписка остается в состоянии ACTIVE.

Чтобы отслеживать изменения статуса подписки, лучше всего использовать уведомления для разработчиков в режиме реального времени. Вызовите метод purchases.subscriptionsv2.get() в момент получения RTDN, а не в момент истечения срока действия, чтобы получить более точный статус подписки.

В зависимости от статуса подписки после 24-часового скрытого льготного периода вы должны получить одно из следующих уведомлений:

  • SUBSCRIPTION_ON_HOLD (если включено)
  • SUBSCRIPTION_CANCELED (если отменено)
  • SUBSCRIPTION_EXPIRED (если срок действия истек)
  • SUBSCRIPTION_RENEWED (если продление пройдет успешно)

Вы также можете вызвать метод subscriptionV2.get() в любой момент после окончания 24-часового льготного периода, чтобы получить актуальный статус подписки.

Временная блокировка аккаунта

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

Пока аккаунт заблокирован, вы должны по-прежнему обрабатывать отмены, восстановления и повторные покупки подписок, поскольку пользователь может вносить эти изменения.

Уведомления RTDN сообщают, когда пользователь переходит в период временной блокировки аккаунта, чтобы вы могли как можно скорее сообщить ему, почему доступ к подписке был приостановлен. Самый простой способ это сделать – использовать API для сообщений в приложении. Если вызвать этот API, когда пользователь откроет приложение, ему будет показано временное уведомление о том, что платеж отклонен. В сообщении также есть ссылка на контент, по которой пользователь может перейти в Google Play и исправить способ оплаты.

Если пользователи могут получить доступ к контенту по подписке вне вашего приложения, они могут обнаружить, что потеряли доступ к нему на других платформах. Вы можете отправить пользователю push-уведомление или электронное письмо, чтобы сообщить, что его подписка больше не активна из-за отклоненного платежа.

Подписка не возвращается методом queryPurchasesAsync() во время временной блокировки аккаунта. Если ваше приложение использует этот метод для показа существующих покупок, вам следует по умолчанию поддерживать временную блокировку аккаунта.

Если вы настроили уведомления для разработчиков в режиме реального времени, то при временной блокировке аккаунта вы получите сообщение SubscriptionNotification с типом SUBSCRIPTION_ON_HOLD. Вызовите метод purchases.subscriptionsv2.get из защищенного бэкенд-сервера, чтобы получить информацию о новой подписке. Во время временной блокировки аккаунта поле expiryTime ресурса subscription содержит временную метку в прошлом, а поле subscriptionState – значение SUBSCRIPTION_STATE_ON_HOLD:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ON_HOLD",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

Чтобы восстановить доступ, пользователям нужно исправить способ оплаты. Google Play сообщает пользователям о временной блокировке аккаунта из-за отклонения платежа. Вам также следует порекомендовать им исправить способ оплаты.

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

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

После восстановления библиотека Play Платежей снова возвращает подписку с помощью метода queryPurchasesAsync(). Если вы используете этот метод, чтобы определить, есть ли у пользователя право на подписку, то ваше приложение должно автоматически обрабатывать восстановление подписки после временной блокировки аккаунта.

Слушайте сообщение SubscriptionNotification с типом SUBSCRIPTION_RECOVERED, чтобы получать уведомления о восстановлении подписки и возобновлении доступа пользователя. Если вы запросите информацию о подписке после получения этого уведомления, в поле expiryTime будет указана временная метка в будущем, а в поле subscriptionState – значение SUBSCRIPTION_STATE_ACTIVE.

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      ...
    }
  ],
}

Если пользователь не исправит способ оплаты до окончания периода блокировки аккаунта, вы получите уведомление RTDN с типом SUBSCRIPTION_CANCELED. Инструкции по обработке отмен приведены в разделе Отмены. Если вы запросите информацию о подписке, отмененной таким образом, в возвращенном поле expiryTime будет указана временная метка в прошлом.

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_past,
      ...
    }
  ],
}

Сразу после того, как вы получите уведомление об отмене подписки во время временной блокировки аккаунта, вы также получите RTDN с типом SUBSCRIPTION_EXPIRED, поскольку пользователь больше не имеет права на платный контент и подписка была отменена. Вы можете продлить срок действия обычным способом.

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

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

На рисунке 3 показана временная шкала для подписки, которая переходит во временную блокировку аккаунта, а затем восстанавливается, когда пользователь исправляет способ оплаты.

Рисунок 3. Временная шкала подписки, которая была заблокирована, а затем восстановлена до окончания срока действия.

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

Рисунок 4. Хронология подписки, которая переходит в льготный период, затем переходит во временную блокировку аккаунта и в итоге восстанавливается до окончания временной блокировки аккаунта.

Важно помнить следующее:

  • Прежде чем подписка перейдет в состояние временной блокировки аккаунта, Google Play в течение 48 часов пытается списать средства с помощью указанного способа оплаты. В течение этого периода пользователь сохраняет доступ к преимуществам подписки. Если по истечении этого периода оплата не поступит, аккаунт пользователя будет временно заблокирован, а преимущества подписки станут недоступны.
  • Подписка переходит во временную блокировку аккаунта сразу же, когда она возобновляется после приостановки с недействительным способом оплаты.
  • Когда подписка восстанавливается после временной блокировки аккаунта, дата продления сбрасывается.

Как узнать, когда закончится срок проката

После окончания срока действия подписки пользователь должен потерять доступ к ней. В этом случае отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_EXPIRED. Получив такое уведомление, отправьте запрос в Google Play Developer API, чтобы получить актуальный ресурс подписки. После того как вы подтвердите, что subscriptionState имеет значение SUBSCRIPTION_STATE_EXPIRED, отмените право и зарегистрируйте в своей серверной части недействительный статус покупки. Ресурс подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time_in_past,
      ...
    }
  ],
}

Отмененные подписки

Пользователь может отменить подписку в центре подписок Google Play. Кроме того, подписка отменяется автоматически, если пользователь не восстановил ее после временной блокировки аккаунта. Разработчики также могут инициировать отмену с помощью purchases.subscriptionsv2.cancel. После отмены подписки пользователь сохраняет доступ к контенту до конца текущего платежного цикла. Когда платежный цикл закончится, доступ должен быть закрыт.

При отмене подписки с автоматическим продлением и без рассрочки отправляется уведомление SUBSCRIPTION_CANCELED. Когда вы получите это уведомление, в ресурсе subscription, возвращенном Google Play Developer API, в поле subscriptionState будет указано значение SUBSCRIPTION_STATE_CANCELED, а в поле expiryTime – дата, когда пользователь должен потерять доступ к подписке. Если эта дата уже прошла, пользователь должен немедленно потерять право на доступ. Это может произойти, например, если пользователь отменит подписку, когда действие аккаунта приостановлено из-за отклоненного платежа.

Ресурс подписки для отмененной покупки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_CANCELED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ],
}

Если пользователь отменяет подписку с рассрочкой, когда до конца минимального срока подписки ещё остаются платежи, отправляется уведомление SUBSCRIPTION_CANCELLATION_SCHEDULED. Отмена ожидает обработки и вступит в силу в конце текущего минимального срока подписки. Когда вы получите это уведомление, в ресурсе подписки, возвращенном из Google Play Developer API, в поле subscriptionState будет установлено значение SUBSCRIPTION_STATE_ACTIVE, поскольку подписка с рассрочкой платежа будет активна до конца периода обязательств. Однако в нем есть пустой объект pendingCancellation. В конце минимального срока подписки отправляется уведомление SUBSCRIPTION_CANCELED, а затем SUBSCRIPTION_EXPIRED.

Ресурс подписки с рассрочкой платежа, отмена которой находится в ожидании, выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_plan01",
      "expiryTime": expiration_time,
      "autoRenewingPlan": {
        "autoRenewEnabled": true,
        "recurringPrice": {
          "currencyCode": "USD",
          "units": "1",
          "nanos": 990000000
        },
        "installmentDetails": {
          "initialCommittedPaymentsCount": 6,
          "remainingCommittedPaymentsCount": 5,
          "pendingCancellation": {}
      ...
        }
      }
    }
  ],
}

Чтобы узнать, почему подписка была отменена (например, пользователем, системой или вами), посмотрите поле canceledStateContext в ресурсе подписки. Если подписку отменил пользователь, вы можете посмотреть причину в поле userInitiatedCancellation. Это может помочь в разработке коммуникационных стратегий.

Если подписка отменена, но ее срок действия ещё не истек, она по-прежнему возвращается методом queryPurchasesAsync(). Вы можете показывать в приложении сообщение о том, что подписка отменена, и указывать дату ее окончания.

Отзывы

Подписка может быть отозвана по разным причинам, например из-за того, что ваш сервер отменил ее с помощью purchases.subscriptionsv2.revoke, или из-за возврата средств за покупку. В этом случае немедленно отмените право пользователя на доступ. В этом случае отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_REVOKED. Когда вы получаете это уведомление, в ресурсе подписки, возвращенном из Google Play Developer API, поле subscriptionState имеет значение SUBSCRIPTION_STATE_EXPIRED.

Ресурс подписки для отмененной покупки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_EXPIRED",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": expiration_time,
      ...
    }
  ]
}

Отложенные подписки

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

Вы можете использовать API purchases.subscriptionsv2.defer, чтобы отложить дату выставления счета за подписку (в том числе с дополнениями). Если вы откладываете подписку с дополнениями, все ее элементы откладываются на один и тот же срок.

При отсрочке подписки отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_DEFERRED. В течение этого периода пользователь будет иметь полный доступ к контенту, но плата с него взиматься не будет. Дата продления подписки будет обновлена.

Для планов с предоплатой можно использовать API отложенных платежей, чтобы отложить время окончания подписки.

Ресурс подписки с отложенным началом выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": timestamp_in_future,
      ...
    }
  ],
}

Приостановленные подписки

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

Периодичность подписки Еженедельно Ежемесячно 3 месяца 6 месяцев Ежегодно
Доступные варианты длительности паузы* 1 неделя
2 недели
3 недели
4 недели
1 месяц
2 месяца
3 месяца
1 месяц
2 месяца
3 месяца
1 месяц
2 месяца
3 месяца
1 месяц
2 месяца
3 месяца
*Может быть изменено в любое время.

Подписка приостанавливается только после завершения текущего расчетного периода. Пока она приостановлена, пользователь не имеет к ней доступа и не платит за продление. По окончании этого срока мы предпринимаем попытку продлить подписку. Если сделать это удается, она снова становится активной. Если возобновление подписки не удалось из-за проблем с оплатой, аккаунт пользователя будет заблокирован, как показано на рисунках 5 и 6.

Рисунок 5. Пользователь приостанавливает, а затем возобновляет подписку.
Рисунок 6. Пользователь приостанавливает подписку, а затем его аккаунт временно блокируется.

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

Если подписка пользователя приостановлена, библиотека Play Платежей не возвращает ее с помощью метода queryPurchasesAsync(), если только параметр includeSuspendedSubscriptions не имеет значение true в QueryPurchasesParams. Если подписка возобновлена, метод queryPurchasesAsync() возвращает ее снова.

Слушайте уведомления RTDN, чтобы знать, когда пользователь приостанавливает подписку. Эти уведомления также позволяют вам сообщать пользователям в приложении, что они приостановили подписку и не имеют к ней доступа. Также необходимо предоставить пользователю возможность в любой момент возобновить подписку вручную, используя прямую ссылку на Google Play.

Сообщение SubscriptionNotification с типом SUBSCRIPTION_PAUSE_SCHEDULE_CHANGED отправляется, когда пользователь приостанавливает подписку. В этот период у пользователя должен оставаться доступ к подписке до следующей даты продления, а ресурс подписки должен содержать autoRenewEnabled = true. Значение поля subscriptionState в этот момент – SUBSCRIPTION_STATE_ACTIVE.

Когда приостановка вступает в силу, отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_PAUSED. В этом случае пользователь должен потерять доступ к подписке, а ресурс подписки содержит autoRenewEnabled = true, и поле subscriptionState имеет значение SUBSCRIPTION_STATE_PAUSED. Чтобы узнать, когда подписка будет продлена снова, проверьте объект PausedStateContext.

Сообщение SubscriptionNotification с типом SUBSCRIPTION_RECOVERED отправляется, если подписка возобновляется автоматически в конце периода приостановки или если пользователь решил возобновить подписку вручную.

Если при попытке возобновить подписку после приостановки произошел сбой оплаты, отправляется сообщение SubscriptionNotification с типом SUBSCRIPTION_ON_HOLD.

В обоих случаях действуйте, как описано в разделе Временная блокировка аккаунта.

Подпишитесь снова

Для основных тарифных планов с автоматическим продлением в Google Play может показываться кнопка Возобновить подписку. Эта кнопка позволяет пользователям восстановить доступ к подписке. Она может не показываться по разным причинам, например если подписка истекла давно.

Рисунок 7. Раздел "Аккаунт > Подписки" в приложении Google Play, где показана отмененная подписка с кнопкой Подписаться снова.

Хотя кнопка всегда называется Оформить подписку повторно, ее функция зависит от статуса подписки.

Пока подписка отменена, но срок ее действия не истек, пользователь по-прежнему считается подписчиком и получает все преимущества. Если пользователь нажмет "Возобновить подписку", отмена будет аннулирована, а подписка продолжит продлеваться. В документации для разработчиков Google Play и API это действие называется восстановлением.

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

Восстановление до истечения срока действия

Если ваше приложение определяет, есть ли у пользователя подписка, только с помощью метода queryPurchasesAsync(), то оно должно автоматически восстанавливать подписки, поскольку метод queryPurchasesAsync() продолжает возвращать отмененные покупки до истечения срока их действия. Восстановленная подписка будет продлеваться так же, как если бы она не была отменена.

Если ваше приложение синхронизирует статус подписки с серверной частью, вам нужно отслеживать сообщения SubscriptionNotification с типом SUBSCRIPTION_RESTARTED. После получения уведомления RTDN ваше приложение может отреагировать на него, записать, что подписка теперь продлевается, и перестать показывать сообщения о восстановлении в приложении. Ресурс подписки выглядит примерно так, как в следующем примере:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date
      ...
    }
  ],
}

При восстановлении подписки новый заказ не создается. Если вы видите заказ на сумму 0,00 долл.США за подписку, которую пользователь ранее отменил, скорее всего, он снова оформил ее в вашем приложении до окончания срока действия. Подробнее о переходе на другую версию и повторном оформлении подписки…

Как возобновить подписку после окончания ее срока действия

Если основной тарифный план с автоматическим продлением настроен в Google Play Console или API так, что позволяет возобновлять подписку, пользователи могут повторно оформить ее в Google Play.

Это новые покупки. Google Play выдает новый токен покупки, а ваш сервер получает уведомление RTDN типа SUBSCRIPTION_PURCHASED. Статус покупки для этого типа покупки вне приложения не включает linkedPurchaseToken, связанный с исходной покупкой, поскольку срок действия исходной подписки полностью истек.

Чтобы обеспечить точную связь пользователя с повторно приобретенными подписками и предотвратить автоматический возврат средств за необработанные покупки, необходимо подтвердить повторную покупку на бэкенд-сервере:

  1. Вызовите метод purchases.subscriptionsv2.get с новым токеном покупки из уведомления для разработчиков в режиме реального времени. Ответ на запрос о такой покупке вне приложения содержит поле outOfAppPurchaseContext, которое присутствует только в неподтвержденных покупках возобновленных подписок. Это поле содержит:

    • expiredExternalAccountIdentifiers – объект ExternalAccountIdentifiers, содержащий поля obfuscatedAccountId и obfuscatedProfileId, которые были настроены для предыдущей подписки с истекшим сроком действия, если они были заданы.
    • expiredPurchaseToken – токен покупки последней подписки, срок действия которой истек.

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

  2. Вызовите purchases.subscriptions.acknowledge, чтобы подтвердить покупку.

    • При необходимости вы можете передать obfuscatedAccountId и obfuscatedProfileId пользователя, если вы настроили их с помощью setObfuscatedAccountId и setObfuscatedProfileId в процессе оплаты контента.

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

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

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

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

Если пользователь снова оформляет подписку на тот же основной план до ее окончания, Google Play создает заказ на сумму 0,00 руб. При оформлении подписки средства не списываются, поскольку пользователь уже оплатил текущий расчетный период. Стандартная абонентская плата возобновится в исходную дату продления. Заказ на сумму 0 рублей появится в разделе Управление заказами в Play Console и в ваших финансовых отчетах. Это не означает, что пользователь получил бесплатную пробную версию или скидку.

Прежде чем предлагать пользователю в приложении перейти на другой тариф, оформить подписку повторно или перейти на более дешевый тариф, вы должны подтвердить существующую подписку. Любые изменения тарифного плана или повторная подписка блокируются, если существующая подписка ещё не подтверждена.

Если пользователь успешно переходит на более дорогой или дешевый тарифный план или оформляет подписку повторно, это считается новой покупкой, которую необходимо подтвердить. Рекомендуем использовать для этого Google Play Developer API. Ресурс подписки выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  ...
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "linkedPurchaseToken": old_purchase_token,
  ...
  "lineItems": [
    {
      "productId": "sub_variant_plan01",
      "expiryTime": next_renewal_date,
      "autoRenewingPlan": {
        "autoRenewEnabled": true
      }
    }
  ],
}

изменения в ценах;

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

Когда вы добавите изменение цены или обновите статус изменения цены, вы получите уведомление SUBSCRIPTION_PRICE_CHANGE_UPDATED RTDN. Вы можете отправить запрос к конечной точке purchases.subscriptionsv2.get, чтобы получить ресурс подписки, который будет содержать сведения об изменении цены для каждого товара в подписке.

Если изменение цены применяется к существующим подписчикам в режиме с запросом согласия, вы получите уведомление RTDN, если пользователь подтвердит или отклонит новую цену.

Как обрабатывать подтверждение согласия пользователя на повышение цены

Когда пользователь согласится с повышением цены, вы получите сообщение SubscriptionNotification с типом SUBSCRIPTION_PRICE_CHANGE_UPDATED.

Как обрабатывать продления после изменения цены

При снижении цены или продлении подписки с повышенной ценой вы получите сообщение SubscriptionNotification с типом SUBSCRIPTION_RENEWED. Относитесь к этому уведомлению как к любому другому продлению.

Как обрабатывать случаи, когда пользователь не соглашается на повышение цены с запросом согласия

Если пользователь не принял повышение цены с запросом согласия до того, как ему нужно будет продлить подписку по новой цене, он будет автоматически отписан, а вы получите сообщение SubscriptionNotification с типом SUBSCRIPTION_CANCELED. Обработайте это событие, как описано в разделе Отмена подписки.

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

Согласно новым законам Южной Кореи пользователи, проживающие в этой стране, должны предоставлять свое согласие на повышение цены подписки после окончания бесплатного пробного периода или периода действия специального предложения.

Чтобы помочь вам соблюдать требования законодательства, Google Play будет уведомлять пользователей в Южной Корее о необходимости дать согласие и сохранять их ответы. Подписки пользователей, которые не дали согласия до того, как начала действовать более высокая цена, будут автоматически отменены. Помимо уведомлений от Google Play вы можете отправлять пользователям собственные уведомления о повышении цен и добавлять в них ссылки на определенные страницы управления.

Когда начнется период согласия или пользователь даст согласие, вы получите сообщение SubscriptionNotification с типом SUBSCRIPTION_PRICE_STEP_UP_CONSENT_UPDATED.

Разница между повышением и изменением цены

price step-up – это повышение стоимости подписки при переходе от одного этапа специального предложения к другому. Например, когда пробный период заканчивается и начинает действовать обычная цена. Чтобы определить текущий этап подписки, используйте поле offerPhase в ресурсе подписки.

Однако price change относится к изменениям цены, которые вы (разработчик) вносите в основной план подписки. Например, повышение цены с запросом согласия или повышение цены без запроса согласия.

Как управлять жизненным циклом тарифных планов с предоплатой

Как и в случае с автоматически продлеваемыми подписками, вы должны подтверждать планы с предоплатой после каждой новой покупки. В случае с предоплаченными планами вы должны полностью обработать как первоначальную покупку, так и любые пополнения, поскольку пользователь должен каждый раз проходить процесс покупки.

Поскольку предоплаченные планы могут быть краткосрочными, важно подтверждать покупку как можно скорее. Тарифные планы с предоплатой на неделю или дольше должны быть подтверждены в течение трех дней. Тарифные планы с предоплатой, действующие менее недели, должны быть подтверждены в течение половины срока их действия. Например, у разработчиков есть 1,5 дня, чтобы подтвердить покупку трехдневного предоплаченного плана.

Рисунок 8. состояния жизненного цикла и события перехода для покупок подписок.

Сообщение SubscriptionNotification с типом SUBSCRIPTION_PURCHASED отправляется вашему клиенту RTDN при каждой покупке плана с предоплатой, в том числе при каждом пополнении баланса. Вызовите метод purchases.subscriptionsv2.get, чтобы проверить текущий статус подписки с предоплатой.

При пополнении баланса создается новый токен покупки, а предыдущий токен покупки передается в поле linkedPurchaseToken как часть нового состояния покупки подписки. Токен покупки действителен с момента оформления подписки до 60 дней после ее окончания. После этой даты токен покупки больше нельзя использовать для вызова Google Play Developer API.

Ресурс подписки для покупки по тарифу с предоплатой выглядит примерно так:

{
  "kind": "androidpublisher#subscriptionPurchaseV2",
  "startTime": "2022-04-22T18:39:58.270Z",
  "regionCode": "US",
  "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE",
  "latestOrderId": "GPA.3333-4137-0319-36762",
  "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED",
  "lineItems": [
    {
      "productId": "prepaid_plan01",
      "expiryTime": expiry_date,
      "prepaidPlan": {
        "allowExtendAfterTime": timestamp_after_which_topups_are_allowed
      }
    }
  ]
}

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

Вы можете показывать в приложении сообщение о том, что подписку с предоплатой можно продлить, пополнив баланс. Чтобы узнать, когда пользователь сможет пополнить баланс, проверьте поле allowExtendAfterTime в ресурсе подписки.

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

Поля SubscriptionPurchaseV2 для планов с предоплатой

Добавлены новые поля для поддержки планов с предоплатой, которые продлеваются пользователем, а не автоматически. Все поля применяются к планам с предоплатой так же, как и к подпискам с автоматическим продлением, за следующими исключениями:

  • [Новое поле] lineItems[0].prepaid_plan.allowExtendAfterTime: указывает, когда пользователь сможет купить ещё одно пополнение, чтобы продлить предоплаченный план. У пользователя может быть только одно неиспользованное пополнение.
  • [Новое поле] SubscriptionState – указывает состояние объекта подписки. Для планов с предоплатой это значение всегда равно ACTIVE, PENDING или CANCELED.
  • lineItems[0].expiryTime – это поле всегда присутствует для планов с предоплатой.
  • paused_state_context: это поле никогда не присутствует, так как тарифные планы с предоплатой нельзя приостановить.
  • lineItems[0].auto_renewing_plan – отсутствует для планов с предоплатой.
  • canceled_state_context – не используется для планов с предоплатой, так как это поле применяется только к пользователям, которые активно отменяют подписку.
  • lineItems[0].productId – это поле заменяет subscriptionId из предыдущих версий.