For iOS 6.1 or earlier, in-app purchase transaction ID received after purchase or restore is unique each time and original transaction id never change, even after restore.
However, for iOS7, transaction id and original transaction id is always same! I even tried to refresh receipt, delete app from device and put it back again. Both fields are always same.
Does anyone know in which cases transaction id will change? My server logic was relying on unique transaction ID from receipt itself, which currently doesn't work in case of iOS7.
Following is app receipt decrypted by Apple server. Same result if I decrypt it locally.
{
environment = Sandbox;
receipt = {
"adam_id" = 0;
"application_version" = "1.0";
"bundle_id" = "com.###";
"download_id" = 0;
"in_app" = (
{
"is_trial_period" = false;
"original_purchase_date" = "2014-02-18 14:23:40 Etc/GMT";
"original_purchase_date_ms" = 1392733420000;
"original_purchase_date_pst" = "2014-02-18 06:23:40 America/Los_Angeles";
"original_transaction_id" = 1000000101860870;
"product_id" = "com.###";
"purchase_date" = "2014-02-24 09:12:21 Etc/GMT";
"purchase_date_ms" = 1393233141000;
"purchase_date_pst" = "2014-02-24 01:12:21 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000101860870;
}
);
"original_application_version" = "1.0";
"original_purchase_date" = "2013-08-01 07:00:00 Etc/GMT";
"original_purchase_date_ms" = 1375340400000;
"original_purchase_date_pst" = "2013-08-01 00:00:00 America/Los_Angeles";
"receipt_type" = ProductionSandbox;
"request_date" = "2014-02-24 09:12:56 Etc/GMT";
"request_date_ms" = 1393233176903;
"request_date_pst" = "2014-02-24 01:12:56 America/Los_Angeles";
};
status = 0;
}
The transaction ID is always unique, which means that there are no transaction IDs that are the same. This transaction key is usually generated after the system defines it as a successful one.
To test receipt validation, you must run the app on a real device, as it won't work in the simulator. You'll need a Development Certificate and a sandbox account. When testing an app through XCode, the app won't have a receipt by default.
A transaction ID is a number generated from the electronic transfer of funds. It's a unique identifying number, meaning that no two transaction ID numbers are identical. These numbers can take many forms and are generated with every card transaction.
The Receipt Verification Service (RVS) enables validation of purchases made by your app's users.
Transaction dates are updated correctly
We can make use of the observation that the transaction dates are updated correctly (even in the Sanbox environment and surely in Production):
"in_app":[{"quantity":"1", "product_id":"###",
"transaction_id":"1000000122762089",
"original_transaction_id":"1000000122762089",
"purchase_date":"2014-09-07 16:15:13 Etc/GMT",
"purchase_date_ms": "1410106513000",
"purchase_date_pst":"2014-09-07 09:15:13 America/Los_Angeles",
"original_purchase_date":"2014-09-07 05:35:16 Etc/GMT",
"original_purchase_date_ms":"1410068116000",
"original_purchase_date_pst":"2014-09-06 22:35:16 America/Los_Angeles",
"is_trial_period":"false"}]
You can see that purchase_date_ms
and original_purchase_date_ms
differ.
Therefore: enforce uniqueness of the combination of transcation ID and date
Not only store the transaction ID but also the purchase date (not original purchase date) in your server database. The combination of those two values will not exist in your database for a legitimate restore transaction, but will collide with an existing record if the receipt is a replay.
Note that we are looking a response from the validation server, which means that clients won't be able to vary the date, just as they aren't able to vary the transaction ID without breaking the validity of the receipt.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With