I am a little confused about the process involved in the validation of receipts from users who have subscribed to my app.
At the minute a user joins and then purchases the subscription, the receipt is then base64 encoded and sent to my server. At midnight each night the server sends off the receipt stored in my db to Apple to be validated and the expiry date updated.
Now i'm a bit confused about how a receipt is updated each month. Please take a look at the following flow and let me know if this is correct.
The user registers and subscribes to my app.( Lets say January).
The original receipt is sent to my server and then validated with Apple, the expiry date is returned and set on my server.
A month later in February on the expiry date I send the original (January) receipt to Apple again to see if the subscription has been renewed and then I can set the new expiry date.
Is this flow correct? Because I am sending the original (January) receipt each month will it still contain the latest renewal information or do I somehow have to refresh the receipt each month when the user logs in or opens the app?
Yes, your understanding is more or less correct. When a user's first renewal occurs a couple of things will happen:
The next time the user launches the app, your SKPaymentQueue delegate will receive a new SKPaymentTransaction for the new transaction. You need to be ready to observe this transaction with your delegate and finish it. If you don't, transactions will just continue to pile up over the months.
The verifyReceipt response received from Apple for the first receipt will update the latest_receipt_info key to include the most update version of the receipt data. latest_receipt_info will originally just be a copy of the receipt.in_app field, but after the first renewal it will contain the most up to date transactions. You should use these latest_receipt_info transactions to update the expiration date.
My suggested behavior is that when you receive the new SKPaymentTransaction you send it to your server anyway (although you technically don't need to) and you use it to verify and update the expiration date before finishing the transaction. You can overwrite the old receipt with the new one.
You can have a look at the RevenueCat iOS framework source code to see how I handle it. (You should also make sure you trigger a fetch receipt request if the receipt data is missing, which I do in the code.)
If you are interested in an out of the box solution, RevenueCat is a service I started to handle all these and many more edge cases automatically.
Related
I'm building a react native app that has a 1 month subscription component. I have integrated into the apple API to get the receipts but I have one question I can't seem to figure out in test mode. Probably a newbie question but here we go...
When a user has an auto-renewing subscription and I call the Apple API there is the latest_receipt_info.
Will I get a new one every month? if so when does it come through?
So will all I have to do is call the Apple API, grab the latest transaction from latest_receipt_info and look at the "expires_date" field. If we are still before this date then I assume the subscription is still active? Can it be this simple to see if a subscription is active or not?
I've seen talks online about a "cancellation_date_ms" field but I can't seem to find it in sandbox mode, but why would this be needed if I just use the logic I stated above?
You can get an updated receipt any time by calling Apple with receipt data from the application, even if you send older data Apple always sends you the latest receipt.
You can check for the expiration date within, however it is the case if a user gets a refund the expiration date may still be in the future - in that case you'd be sent the cancellation_date_ms as well, so you should look out for that.
To get a better understanding of what all can be in latest_receipt_info, read through the entries in here, search for responseBody.latest_receipt_info:
https://www.namiml.com/blog/app-store-verify-receipt-definitive-guide
So our ios app has issue of not updating the expiry date.
Now we want to update all users expiry date from directly our php backend using the verify apple receipt code of node js
But the problem is data base has no purchase id, installion id.. so how do we identify and get the receipt of X user
we are looking at https://www.npmjs.com/package/node-apple-receipt-verify
So User1 emails us he purchased the auto renewal but it did not renew, now we want to update User1's expiry date before he opens the app
You have the send the receipt from the iOS app to your server. Ideally you should do this when the user makes a purchase, but it can be done at anytime. You should store this on the backend with that users info. This is the receipt you need to send when making the validate and verify calls to apple.
I haven't used this library before but the general idea is that you can send this same receipt every time and apple will return you the latest receipt info. You can use the latest receipt info to update/cancel the user subscription.
This is the documentation from apple:
https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1
I try to add auto-renewable subscriptions in my app, but not sure about the proper way to handle this.
What I'm having right now is
Add SKPaymentQueue.default().add(self) in app delegate.
Once user purchase I save expiration date and set timer to fire on that date.
If I get renew transaction, update expiration date and extended timer.
If user not renew timer will fired and update ui to reflect that change.
My question is if this a right approach? This approach seem to have a gap where a brief moment (when date expired and renew transaction not yet arrived), users are treat as free tier.
What is a better way to do this?
The app receipt contains a record of the user’s purchases, cryptographically signed by Apple. You can validate subscription receipt in two ways:
Locally/Unsafe: Perform receipt validation immediately after your application launched.
Remotely/Safe: Perform receipt validation at server end. Use trusted
server to connect with App Store.
For more information, see Receipt Validation Programming Guide.
I want to offer a renewable subscription in my iOS application. The user subscribed and the receipt is stored. Now i wonder how i need to make sure that the receipt is valid and not cancelled:
If the user cancels the subscription and it is not renewed, how would i know it? If the subscription is renewed, when a new receipt will be created?
If the user cancels the subscription through apple support (because, for example, he bought it my mistake), how can i know it? The receipt on the device will be valid. Should i refresh the receipt every time the user logs in?
EDIT:
I forgot to mention it, but the receipt is checked in the client side.
Generally you need to check the expiration date of the subscription. To do that you need to get the receipt list and find the most recent record. It could be done using several ways (iOS Restore in App purchases with receipts)
If user cancels the subscription, I believe it means that receipt list simply will updated and you can find this by reading the 'cancellation date' field. To get track the expiration date I'd recommend to use UILocalNotification. If user continues to use subscription and you doubt whether he prolonged it or not, you should update the receipt list and send request to Apple [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]
If user cancel the subscription through apple support , you can find the corresponding record (aka "Cancellation Date") in the receipt data. Please read (https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html).
I'd recommend to check the receipt from time to time or use a notification mechanism.
I am trying to implement an auto-renewable subscription in an app, it works like this:
The user buys a subscription.
The app gets the receipt and sends it to my webService.
My webService verifies the receipt, changes the role of the user from Free to VIP and also records the receipt.
Now the question: When the expiration date comes, should I verify the receipt at my webService or in the app?
If it is on the webService, should I attempt to verify the old receipt (stored) and Apple returns to me the latest one if renewed or cancelled?
If it is on the app how should I proceed? Is there some kind of notification from storeKit when the subscription is renewed or cancelled?
If the right approach is the second (App), since my webService controls whether the role of the user is Free or VIP, every time a renewal happens I will have to send the latest receipt to my webService, so, it can manage the user's role properly. That's why I need to know how and when to get the latest receipt to send.
The more useful approach is the first one - through your web Service.
When you will attempt to verify the old receipt (stored) and Apple may respond in one of the following two ways:
If user has not cancelled the subscription, you will get the latest receipt with the expiration date extended.
If user has cancelled the subscription, you will get the receipt with the old expiration date only.
So based on the expiration date you can create your logic to whether extend the VIP membership or not.
Additionally, you can configure your authentication call on app side to re-authenticate user every 12 hours or 24 hours so you will get the updated membership status as well.