Detecting IAP Cancellation - ios

I generally understand receipt validation on In App Purchases. Most libraries make this as simple as calling a method.
I'm not so clear on how subscriptions work though -- specifically, how can I detect if the subscription is cancelled?
Subscriptions are cancelled on Apple's iTunes interface only. How is my server supposed to know that a subscription was cancelled?

From the Apple docs:
The user can also cancel their subscription by disabling auto-renew and intentionally letting their subscription lapse. This action triggers the App Store to send your server a status update notification of type DID_CHANGE_RENEWAL_STATUS. Your server can parse the auto_renew_status and the auto_renew_status_change_date to determine the current renewal status of the subscription.
https://developer.apple.com/documentation/storekit/in-app_purchase/subscriptions_and_offers/handling_subscriptions_billing#3221914

The answer from Jacob is correct for the case that the user disables the auto-renewal of his subscription. If the user requested a refund from Apple and they cancel the subscription for him. Your server will receive a CANCEL notification and the receipt will contain a cancellation_date field.
You need to handle both of those cases, because when the user cancels (deactives the auto-renewal) his subscription, it is still valid (till it expires). When Apple customer support cancels the subscription, then it is from this point on invalid.
Note: the CANCEL notification is also triggered when a user up- or downgrades to a different subscription of the same subscription group. See this answer for more details on that.

Related

Question about server-to-server notification

As Apple doc said in this doc: https://developer.apple.com/documentation/appstoreservernotifications/notification_type?changes=_2
Subscription event | Notification types triggered
-----------------------------------------------------------------------------
.
.
.
Auto-renewal disabled (canceled) from
the App Store account's Subscriptions settings | DID_CHANGE_RENEWAL_STATUS
AppleCare refund | CANCEL, DID_CHANGE_RENEWAL_STATUS
When AppleCare refund happend, there are two notification types triggered, one of them is DID_CHANGE_RENEWAL_STATUS. And when cancel subscription happened, its notification type is DID_CHANGE_RENEWAL_STATUS too. So, when i got a notification with notification_type DID_CHANGE_RENEWAL_STATUS, how could i know whether the user has refunded or canceled?
I don't know why Apple triggers CANCEL as well as DID_CHANGE_RENEWAL_STATUS, but technical it is correct. The user cancels his subscription (you get the CANCEL notification) and this also changes the renewal status (you get the DID_CHANGE_RENEWAL_STATUS notification—obviously the subscription won't renew in the future).
To your question: you know a refund happend when you receive the CANCEL notification and when the server response body with the DID_CHANGE_RENEWAL_STATUS notification contains the cancellation_date_ms in Latest_receipt_info.
cancellation_date_ms
The time and date that Apple customer support canceled a transaction or the time and date the user upgraded an auto-renewable subscription.
see here for more details.
Don't worry in the case that a user upgrades his subscription, your server will receive additionally to CANCEL and DID_CHANGE_RENEWAL_STATUS the INTERACTIVE_RENEWAL notification.
In the case the user canceled (deactivated auto-renew) the field auto_renew_status (documentation) in the response body is set to 0.

Apple iOS Inapp purchase Server to Server Notifications' 'Cancel' notification cases?

We have been testing In App purchase Server to Server notifications in sandbox environment over and over. Apple's documentation here states for the Cancel type notification that:
Indicates that the subscription was canceled either by Apple customer support or by the App Store when the user upgraded their subscription. The cancellation_date key contains the date and time when the subscription was canceled or upgraded.
As per this, we should receive a Cancel notification when we perform an upgrade of a product from the subscription group but we have been receiving a INTERACTIVE_RENEWAL instead? Is this because we are testing in Sandbox environment. Do we get the CANCEL in production, and if yes whether we should still expect another INTERACTIVE_RENEWAL in production as well.
You'll only receive a CANCEL notifications if the subscription was refunded by Apple support. You should expect the INTERACTIVE_RENEWAL events for upgrades.
Is this because we are testing in Sandbox environment. Do we get the CANCEL in production, and if yes whether we should still expect another INTERACTIVE_RENEWAL in production as well.
Correct. This behavior is due to Sandbox env. In Production, you would get both the notification.
From Apple Doc :
CANCEL - indicates that the subscription was canceled either by Apple customer support or by the App Store when the user upgraded their subscription. The cancellation_date key contains the date and time when the subscription was canceled or upgraded.
https://developer.apple.com/documentation/storekit/in-app_purchase/enabling_server-to-server_notifications
If you check the documentation for CANCEL today (20210404) you can see that the CANCEL notification no longer mentions the part that it is sent when there is an upgrade. They changed the documentation (and, I suppose, the behaviour too), but they didn't make an explicit mention to that (a changelog, for example), and they don't include modification time for documentation pages. So it is very difficult for us, as developers, detect the changes in an easy way.

Never Get RENEWAL Notification Type on Apple statusUpdateNotification

