Managing subscribers lifecycle comprehensively is essential. You don't want to let subscribers out because you didn't activate their purchases and you don't want to let people enjoy it when they shouldn't.
In this article we will be discussing that last case and you will see that it is much more complicated than what you probably expect especially as Apple introduced new APIs.
What causes subscriptions expirations?
There are many events that lead to a subscription expiration. They all need to be handled by your subscription stack:
- Renewal canceled by your customer
This is the most common case, your customers goes to its settings and choses not to renew for the next period. At the end of the period, the subscription naturally expires.
Some stores like the Google Play Store offer the possibility to pause a subscription. In that case you need to suspend the access to the features or content of your subscription.
- Billing issues
If the store cannot proceed with the payment (expired card, insufficient funds…) your user will churn. You can get him (and you) an extra chance by allowing a grace period and avoid having to convert him again. At the end of the billing period he will expire and you need to revoke the access.
Every customer can ask the stores for a refund. Apple even introduced an API to ease that process. Customers need to justify it with the customer care and it can be unintentional but eventually they will get refunded and you don't want them to continue enjoying your content.
- Price increase that was refused
As an app editor you can change the prices of a subscription (be really careful with that). This will send a price increase consent message to current subscribers. If they refuse they will churn (once again be really careful if you consider doing this).
- Removal from a family sharing
If you are in a family group and one of the family member purchases a family shareable In-App Subscription you will be able to use it as a regular subscriber. If you are removed from the family group (or any of the previous case apply to the owner) your subscription will be revoked.
Manage expirations with Purchasely
Manage expirations with the Apple App Store
At the WWDC21, Apple has announced new server-to-server notifications (S2S) to help developers. Depending on the version you are supporting, the amount of development will be more or less important.
At the time of writing this article, Apple hasn't released these new notifications yet.
With the old S2S (pre-2021)
If you're not using the 2021-version of the S2S, it means you won't have direct S2S to know when a subscription expires and you'll have to work your way around. Here is what you'll have to do:
- for anticipated cancellations (refund, upgrade), Apple sends specific S2S:
CANCEL: indicates that either Apple customer support canceled the subscription or the user upgraded their subscription. The
cancellation_datekey contains the date and time of the change.
DID_FAIL_TO_RENEW: indicates a subscription that failed to renew due to a billing issue. It doesn't mean you should remove access to the user though (cf. previous explanation on grace period)
REFUND: Indicates that App Store successfully refunded a transaction.
REVOKE: Indicates that an in-app purchase the user was entitled to through Family Sharing is no longer available through sharing. StoreKit sends this notification when a purchaser disabled Family Sharing for a product, the purchaser (or family member) left the family group, or the purchaser asked for and received a refund.
- for normal subscription cancellations, there is no S2S. You'll have to use the /verifyReceipt API (cf. "By Calling Apple servers" section)
All the S2S are listed in the Apple documentation.
With the new S2S v2 (2021)
One of the new S2S notification that was introduced is
EXPIRED. It will have different substates to know the expiration's cause:
So, whenever you receive this S2S, you know you can revoke the accesses to your user.
By calling Apple servers
For the new Subscription Status API, request it and check for the
grace to determine the current status of your subscription.
You should revoke the subscription when:
graceis in the past (more info on grace period here)
Period Expires Date
expiresDateis in the past AND
graceis not defined
Period Expires Date
For the old /verifyReceipt API, you can check the equivalent properties to revoke a subscription:
grace_period_expires_dateis in the past (more info on grace period here)
expired_dateis in the past AND
grace_period_expires_dateis not defined
As you won't receive live notifications, you might have people enjoying their subscription longer than they should. For example, a refund can occurs 5 days after an initial purchase. Think about adapting the number of verifications and the frequency check instead of just checking at the expiration date. This is especially important for annual subscriptions!
Manage expirations with Google Play Store
Google sends S2S when you have to revoke accesses to a user:
SUBSCRIPTION_EXPIRED: more info here
SUBSCRIPTION_REVOKED: more info here
SUBSCRIPTION_PAUSED: more info here
By calling Google servers
If you don't want to use the S2S, you can check a subscription's status by directly calling the Google Play developer API. It's not recommended though, since you could let free access to a user who asked for an early refund.
As you could see in this article, despite some efforts made by the stores it is still complicated to manage accesses and revoke them correctly.
If you miss one case you will let unauthorized customers enjoy your contents or services, and sometimes forever. The worst thing is that people love to explain how they could get that subscription for free to their friends and family and that this spreads.
Some recommendations (other than save time and troubles by using Purchasely 😂):
- Unit-test your engine
- Follow the store evolutions to be sure to support every new cases
- Don't rely ONLY on the S2S notifications. They might not be sent or you might miss them because your servers aren't responding.
You should pull-check the subscriptions regularly with the stores in case you missed a message.