Open bushev opened 6 months ago
https://github.com/j3k0/cordova-plugin-purchase/issues/1466#issuecomment-1741730584
use app store server api on your server to verify the receipt. the new v13 version of this plugin just sends the cached appStoreReceipt which doesnt change after a purchase. You will need to use the transactionID and send that to an end point to the app store server api. You can get most of the information you need with the apple documentation on the app store server api and a few google searches.
I have implemented a validator method on my server and there I am trying to replace the deprecated IOS VerifyReceipt endpoints with logic that calls the app store server api. However I do not understand how I should get a valid transactionID from the plugin.
Does anybody know?
It is the transaction Id in the json response sent to your server when you purchase an item. Such as
{
// other purchase information
"transaction":
"id": "this is where the transaction id will be"
// other purchase information
}
I read online the endpoint you would use would be the transactions endpoint and send a request to that endpoint with the transaction id and see if it returns with a valid response (will be a json response with information on the purchase). If not then its invalid and it would show an error of some sort.
Also to note, you must use a jwt when sending that request to the apple server api.
In my iPad the validator is called with this:
The transaction has an id but it is NOT the transaction id. So what transaction id do you mean?
I'm in the same boat as @henkkelder
verifyReceipt is being deprecated (https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) and Apple recommends to use https://developer.apple.com/documentation/appstoreserverapi/get_all_subscription_statuses instead.
In order to do that one needs the transactionID or the OriginalTransactonID. However transaction.id when being inside the custom validate method (see screenshot above) is not an transaction ID that can be used with that endpoint to get the subscription status from Apple, I don't know what kind of ID that is (though it is numerical on my end and not "appstore.application").
Would it be possible to expose the transactionID and OriginalTransactionID sow e can migrate away from the deprecated endpoint - Or am I missing something obvious and it is possible to use the new endpoint with the current version of the plugin?
In my iPad the validator is called with this:
The transaction has an id but it is NOT the transaction id. So what transaction id do you mean?
That is the transaction id (to my knowledge) of your app. When the plugin starts it checks the receipt of you owning the application that it running. even on free apps. The transaction ID in the receipt data (that is sent to the CdvPurchase.store.validator url.
On your server you will get the transaction id after you purchase an in app item. If you are doing local validation i am little help there but the data sent with the .verify() method sends the valid transaction id of the purchase where you see "appstore.application" in the screenshot.
I'm in the same boat as @henkkelder
verifyReceipt is being deprecated (https://developer.apple.com/documentation/appstorereceipts/verifyreceipt) and Apple recommends to use https://developer.apple.com/documentation/appstoreserverapi/get_all_subscription_statuses instead.
In order to do that one needs the transactionID or the OriginalTransactonID. However transaction.id when being inside the custom validate method (see screenshot above) is not an transaction ID that can be used with that endpoint to get the subscription status from Apple, I don't know what kind of ID that is (though it is numerical on my end and not "appstore.application").
Would it be possible to expose the transactionID and OriginalTransactionID sow e can migrate away from the deprecated endpoint - Or am I missing something obvious and it is possible to use the new endpoint with the current version of the plugin?
To my knowledge and testing the get_all_subscription_statuses works for subscriptions and not for consumables which is why i suggested to use the transactions endpoint as it will work win consumables and non-consumables. Also the transaction id is there with the receipt data that is sent to the validation server.
I am using the validator method to do validation on my server. That happens each time I initialize the store. Which is nice, because I have noticed that there are users that ask for a refund after installing the non-consumable.
Using the payload (the Body) of the validator I can use the (deprecated) verifyReceipt method that gives me, amongst other things, the transaction Id. That id can be used against appstore api to validate the validity of it.
Are you saying I should act on the Verify() callback from the plugin to get the proper transactionId?
The appStoreReceipt in the json sent to the validator url is the cached receipt when the plugin initializes for the first time (from my experience upgrading my app to use v13.x of this plugin) the transaction id will be the correct id of that current purchase which can be used as is to use with the apple server api.
the transaction id will be the correct id of that current purchase which can be used as is to use with the apple server api.
That is not what I think I see. I get what I showed in the image earlier.
Maybe I just don't understand what you are trying to say? Your last reply is one very long sentence. So I don't understand to what part of the sentence the part between the () refers.
To my knowledge and testing the get_all_subscription_statuses works for subscriptions and not for consumables which is why i suggested to use the transactions endpoint as it will work win consumables and non-consumables. Also the transaction id is there with the receipt data that is sent to the validation server.
I figured it out, sorry it was my mistake. Leaving it here in case anyone stumbled across the same.
So what put me off was the fact that the ID I got from the plugin had more digits than the "normal" ones I resolved via the deprecated verifyReceipt endpoint to get the originalTransactionID. I was using the _get_all_subscriptionstatuses endpoint but got hit with a
{errorCode: 4040010, errorMessage: "Transaction id not found.", retryAfter: 0}
Turns out test purchases from your developer AppleID can't be verified on the production endpoint anymore like it was possible with the verifyReceipt endpoint. After trying this transaction ID against the sandbox endpoint I got it working again.
I am not sure I understand. Currently I use the appStoreReceipt against verifyReceipt endpoint to get the original transactionId. Test purchases return 21007 and need to be verified agains the sandbox version.
After that I can use that TransactionId against the https://api.storekit.itunes.apple.com/inApps/v1/transactions endpoint.
But I still need to call the deprecated verifyReceipt to get from the appStoreReceipt to the transactionid. Or am I missing something?
I could use the it from transaction.id in the verify method. Unfortunately I'm not sure why it is "appstore.application" on your end, on my end it was an ID that I could use against the endpoint. Did you try checking the id after you made a purchase?
The "appstore.application" is the transaction id of the app when you first load up the plugin. In earlier versions it was set to something else. It checks that te user owns the app eve on free apps. But i agree, something is happening that i am not understanding on his end. I am also able to use the transaction id as is from the plugin that is sent to my validation server. I only see the "appstore.application" as the transaction id when the plugin initializes. which i have logic to see it and not try to validate it further by sending it to apple server api.
@henkkelder Maybe share the code you have to use the plugin in your app. With items changed for privacy and security sake that are pertaining to your app. This way we can help further.
The appStoreReceipt in the json sent to the validator url is the cached receipt when the plugin initializes for the first time (from my experience upgrading my app to use v13.x of this plugin) the transaction id will be the correct id of that current purchase which can be used as is to use with the apple server api.
store.getAdapter("ios-appstore").refreshReceipt(); //refreshes the receipt in the latest version you can use that
I must confess I think we are miscommunicating...
As I understand it there are currently 2 ways of validating a purchase.
The existing method of posting to https://buy.itunes.apple.com/verifyReceipt with an appStoreReceipt as payload. This returns a JSON object that contains, amonst other things, the transaction ids of the purchases.
An alternative is doing a GET https://api.storekit.itunes.apple.com/inApps/v1/transactions/_transactionId_. This method needs an transactionId and NOT a receipt.
The verifyReceipt endpoint still works, but is deprecated. See https://developer.apple.com/documentation/appstorereceipts/verifyreceipt.
So I am trying to switch to the storekit endpoint. In order to do so I need a transactionId. But I have not yet found a way that the plugin gives me a valid transactionId when initializing the plugin. And yes, I know I do get a valid one on purchase. But the problem with non-consumables is that a user can ask for a refund. Therefor I want to check the validity of purchases everytime the user visits my 'purchases' page in the app.
Many suggestions here are token about getting an actual receipt, but that is not my problem.
For now I still use the VerifyPurchase method. That works, but somewhere in the future it will stop to work.
There are two ways that i know of that you can check if a product was refunded and that is to use the Get refund history endpoint. you will need a past transaction id of an item that user has made. If you are saving a list of transaction ids on your validation server this would be pretty easy to pull up a past transaction id and get all of the refunds of that user.
The other way to get if a user asked for a refund is to use the refund notification from the Appstore server notofications (which is stated in the refund history endpoint above) Which will send a notification to your validation server as soon as the user gets a refund for the product even if they are not in the app which you can then update your back end with a refunded flag or how ever you choose to do it.
the endpoint is very useful if there is a server outage either on apples side or on yours and you can pull missed refund notifications from that user.
For what is worth; there is a node package that can handle the validation --> https://github.com/apple/app-store-server-library-node
I must confess I think we are miscommunicating...
As I understand it there are currently 2 ways of validating a purchase.
- The existing method of posting to https://buy.itunes.apple.com/verifyReceipt with an appStoreReceipt as payload. This returns a JSON object that contains, amonst other things, the transaction ids of the purchases.
- An alternative is doing a GET https://api.storekit.itunes.apple.com/inApps/v1/transactions/_transactionId_. This method needs an transactionId and NOT a receipt.
The verifyReceipt endpoint still works, but is deprecated. See https://developer.apple.com/documentation/appstorereceipts/verifyreceipt.
So I am trying to switch to the storekit endpoint. In order to do so I need a transactionId. But I have not yet found a way that the plugin gives me a valid transactionId when initializing the plugin. And yes, I know I do get a valid one on purchase. But the problem with non-consumables is that a user can ask for a refund. Therefor I want to check the validity of purchases everytime the user visits my 'purchases' page in the app.
Many suggestions here are token about getting an actual receipt, but that is not my problem.
For now I still use the VerifyPurchase method. That works, but somewhere in the future it will stop to work.
I found out that if the transactionId is coming back as "0", it's because even if you are running the app in your phone through xcode, the purchase is being done through the simulator. To get a valid transactionId number you need to enable the sandbox mode from your AppStore Connect configuration and set up a bogus sandbox AppleId account to use in your app.
Additionally, you need to set the StoreKit configuration on the build to "none" (in Product > Scheme > Edit), otherwise it will run the purchase through a temporary xcode account (that's why the purchase dialog will read "Environment: Xcode". It should read "Environment: Sandbox")
Hi,
I am currently in the process of upgrading to a newer version of the
cordova-plugin-purchase
plugin and have encountered an issue concerning the retrieval of the native Apple purchase receipt.In prior versions, I was able to access the encoded receipt string via
product.transaction.appStoreReceipt
in theapproved(product => ...)
callback. However, with the update, I'm only seeing atransaction
with certain parsed receipt metadata.Our server relies upon using the aforementioned string for validation processes. Could you provide some guidance as to how I may retrieve the receipt in this case?