I created an API to be called by Apple webhook to work with subscription. I've set the API url in Itunes to be called by the webhook.
According to Apple help site https://help.apple.com/app-store-connect/#/dev7e89e149d in regards to the Testing Auto-Renewable Subscription, when testing auto renewable subscriptions in the test environment, the Apple webhook will make a call to the API after 5 minutes if I select 1 month subscription duration.
But the thing is, after making first purchase, apple webhook doesn't follow up call to the API that I created to renew the subs. Even after I waited for more than 5 minutes. So I can't do any processing from the API to renew user subs in the database.
Is there some configuration that I had to make in order to test the auto renew and make apple webhook call the API to renew the sub?
We've found that Apple's subscription update webook calls are rather unreliable.
Based on experience:
Don't count on Apple to notify you of renewals. The notification may arrive arbitrarily late (often leaving a "gap" in time), or not at all. We've resorted to retaining and retrying the original iTunes-provided receipt to revalidate renewals at the end of subscription periods --the expiration dates will change to account for the renewal.
Don't count on Apple to notify you of cancellations, either. Same as above, calculate subscription duration, and retry receipts at the end of a period (the expiration date will NOT be updated if the subscription is cancelled).
Generally, this involves mapping the additional transactions/in_apps that are returned with the retried receipt to the original_transaction_id --and updating the expires_at accordingly on your end.
Hope this helps!
Update: In WWDC2020 Apple announced that they add a new notification type called DID_RENEW which will be sent after any successful auto-renew. More info on that in this video, starting at around 16:00.
Original answer:
I can't find the page you linked to, however this page may shed light on the subject (emphasis by me):
The App Store attempts to charge the user account 24 hours before an auto-renewing subscription expires. If the renewal is successful, there is no server-to server notification because the auto-renewing subscription did not enter into the expired state. However, in the few cases that iTunes is unable to renew the subscription (generally there was a connection problem with the credit card server) and the auto-renewing subscription is not renewed before the expiration_date passes, the auto-renewing subscription is technically considered expired. iTunes may continue to attempt to renew the subscription. If iTunes is successful, then the RENEWAL event is sent.
Meaning, you're not supposed to receive notifications for renewals, but only for cases where the subscription became expired and only then renewed. This might be the case for sandbox renewals as well.

How to restore and verify auto-renewable subscriptions?

First off there seem to be many questions on SO regarding this topic but most seem outdated and not considering APIs that are available in iOS 9.
1) How are purchases restored?
When a user taps the Restore Purchase button for auto-renewable subscriptions on >=iOS 9, should a SKReceiptRefreshRequest or SKPaymentQueue.defaultQueue().restoreCompletedTransactions() be called? Currently I verify the receipt file to determine the active subscription and parse for the latest_receipt_info, is a receipt file also created on the device when restoreCompletedTransactions is called?
2) How can an auto-renewable subscription be verified?
To verify that an auto-renewable subscription on >= iOS 9 is still active and not cancelled I would call SKReceiptRefreshRequest every time the user launches the app. But the docs say:
Include some mechanism in your app to let the user restore their
purchases, such as a Restore Purchases button. Restoring purchases
prompts for the user’s App Store credentials, which interrupts the
flow of your app: because of this, don’t automatically restore
purchases, especially not every time your app is launched.
Should I call it only once a day or is there another way to verify the subscription?
Update:
For 2) just found this here:
Perform receipt validation immediately after your app is launched,
before displaying any user interface or spawning any child processes.
Implement this check in the main function, before the
NSApplicationMain function is called. For additional security, you may
repeat this check periodically while your application is running.
Apparently the receipt can be validated without user interaction. It is even recommended to do it on one's own server for security purpose. So as long as the receipt is validated by the App Store server there is no need for a receipt refresh request.

iOS In-App Purchasing and Detecting Auto-Renewable Subscription

I have a couple questions regarding the process of detecting that a subscription has been auto-renewed.
Currently I have my sandbox test environment all set up, I am able to purchase a 1 month subscription and all of that works nice and dandy.
My questions are as follows:
Do I need to verify the initial receipt (or really any subsequent receipts) of the in app purchases? If so, for what reasons?
Does my app get notified via a paymentQueue:updatedTransactions: call when the auto-renew has happened? Both in the sandbox environment and in the production environment.
So far, I have not seen the StoreKit notify me of a renewed subscription (in the sandbox environment) but I have also read that it is finicky and might not.
Any general tips with Auto-Renewable subscriptions that I should take into account?
Thanks for your help and time!
1. Regarding Receipt Validation
Receipt validation is your means of performing extra security checks before you unlock the users content. Think of a receipt as a lotto ticket. A client comes to you with the "Winning Ticket". Depending on how valuable you consider the reward to your Lottery you can either give said individual their winnings, or you can contact Apple and check whether the user actually purchased this ticket through them.
The client could have got this lotto ticket through some malicious means be it a jail broken device etc and so its really up to you to decide whether you want to verify the receipt or not.
2. Regarding Renewal Notification
The official documentation states the following:
After a subscription is successfully renewed, Store Kit adds a
transaction for the renewal to the transaction queue. Your app checks
the transaction queue on launch and handles the renewal the same way
as any other transaction. Note that if your app is already running
when the subscription renews, the transaction observer is not called;
your app finds out about the renewal the next time it’s launched.
So you should definitely be getting receipt renewal notifications in your app. Don't forget that you should always add yourself as the observer of StoreKit's paymentQueue in order for this to work, something like this in your app delegates didFinishLaunching would work:
//where YourObserver is an object that is alive for the apps lifecycle
[[SKPaymentQueue defaultQueue] addTransactionObserver:YourObserver];

Resources