We are using server side validation of the payment like so -
User makes payment.
Store kit API sends transaction receipt to App.
App sends base64 encoded transaction receipt to our server.
Our server calls https://buy.itunes.apple.com/verifyReceipt and validates the transaction recept.
User is marked as paid.
For a particular user, we didn't get the transaction receipt at the server, due to which the receipt couldn't be verified. We are guessing something went wrong in steps 2 and 3.
If there were connection problems at the time of sending receipt to server, the app retries again on subsequent app resume.
Now we have one missing transaction receipt and an angry user. How do you suggest we go forward? How can we prevent this in future? Are there any guidelines or best practices that we can follow to prevent such situation?
Thank you.
Based on my experience, the likely issues are
The base64 data got url-encoded along the way and so + and / got messed up - replace these with safer characters before transfer
The whole transaction is bogus.
The way to check for the second case is to look at your account and see if there is a matching purchase record. Unfortunately, the web site can be a bit difficult to review unless you have a low purchase volume.
The are two things you need in your code to correctly handle errors on your server or on, if it happens, Apple's end.
Do not call finishTransaction: until you have successfully communicated with your server (it wouldn't help in this case but worth noting)
Have a "Reload Purchases" button or action that calls restoreCompletedTransactions: on the SKPaymentQueue defaultQueue. For non-consumable/entitlement objects, this will resend all transactions with receipts that can be re-verified on your server.
If the problem you are facing is with non-consumables/entitlements, then the second item is the way out.
Related
Good day! I'm trying to implement notifications for auto-renew subscriptions and some parts of the whole system are not clear for me. Could you please help?
First of all, when user creates a subscription I get a receipt from user's device, verify it and create a record in database with all needed information. Now, the notifications are coming to server.
INITIAL_BUY notification - When does it come and why? I just got a receipt from device, verified it and I'm happy. Why do I need it?
Correct me if I'm wrong, this part is unclear for me, When user UPGRADES subscription level I get CANCEL notification for oldSubscription and a receipt with a new purchase for newSubscription, right?
So theoretical question is - if on my server side content available in oldSubscription and content available in newSubscription are different entities than when I get CANCEL for oldSubscription I just deny user's access to oldSubscription content and when I get receipt from client I create newSubscription with access to new content, right?
DOWNGRADE and CROSSGRADE. As far as I see I get DID_CHANGE_RENEWAL_PREF or DID_CHANGE_RENEWAL_STATUS. So I will get auto_renew_status in notification for this subscription and when payed period will expire I will get a receipt from user device with info about new purchase? Or I have to figure out how to handle DOWNGRADE and CROSSGRADE only by DID_CHANGE_RENEWAL_PREF and DID_CHANGE_RENEWAL_STATUS notifications?
Thank you
The problem with server receipt validation is that there is not only one way. There are endless possibility to implement this and it depends on your use case of the usage of subscriptions and how you want the communication between your app and server to happen.
In your second paragraph is the first example of those possibilities: your server will get the receipt from the device only if you implemented it that way. Also, maybe you update your database solely based on the notifications instead of the send receipt. You see, it is all up to you ;-)
Regarding you questions:
1)
Occurs at the user’s initial purchase of the subscription.
See documentation
Theoretically this is correct, but your described use case isn't an upgrade. Would be odd, if the better subscription wouldn't contain the content of the lower one.
There isn't much to handle with down- or crossgrade. The notifications only tell you that there will be a change with the next auto-renewal. Because, the user is still eligible to access the better content until the next auto-renewal. After the better subscription expired you will receive a normal DID_RENEW with the down- or crsssgrade product id.
So I followed the official manual and implemented this:
https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1
user pays in app
app gets receipt info from Apple
this receipt info is sent to my server
my server verified receipt by calling Apple API and activates membership for client
The obvious problem is that 3. can fail. I have clients complaining they paid, they are sending me SS of the amount being deducted, but my server was never notified. And I have no way to find these users. Is there some CP where I can search by customer e-mail or transaction ID to check if this is Photoshopped screenshot or valid one?
Is there some API that can be called to list transactions by product and e-mail of client?
https://appstoreconnect.apple.com/ - Apple CP is useless for this
There is no method to correlate the customers details with your transaction details. Only Apple can do this.
My first suspicion is that you may have a logic problem in your purchasing process. If implemented correctly, a transient failure at step 3 doesn't matter.
You should:
Create your transaction queue observer a soon as your app starts. This will enable any pending transactions to be delivered to your observer
When you get a purchase transaction in your observer you verify with your server
Only once you have a response from your server that the purchase has been recorded successfully do you call finishTransaction.
This way if something goes wrong with your server or the app crashes the transaction is still pending in the queue.
If you are using auto-renewing and/or non-consumable IAP then I
strongly suggest you provide a "restore purchases" button in your
UI. This makes it simple for the user if something goes wrong or when
they move to a new device.
If you have users who claim that they did not get what they paid for then you can refer them to Apple App Store support who can refund the transaction.
If step three fails you can fall back to local verification and then let the user through for this session (or some number of sessions before you require it to succeed). Unfortunately local authentication is a pain in the ass because the receipt is encrypted. See this link for an example: https://github.com/andrewcbancroft/SwiftyLocalReceiptValidator . You can also report failures of step 3 to your analytics tool so you can see who is actually affected by this issue (obviously this only works if the analytic eventually get an internet connection.
We have a gamme with iAP feature with some issue recently.
Currently the device is to purchase items from Appstore
and the device will send the receipt to server for validation.
After validated, server will give the products (e.g. coins) to player's account.
It ran well for long and there is a user reported that they cannot receive coins from the game.
The user said they have receive confirmation from AppStore but no increase in coins.
Thus, we are thinking if the user has sudden data lost in network and the receipt was not sending to server. (or sent but somehow lost packet)
would like to know:
1. how to search out this purchase history? by code, in Appstore or iTune connects?
2. is there any best practice code to recovery lost receipt or validate the receipt?
Thanks very much
Apple has responded me about this issue.
From their explanation, it sounds like a specific case that the transaction is not completed in their side but it gives a transaction completed message to user.
In an IOS app, I normally validate that purchases have succeeded and been processed by my application by comparing Apple's list of receipts with one that I add to locally when I've processed the purchase myself. This safeguards against things like app crashes during purchase, bugs, etc that can make things get out of sync. I'm trying to do something similar with Amazon.
I have come across statements like this repeatedly in Amazon docs about purchase validation/restoration:
It is possible for a purchase transaction to have more than one Purchase Token representation, so they should not be used as transaction IDs.
This was a huge help as I thought the exact opposite. Unfortunately, I haven't found the rest of the thought: "The transaction ID can be found here:...". I'm starting to think that their transactions don't offer a stable ID...! Please tell me what I'm missing or, if it really doesn't exist, how I can safeguard against the problems I mentioned above?
The initiatePurchaseUpdatesRequest call under Amazon IAP takes an offset parameter which is a permanent identifier for a restore point. Each time you start up you issue an initiatePurchaseUpdatesRequest starting from the last offset you saw (or Offset.BEGINNING the first time). When the response comes in, you save off the offset from the response for the next startup. In this way, any new but unrecorded sales (due to bugs or multiple device issues) will get caught on the next startup. One, minor, impact of this is that you can actually get notified of a purchase twice - once when it occurs and once on the next onPurchaseUpdatesResponse.
As usual you also have the ability for a user to manually request a "restore purchases" that issues the initiatePurchaseUpdatesRequest with the Offset.BEGINNING parameter in case all else fails.
Ps. The actual receipt validation should be performed by calling an Amazon web service from your own server using the receipt values from either the restore or the purchase responses.
With the current Amazon IAP api, keep track of whether you've fulfilled the IAP item by the "requestId" in the PurchaseResponse object. This "requestId" can be used as a sort of pseudo transaction id. You should save this requestId to a server or to the device's local storage.
See the quick start link below for more details:
https://developer.amazon.com/appsandservices/apis/earn/in-app-purchasing/docs/quick-start#7
I've just made iOS app with IAP to purchase virtual coins(Consumable). And the backend is Ruby on Rails. I have some concerns for now about the whole solution.
My current IAP process describes as following:
STEP 1 - iOS Client sends request to our backend and get product ids.
STEP 2 - Client retrieve product list through Store Kit with ids from step1
STEP 3 - User click buy and client sends a payment request to Store Kit
STEP 4 - When finish transaction the client send the receipt token to our backend
STEP 5 - Server verifies the receipt first to make sure it's a valid verification
STEP 6 - Server calls App Store to verify the receipt and deal with the exchange(Recharge account in DB)
STEP 7 - Client gets the response back and displays account balance
I worked on e-commerce/payment solutions before, and IAP takes the other way, though usually the payment gateway will send the receipt server-to-server for verification. And we always have message queue sort of solutions to make sure all transactions are stable and maintainable.
My questions are:
What's the best practice to verify IAP receipt? How to avoid the interruption of verification from our server? (e.g., User spend money and finish the transaction on the client, but fails when verify the receipt on server. No IAP restore transaction support.)
Apple IAP more likely a perfect client solution. Especially in my case, after user's payment, he wants to receives the coins immediately, and not the case we tell him the transaction is processing and his account will be fulfilled soon. To have responsive UX on mobile device is prioritized. Do you still use message queue stuff on server?
Thanks for your time.
You might find http://helios.io/ useful. It combines four useful iOS related gems, one of which is https://github.com/mattt/rack-in-app-purchase
Question 1: According to Apple's docs here, you should always validate receipts on the server. There are a couple of ruby gems that can help with talking to Apple's server on the backend:
https://github.com/gabrielgarza/monza
Hosted: https://getmonza.com
https://github.com/nomad/venice
https://github.com/nov/itunes-receipt
Question 2: This depends how concerned you are with fraud. If you don't validate receipts then you expose yourself to fraud. I would highly recommend validating on the server side.
Checkout this WWDC video that for a nice fundamentals on In App Purchases.
If I understand the question correctly, it looks like there's a gem called itunes-receipt that can be used for this. The gem can be found here: https://github.com/nov/itunes-receipt
There's also an NSScreencast addressing this issue, and the instructions within the show notes look fairly complete. http://nsscreencast.com/episodes/45-validating-iap-receipts