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

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

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

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

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

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

Токен покупки действителен с момента оформления подписки до 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, предоставленное в ресурсе subscription, возвращенном 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-дневный льготный период.
  • Подписка останется активной, и вы не получите уведомление RTDN о льготном периоде, пока не закончится скрытый льготный период.

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

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

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

В зависимости от статуса подписки после 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 ресурса подписки устанавливается метка времени из прошлого, а в поле 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 месяца
*Может быть изменено в любое время.

Подписка приостанавливается только после завершения текущего расчетного периода. Пока она приостановлена, пользователь не имеет к ней доступа и не платит за продление. По окончании периода приостановки подписка возобновляется, и Google пытается ее продлить. Если сделать это удается, она снова становится активной. Если возобновление подписки не удалось из-за проблем с оплатой, аккаунт пользователя будет заблокирован, как показано на рисунках 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 с отмененной подпиской и кнопкой Оформить подписку снова.

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

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

После того как срок действия подписки с автоматическим продлением истек, вы можете разрешить пользователям приобрести тот же основной тарифный план. В документации для разработчиков и 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 выпускает новый токен покупки, а ваш сервер получает уведомление в реальном времени с типом 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 руб. При оформлении подписки средства не списываются, поскольку пользователь уже оплатил текущий расчетный период. Регулярная оплата возобновится в исходную дату продления. Заказ с нулевой стоимостью будет показан в разделе Управление заказами в 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 в ресурсе subscription.

Однако 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 из предыдущих версий.