Handling Apple Grace Period and Billing Retry state

Sam Mejlumyan avatar
Sam Mejlumyan

In this post we will talk about handling payment errors and using Billing Retry in apps with in-app subscriptions. Based on the average data from Qonversion, we can see that 15-20% payments move to Billing Issue state. From that percent, around 15% return to active subscription status. Turning on Apple’s Grace Period allows you to improve your customer’s experience and to increase the percent of payments returned to the active subscription status.

Some common questions:

  • How does Billing Retry work?
  • What is Grace Period?
  • Best ways to implement Grace Period in your product

How does Billing Retry Work?

Payment issues are among the most common reasons for losing subscribers. Let’s have a look at the following example:

image

At the end of a subscription period, Apple tries to make a charge from a client’s card. If an error happens during this process, the subscriber’s status changes to the Billing Retry state. He can stay within this state up to 60 days. Apple will try to renew the subscription for the upcoming subscription period while the client is in the Billing Retry status.  All this time the client is blocked from using the app. On the chart above we see that after 10 days when a successful payment was made the recurring payments resume. All of this complicates subscription analytics, subscription LTV estimates, and leads to lower customer satisfaction.

The user receipt contains the following fields:

is_in_billing_retry_period and expiration_intent

The fields tell us that there was an unsuccessful attempt to receive payment.

"pending_renewal_info": [
    {
        "expiration_intent": "2",
        "auto_renew_product_id": "product.99.trial.3d",
        "original_transaction_id": "10000000306492965",
        "is_in_billing_retry_period": "1",
        "product_id": "product.99.trial.3d",
        "auto_renew_status": "1"
    }
]

What is Grace Period?

Your can allow access to your app’s premium content even in the case when Apple is unable to receive a payment from a client. That is exactly the case Grace Period was designed for. While Apple is trying to receive a payment, the client is granted full access to the app. Grace Period can be activated for auto renewable subscriptions. The duration of Grace Period depends on the duration of your subscription:

image

Let have a look at 2 examples:

Example 1: successful subscription payment while in Grace Period

image

Upon the ending of the first auto renewable period, Apple was not able to collect the payment. This would normally instantly move the client into the Billing Retry status and block his access to the app. However, if the Grace Period has been turned on then the user can still access the premium features for a specified period of time. If Apple collects the payment at one of the next attempts while the user is still in Grace Period the existing payment cycle is not interrupted.

Example 2: payment did not go through during Grace Period

image

In the second example, Apple was unable to collect the payment during the Grace Period, which leads to changes in the current billing cycle and the client moves into Billing Retry status with blocked access to the app. Later, if Apple is able to collect the payment a new auto renewable payment cycle is launched starting from the actual payment date.

After turning on the Grace Period option in the app settings, the JSON response you get when validating the payment receipt will include an extra field: grace_period_expires_date_ms. 

This field shows the expiration date of the premium content access.

"pending_renewal_info": [
    {
        "expiration_intent": "2",
        "grace_period_expires_date": "2020-09-05 23:41:42 Etc/GMT",
        "auto_renew_product_id": "product.99.trial.3d",
        "original_transaction_id": "10000000306492965",
        "is_in_billing_retry_period": "1",
        "grace_period_expires_date_pst": "2020-09-05 16:41:42 America/Los_Angeles",
        "product_id": "product.99.trial.3d",
        "grace_period_expires_date_ms": "1599349302000",
        "auto_renew_status": "1"
    }
]

Right after a successful payment has been made, this field will disappear together with is_in_billing_retry_period.  The field that will show you when the subscription expires is expires_date_ms which is received from receipt.in_app.

"in_app": [
            {
                "quantity": "1",
                "product_id": "product.99.trial.3d",
                "transaction_id": "0000000306492966",
                "original_transaction_id": "0000000306492965",
                "purchase_date": "2020-08-25 02:53:10 Etc/GMT",
                "purchase_date_ms": "1598323990000",
                "purchase_date_pst": "2020-08-24 19:53:10 America/Los_Angeles",
                "original_purchase_date": "2020-08-25 02:53:12 Etc/GMT",
                "original_purchase_date_ms": "1598323992000",
                "original_purchase_date_pst": "2020-08-24 19:53:12 America/Los_Angeles",
                "expires_date": "2020-09-25 02:53:10 Etc/GMT",
                "expires_date_ms": "1601002390000",
                "expires_date_pst": "2020-09-24 19:53:10 America/Los_Angeles",
                "web_order_line_item_id": "000000003253190",
                "is_trial_period": "false",
                "is_in_intro_offer_period": "false"

If the payment did not go through in 60 days, the fields is_in_billing_retry_period and grace_period_expires_date disappear from the receipt and you will able to use  expires_date_ms, but in this case, the subscription is expired with the field auto_renew_status being equal to 0.

Ways to implement Grace Period in your product

If a billing issue has been detected, it might be a good idea to notify a user about the issue within the app. And remind him to update his billing information with the App Store.

You can validate user receipts on your server to catch billing retry state and check if a user is currently in grace period. You can also try Qonversion for that, and save yourself some time to work on your product. With Qonversion all you’ll need to do is to implement the code below:

Qonversion.checkPermissions { (permissions, error) in
  if let error = error {
    // handle error
    return
  }

  if let premium = permissions["premium"], premium.isActive {
    switch premium.renewState {
       case .billingIssue:
         // Grace period: permission is active, but there was some billing issue.
         // Prompt the user to update the payment method.
         break
       default: break
    }
  }
}