In our app we verify purchases on our server using the Amazon receipt validation service. The flow is usually: a) user purchases a consumable, b) we send the userId and purchaseToken to our servers for verification c) if valid, we update consumable count on server side and deliver some info back to the application. In order to prevent replays of the "verification" call, other platforms provide a unique identifier (an order ID or a transaction ID). Is there something like this for Amazon IAP? I don't see anything returned from the call that we can use to lookup orders by identifier to see if we are seeing a repeat order or a new one. I was thinking we could use purchaseToken, but I'm not entirely sure if that's guaranteed to be unique and unchangeable. Ideas? Will I need to compute my own unique identifier?
Furthermore, I've noticed that the purchaseToken is identical for multiple purchase of the same consumable (at least using the Sandbox SDK app for fulfillment) so it cannot be used as a unique identifier. What should we use to uniquely identify individual purchases?
You can track the RequestID returned by each method so you can identify a response to its initiator. The PurchaseToken is dynamically generated each time Receipt data is returned and is not a unique order identifier. They are unique values for verifying the Receipt data returned in a response object. The PurchaseToken of a Receipt returned in a PurchaseResponse will be different than the PurchaseToken of a Receipt for the same user and sku returned in a PurchaseUpdatesResponse. Hope this helps. Thank you.
I'm not sure that this helps. Here's where I'm running into a problem (or confusion!). Let's say we want to verify all purchases on our server (this is what our app on other platforms does), here's what happens in detail: 1) User initiates purchase of a consumable 2) User completes purchase of a consumable 3) In our Observer, we execute a call to our server passing along the userId and purchaseToken (HTTP GET) 4) On our server, we verify the purchaseToken using the Amazon API for verification 5) If the request comes back as valid, we update their account on our server and send a success message back to the client Without a way to uniquely identify this specific transaction, what's stopping a user from replaying the call to our server and increasing their consumable count without paying? On other platforms we use the transaction ID given, and if we see the same transaction ID come through that has already been delivered we ignore it. Since there doesn't appear to be a unique identifier included, I'm not sure we can handle transactions the same way. I *could* generate a unique identifier and enforce it all on our side, but I'm trying to keep the code paths for each App Store provider similar. All other platforms provide a transaction or reference ID. We also run into issues if there are billing questions, etc, and a user needs to contact us.. how can we communicate back to Amazon without some kind of order number or transaction ID?
Thank you for your post. We have understand your issue in tracking of IAP purchases. In Live Environment, Currently Amazon IAP not providing unique transaction number or order id for purchasing of IAP items. During Testing environment(SDK tester), SDK tester produces the same purchase token for subsequent purchase of the same consumable item. Since the combination of userid and purchase token is the way to know whether a payment sent to the backend server or not. The live store will generate a different purchase token for each purchase, even if you purchase the same item. As a developer, you have access to the user ID, Purchase Token and SKU for a particular purchase. You need to compute your unique identifier for tracking of purchases based on the above values. Hope this information helps you.
Hello, I have a further question regarding replay attacks. The Receipt Verification Service provides a method to renew an expired token. Couldn't a hacker use this method to generate a fresh token for the same order out of the expired one, and send this to the application's server? If the server only knows about the expired token it wouldn't realize it's a replay of the old order. Thanks, Marius
Hi guys Please dont stop discussion ) I have the same problem I work with AIR framework. So this is real case: 1 User make consumable purchase - coins pack 2 I recieved from OS that purchase is successed 3 Immediatly application send request to my server to validate it 4 But user lost internet connection at this moment. Application cannot verify purchase on the my server and server cann't increase user balance 5 User close application 6 User open application after 3 days 7 Really he made purchase and he wait coins pack on his balance How I can determine that this consumable purchase didn't processed? For example iOs opens transaction for every purchase and it arrives every application start until application close it. Message was edited by: chapayamazon
Amazon IAP does not provide unique identifier for every transaction. So I would suggest you to generate an unique id on your own in the back end for every purchase attempt happening in your client. In the table of your database, you can have fields for unique transaction id (int, unique and autoincreament)and the status (enum value could be like NOT_PURCHASED - default value, PURCHASED) of current attempt. you should insert into that table while user is going to purchase any item in the app before triggering the initiatePurchaseRequest(). Send the transaction id back to client in the response of the same request. You need to also persist the id in the client (sql lite is recomended) and maintain the status of the transaction there (like NOT_PURCHASED - default value, PURCHASED_BUT_NOT_NOTIFIED_TO_GAME_SERVER, PURCHASED_AND_NOTIFIED_TO_GAME_SERVER). If user purchases the item, change the status of the current transaction attempt to "PURCHASED_BUT_NOT_NOTIFIED_TO_GAME_SERVER". Then send request to server to validate the token and change status of transaction attempt in the db table to "PURCHASED". After receiving the response of the this request in the client you should finally change the status of transaction in client to "PURCHASED_AND_NOTIFIED_TO_GAME_SERVER". This way you are maintaining the transaction log in client and server both so that you can sync later on. In start of your app, you can check the local transaction attempt persistence and if any purchase attempt stays in PURCHASED_BUT_NOT_NOTIFIED_TO_GAME_SERVER, you could resend the validation request that time. Hope this helps.