Question

We have a server which amongst other things needs to buy something from a 3rd party (via an API call) before returning the consumable back to the user. Obviously it checks the Apple receipt beforehand.

What is the best way to deal with a server side in-app failure, say if the 3rd party service fails? At this point the user's experience is that of having paid but not received the consumable and trying again would cause them to spend more money.

So far I have come up with:

On device

  1. When inapp completes store the receipt for that productId as 'unclaimed'
  2. Contact server as usual.
  3. If success then clear the unclaimed receipt/productId
  4. If error then next time user tries the same inapp skip the actual purchase part and go straight to 2. with the previous receipt.

Then on server

  1. Verify receipt with apple
  2. Check that we haven't already provided the user with a consumable for that receipt (prevent re-use of receipts)
  3. Do a call to 3rd party
  4. On success return consumable.
  5. On failure reply with an error (at which point the client will keep the receipt as unclaimed and re-send it when trying again).

Thanks in advance!

Was it helpful?

Solution

As far as I understand, your main issue is with the UI/UX related to buying the consumable.

I don't know how your consumable is "visible/usable" to the user, but the key to me would be making it clear to the user that the transaction with the server entered a "temporary failure" state. This is the same as it happens with the App Store when your app download experiences any hindrances. It could be marked as "loading/waiting" and it would be good if instead of "buying" you could make explicit that the consumable will only need to be downloaded ("install/retry/download/reclaim" as opposed to "buy").

It would be also extremely good to have in the same place a "contact us in case of issues" option. I don't know why your 3rd party connection might fail, but if it does on a less than sporadic fashion, I bet more than a couple of users will need to complain.

As to the client-server protocol side of the question, what you describe seems good to me. The key point here is that the server keeps track of which receipt has been already successfully claimed; the client in principle can try to reuse a receipt as many times as it wants, it will only succeeds on the first attempt (before the server marks the receipt as delivered). If you want more resiliency, I would introduce an explicitly acknowledgement phase from the client to the server, confirming that the consumable has been successfully accounted for.

Hope it helps.

OTHER TIPS

my approach would be to make it sort of a transaction:
split your step 2 into 2a, 2b, 2c and to 2d and involve client server

server:

=> 2a = check we haven't used the receipt (in our internal db of used & delivered goods)
-> deliver it if not used

client:

-> get the purchase and do 2b
=> 2b tell the server we received the data!

server:

=> 2c: wait for client confirmation => 2cd= mark the receipt as burned (in our db) as we have delivered it

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top