Summary
iOS developers are familiar with StoreKit, a framework that allows them to monetize apps through in-app purchases and subscriptions. For everything to work smoothly, avoid piracy, and make sure users get access to what they purchased developers need to perform receipt validation.
The process begins once a user makes an in-app purchase. After that, developers have to process the App Store receipt, the data of which is Base64-encoded. For a decoded version, you need to pass it through Apple’s verifyReceipt endpoint.
Unfortunately, understanding the decrypted receipt can be an arduous process. There are many nuances and potential pitfalls in the data structure. That’s why, in this article, we will cover each element of the decrypted receipt and help you get a better grasp on how you can avoid common problems.
![The Ultimate Handbook On App-Store](https://framerusercontent.com/images/q0ydnf29EyKr8Gq1HPkeEvulxM.jpg)
Elements of a Decrypted Receipt
responseBody.Receipt
Now that we’ve covered all the responseBody properties, let’s deep dive into the potential elements of responseBody.Receipt.
![](https://framerusercontent.com/images/7VJvrA2zQHkzjPh8unCJEJy0.png)
This may look overwhelming, but don’t worry. We are going to look over each of these properties in more detail so you can get a better understanding of what they mean.
adam_id and app_item_id
This property is generated by App Store Connect and used to uniquely identify the app corresponding with the receipt. It’s a 64-bit long integer that is assigned solely in production. Thus, expect a unique value in production and a 0 in the sandbox.
application_version
Indicates the app’s version number at the time of the receipt’s receipt_creation_date_ms
. It corresponds to CFBundleVersion
(iOS) or CFBundleShortVersionString
(macOS) in the Info.plist. The value is always “1.0” in the sandbox.
bundle_id
This string is provided on App Store Connect and relates to the value of CFBundleIdentifier in the Info.plist file of the app. It’s a bundle identifier to the app to which the receipt belongs.
download_id
This is a unique identifier for the app download transaction. In the sandbox, the field will be populated with a 0, while in production you will see a unique identifier.
Unfortunately, the download_id is not well covered by Apple. It appears to be connected to the download transaction represented by original_application_version
and original_purchase_date
.
expiration_date, expiration_date_pst, expiration_date_ms
Illustrate the time at which the receipt expires for apps bought through the Volume Purchase Program.
For the expiration_date the date-time format is similar to that of ISO 8601. For the expiration_date_pst it’s in the Pacific Time zone. Finally, for expiration_date_ms
it’s in UNIX epoch time format, in milliseconds.
in_app
This is an array that contains in-app purchase receipt fields for all in-app purchase transactions.
original_application_version
Indicates the version of the app that the user originally acquired. If the originally purchased version was 2.5, the value in this field would be 2.5, even if currently the application runs on version 5.0. In the sandbox, the value is always “1.0”.
This number corresponds to CFBundleVersion (iOS) or CFBundleShortVersionString (macOS) from the Info.plist.
Original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original app purchase.
As was the case with the expiration_date
property, the original_purchase_date
has the date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format. original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
preorder_date, preorder_date_pst, preorder_date_ms
If the app was available for pre-orders, this field would indicate the time the user made the pre-order.
preorder_date
property has a date-time format similar to that of ISO 8601. preorder_date_pst
is in the Pacific Time zone format and preorder_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_creation_date, receipt_creation_date_pst, receipt_creation_date_ms
Specify the time at which the App Store generated the receipt.
You probably already got the idea, but let us detail the formats anyway. receipt_creation_date
property has a date-time format similar to that of ISO 8601. Receipt_creation_date_pst is in the Pacific Time zone format and receipt_creation_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_type
Lists the type of the receipt that was generated. The value relates to the environment in which the app or VPP purchase was made. Possible values include:
Production: the receipt was created in the App Store production environment
ProductionVPP: the receipt was created in the VPP production environment
ProductionSandbox: the receipt was created in the App Store sandbox environment
Production VPPSandbox: the receipt was created in the VPP sandbox environment
request_date, request_date_pst, request_date_ms
Show the time the request to the verifyReceipt
endpoint was processed and generated a response.
For the request_date the date-time format is similar to that of ISO 8601. For the request_date_pst it’s in the Pacific Time zone. Finally, for request_date_ms it’s in UNIX epoch time format, in milliseconds.
version_external_identifier
A random number that specifies a revision of the app. In the sandbox, this value is “0”.
responseBody.latest_receipt_info Properties
Time to move on to the properties of responseBody.latest_receipt_info
![](https://framerusercontent.com/images/OAtCCMgZPQl6ZwiSEQ2BzENgHE.png)
Hopefully, you already got used to our format. Just like before, let’s explore each of these keys individually.
cancellation_date, cancellation_date_pst, cancellation_date_ms
Indicate the time at which the subscription was canceled. A couple of things can cause this. First, Apple’s customer support team may have refunded the transaction. Second, if Family Sharing is set up, changes to access could lead to subscription cancellation. Finally, the user may have simply upgraded to a different product.
For the cancellation_date
the date-time format is similar to that of ISO 8601. For the cancellation_date_pst
it’s in the Pacific Time zone. Lastly, for cancellation_date_ms it’s in UNIX epoch time format, in milliseconds.
cancellation_reason
Lists the reason behind the refunded transaction. Possible values are 1 and 0. “1” means that the customer canceled because of an issue within your app. On the other hand, “0” means the cancellation occurred for another reason. Often, if the customer accidentally made the purchase.
expires_date, expires_date_pst, expires_date_ms
Illustrate the time at which the subscription will expire or renew.
Expires_date property has a date-time format similar to that of ISO 8601. expires_date_pst
is in the Pacific Time zone format and expires_date_ms
is in UNIX epoch time format, in milliseconds.
in_app_ownership_type
In this property, you will see whether the user is the purchaser of the product, or rather a family member with access to it through Family Sharing.
The value will either be FAMILY_SHARED
or PURCHASED
.
is_in_intro_offer_period
Illustrates if an auto-renewable subscription is in the introductory price period or not. Possible values are true
and false
. true
indicates that the subscription is in fact in an introductory price period, while false
negates it.
is_trial_period
Specifies whether a subscription is in the free trial period or not.
is_upgraded
This property is only present for upgraded transactions and illustrates if a subscription has been canceled because of an upgrade. The value can only be true
, signifying that this is what happened.
offer_code_ref_name
Only present when a subscription offer code was redeemed. Indicates the reference name of the offer that was set up in App Store Connect.
original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original auto-renewable subscription purchase.
original_purchase_date
property has a date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format and original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
original_transaction_id
Identifies the original purchase transaction.
product_id
Identifies the product purchased as set up for that product in App Store Connect.
promotional_offer_id
Identifies the user’s redeemed subscription offer.
purchase_date, purchase_date_pst, purchase_date_ms
Showcase the time at which the user’s account was charged by the App Store for a subscription purchase or renewal.
Purchase_date property has a date-time format similar to that of ISO 8601. purchase_date_pst
is in the Pacific Time zone format and purchase_date_ms
is in UNIX epoch time format, in milliseconds.
quantity
Illustrates the number of accessible products purchased. Usually 1-10, typically 1.
subscription_group_identifier
Identifies the group to which the subscription belongs.
web_order_line_item_id
This is the primary key for identifying subscription purchases. It identifies purchase occurrences across devices.
transaction_id
Identifies purchases, restores, and renewals. The transaction is a purchase when transaction_id matches original_transaction_id
. If they don’t match then it’s a restore or renewal.
responseBody.pending_renewal_info Properties
Now, let’s take a look at responseBody.pending_renewal_info
properties!
![](https://framerusercontent.com/images/fhrW0qrv5oljUNsmc0RDZifk78I.png)
} ], "latest_receipt": "[new]", "pending_renewal_info": [ { "expiration_intent": "1", "auto_renew_product_id": "test.vip.6month.3d.3999.1", "is_in_billing_retry_period": "0", "product_id": "product.name.1", "original_transaction_id": "100000000000000", "auto_renew_status": "0" } ], "status": 0 }
Copy
auto_renew_product_id
Identifies customer’s unresolved subscription renewal. You will only see this field if the user has downgraded or crossgraded to a different duration subscription for the following period.
auto_renew_status
Indicates whether an auto-renewable subscription will renew at the end of the current subscription period. “1” illustrates that it will and “0” shows that the customer has canceled automatic renewal.
If you see the latter, the customer is at high risk of churn and it might be worth presenting him with a special offer.
expiration_intent
Showcases the reason for subscription expiry. Possible values are 1-5.
1 = the customer canceled the subscription themselves. Consider sending a win-back campaign.
2 = there was a billing error. Consider sending a reminder to update billing information to avoid losing access.
3 = the user didn’t agree to a price increase.
4 = the product was unavailable at the time of renewal.
5 = unknown
grace_period_expires_date, grace_period_expires_date_pst, grace_period_expires_date_ms
Signify the time when the subscription renewal grace period expires.
grace_period_expires_date
property has a date-time format similar to that of ISO 8601. grace_period_expires_date_pst
is in the Pacific Time zone format and Grace_period_expires_date_ms is in UNIX epoch time format, in milliseconds.
is_in_billing_retry_period
Illustrates if the customer’s auto-renewable subscription is in the billing retry period. Possible values are 1
and 0
. The former indicates that the App Store is attempting to renew the subscription while the latter shows it has stopped attempting to renew. If the value is 1
, this is a good time to send a billing update request.
offer_code_ref_name
Showcases the reference name of the subscription offer you set up in App Store Connect. This field is only visible when a subscription offer code was redeemed.
original_transaction_id
Identifies the transaction of the original purchase.
price_consent_status
Indicates the consent status for the subscription price increase. The customer has either consented to the increase or hasn’t. 1
means that the customer has agreed and 0
illustrates that the customer has been notified of the price increase but hasn’t agreed to it yet.
product_id
Identifies that purchased product per your setup in App Store Connect.
Date Format Variations
You have probably noticed that throughout the decrypted receipt there are various date formats:
ISO 8601 -like GMT
ISO 8601 -like PST
UNIX epoch time in milliseconds
But do you already know what these date-time formats mean?
In its documentation, Apple refers to a data-time format similar to the ISO 8601 or an RFC 3339 date. Converting these string-based formats can be difficult, so let’s take a closer look.
As you have seen throughout this document, each base date has two modifiers: _pst and _ms. The former represents ISO 8601-like PST (Pacific Standard Time) and the latter represents milliseconds since UNIX epoch time.
A couple of things you should note:
Be extra careful during Pacific Daylight Time (PDT) because the value remains in PST time.
The easiest format to work with is UNIX epoch time in milliseconds because the majority of modern programming languages can convert it to a native date-time format.
Improve Your Receipt Management
Congratulations! You got through our rundown of decrypted receipt elements.
Hopefully, you now have a better grasp on each of them, but don’t worry if things are still a bit overwhelming. You can always bookmark this page for future reference.
Overall, you’ve probably noticed that decrypted receipts are quite complex. New features are added to the App Store every year and writing good code to manage receipts and leverage everything the Store has to offer is incredibly challenging.
We understand that you may not want to do all of this yourself. That’s precisely why we are here!
If you want to avoid the hassle with StoreKit or don’t want to build your own subscription validation server, you can always turn to Qonversion! You can head to our Apple Receipt Checker right now or explore the Product Center which provides full in-app purchases infrastructure. As developers, you don’t have to perform this time-consuming receipts management anymore. Leave it to us.
iOS developers are familiar with StoreKit, a framework that allows them to monetize apps through in-app purchases and subscriptions. For everything to work smoothly, avoid piracy, and make sure users get access to what they purchased developers need to perform receipt validation.
The process begins once a user makes an in-app purchase. After that, developers have to process the App Store receipt, the data of which is Base64-encoded. For a decoded version, you need to pass it through Apple’s verifyReceipt endpoint.
Unfortunately, understanding the decrypted receipt can be an arduous process. There are many nuances and potential pitfalls in the data structure. That’s why, in this article, we will cover each element of the decrypted receipt and help you get a better grasp on how you can avoid common problems.
![The Ultimate Handbook On App-Store](https://framerusercontent.com/images/q0ydnf29EyKr8Gq1HPkeEvulxM.jpg)
Elements of a Decrypted Receipt
responseBody.Receipt
Now that we’ve covered all the responseBody properties, let’s deep dive into the potential elements of responseBody.Receipt.
![](https://framerusercontent.com/images/7VJvrA2zQHkzjPh8unCJEJy0.png)
This may look overwhelming, but don’t worry. We are going to look over each of these properties in more detail so you can get a better understanding of what they mean.
adam_id and app_item_id
This property is generated by App Store Connect and used to uniquely identify the app corresponding with the receipt. It’s a 64-bit long integer that is assigned solely in production. Thus, expect a unique value in production and a 0 in the sandbox.
application_version
Indicates the app’s version number at the time of the receipt’s receipt_creation_date_ms
. It corresponds to CFBundleVersion
(iOS) or CFBundleShortVersionString
(macOS) in the Info.plist. The value is always “1.0” in the sandbox.
bundle_id
This string is provided on App Store Connect and relates to the value of CFBundleIdentifier in the Info.plist file of the app. It’s a bundle identifier to the app to which the receipt belongs.
download_id
This is a unique identifier for the app download transaction. In the sandbox, the field will be populated with a 0, while in production you will see a unique identifier.
Unfortunately, the download_id is not well covered by Apple. It appears to be connected to the download transaction represented by original_application_version
and original_purchase_date
.
expiration_date, expiration_date_pst, expiration_date_ms
Illustrate the time at which the receipt expires for apps bought through the Volume Purchase Program.
For the expiration_date the date-time format is similar to that of ISO 8601. For the expiration_date_pst it’s in the Pacific Time zone. Finally, for expiration_date_ms
it’s in UNIX epoch time format, in milliseconds.
in_app
This is an array that contains in-app purchase receipt fields for all in-app purchase transactions.
original_application_version
Indicates the version of the app that the user originally acquired. If the originally purchased version was 2.5, the value in this field would be 2.5, even if currently the application runs on version 5.0. In the sandbox, the value is always “1.0”.
This number corresponds to CFBundleVersion (iOS) or CFBundleShortVersionString (macOS) from the Info.plist.
Original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original app purchase.
As was the case with the expiration_date
property, the original_purchase_date
has the date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format. original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
preorder_date, preorder_date_pst, preorder_date_ms
If the app was available for pre-orders, this field would indicate the time the user made the pre-order.
preorder_date
property has a date-time format similar to that of ISO 8601. preorder_date_pst
is in the Pacific Time zone format and preorder_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_creation_date, receipt_creation_date_pst, receipt_creation_date_ms
Specify the time at which the App Store generated the receipt.
You probably already got the idea, but let us detail the formats anyway. receipt_creation_date
property has a date-time format similar to that of ISO 8601. Receipt_creation_date_pst is in the Pacific Time zone format and receipt_creation_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_type
Lists the type of the receipt that was generated. The value relates to the environment in which the app or VPP purchase was made. Possible values include:
Production: the receipt was created in the App Store production environment
ProductionVPP: the receipt was created in the VPP production environment
ProductionSandbox: the receipt was created in the App Store sandbox environment
Production VPPSandbox: the receipt was created in the VPP sandbox environment
request_date, request_date_pst, request_date_ms
Show the time the request to the verifyReceipt
endpoint was processed and generated a response.
For the request_date the date-time format is similar to that of ISO 8601. For the request_date_pst it’s in the Pacific Time zone. Finally, for request_date_ms it’s in UNIX epoch time format, in milliseconds.
version_external_identifier
A random number that specifies a revision of the app. In the sandbox, this value is “0”.
responseBody.latest_receipt_info Properties
Time to move on to the properties of responseBody.latest_receipt_info
![](https://framerusercontent.com/images/OAtCCMgZPQl6ZwiSEQ2BzENgHE.png)
Hopefully, you already got used to our format. Just like before, let’s explore each of these keys individually.
cancellation_date, cancellation_date_pst, cancellation_date_ms
Indicate the time at which the subscription was canceled. A couple of things can cause this. First, Apple’s customer support team may have refunded the transaction. Second, if Family Sharing is set up, changes to access could lead to subscription cancellation. Finally, the user may have simply upgraded to a different product.
For the cancellation_date
the date-time format is similar to that of ISO 8601. For the cancellation_date_pst
it’s in the Pacific Time zone. Lastly, for cancellation_date_ms it’s in UNIX epoch time format, in milliseconds.
cancellation_reason
Lists the reason behind the refunded transaction. Possible values are 1 and 0. “1” means that the customer canceled because of an issue within your app. On the other hand, “0” means the cancellation occurred for another reason. Often, if the customer accidentally made the purchase.
expires_date, expires_date_pst, expires_date_ms
Illustrate the time at which the subscription will expire or renew.
Expires_date property has a date-time format similar to that of ISO 8601. expires_date_pst
is in the Pacific Time zone format and expires_date_ms
is in UNIX epoch time format, in milliseconds.
in_app_ownership_type
In this property, you will see whether the user is the purchaser of the product, or rather a family member with access to it through Family Sharing.
The value will either be FAMILY_SHARED
or PURCHASED
.
is_in_intro_offer_period
Illustrates if an auto-renewable subscription is in the introductory price period or not. Possible values are true
and false
. true
indicates that the subscription is in fact in an introductory price period, while false
negates it.
is_trial_period
Specifies whether a subscription is in the free trial period or not.
is_upgraded
This property is only present for upgraded transactions and illustrates if a subscription has been canceled because of an upgrade. The value can only be true
, signifying that this is what happened.
offer_code_ref_name
Only present when a subscription offer code was redeemed. Indicates the reference name of the offer that was set up in App Store Connect.
original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original auto-renewable subscription purchase.
original_purchase_date
property has a date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format and original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
original_transaction_id
Identifies the original purchase transaction.
product_id
Identifies the product purchased as set up for that product in App Store Connect.
promotional_offer_id
Identifies the user’s redeemed subscription offer.
purchase_date, purchase_date_pst, purchase_date_ms
Showcase the time at which the user’s account was charged by the App Store for a subscription purchase or renewal.
Purchase_date property has a date-time format similar to that of ISO 8601. purchase_date_pst
is in the Pacific Time zone format and purchase_date_ms
is in UNIX epoch time format, in milliseconds.
quantity
Illustrates the number of accessible products purchased. Usually 1-10, typically 1.
subscription_group_identifier
Identifies the group to which the subscription belongs.
web_order_line_item_id
This is the primary key for identifying subscription purchases. It identifies purchase occurrences across devices.
transaction_id
Identifies purchases, restores, and renewals. The transaction is a purchase when transaction_id matches original_transaction_id
. If they don’t match then it’s a restore or renewal.
responseBody.pending_renewal_info Properties
Now, let’s take a look at responseBody.pending_renewal_info
properties!
![](https://framerusercontent.com/images/fhrW0qrv5oljUNsmc0RDZifk78I.png)
} ], "latest_receipt": "[new]", "pending_renewal_info": [ { "expiration_intent": "1", "auto_renew_product_id": "test.vip.6month.3d.3999.1", "is_in_billing_retry_period": "0", "product_id": "product.name.1", "original_transaction_id": "100000000000000", "auto_renew_status": "0" } ], "status": 0 }
Copy
auto_renew_product_id
Identifies customer’s unresolved subscription renewal. You will only see this field if the user has downgraded or crossgraded to a different duration subscription for the following period.
auto_renew_status
Indicates whether an auto-renewable subscription will renew at the end of the current subscription period. “1” illustrates that it will and “0” shows that the customer has canceled automatic renewal.
If you see the latter, the customer is at high risk of churn and it might be worth presenting him with a special offer.
expiration_intent
Showcases the reason for subscription expiry. Possible values are 1-5.
1 = the customer canceled the subscription themselves. Consider sending a win-back campaign.
2 = there was a billing error. Consider sending a reminder to update billing information to avoid losing access.
3 = the user didn’t agree to a price increase.
4 = the product was unavailable at the time of renewal.
5 = unknown
grace_period_expires_date, grace_period_expires_date_pst, grace_period_expires_date_ms
Signify the time when the subscription renewal grace period expires.
grace_period_expires_date
property has a date-time format similar to that of ISO 8601. grace_period_expires_date_pst
is in the Pacific Time zone format and Grace_period_expires_date_ms is in UNIX epoch time format, in milliseconds.
is_in_billing_retry_period
Illustrates if the customer’s auto-renewable subscription is in the billing retry period. Possible values are 1
and 0
. The former indicates that the App Store is attempting to renew the subscription while the latter shows it has stopped attempting to renew. If the value is 1
, this is a good time to send a billing update request.
offer_code_ref_name
Showcases the reference name of the subscription offer you set up in App Store Connect. This field is only visible when a subscription offer code was redeemed.
original_transaction_id
Identifies the transaction of the original purchase.
price_consent_status
Indicates the consent status for the subscription price increase. The customer has either consented to the increase or hasn’t. 1
means that the customer has agreed and 0
illustrates that the customer has been notified of the price increase but hasn’t agreed to it yet.
product_id
Identifies that purchased product per your setup in App Store Connect.
Date Format Variations
You have probably noticed that throughout the decrypted receipt there are various date formats:
ISO 8601 -like GMT
ISO 8601 -like PST
UNIX epoch time in milliseconds
But do you already know what these date-time formats mean?
In its documentation, Apple refers to a data-time format similar to the ISO 8601 or an RFC 3339 date. Converting these string-based formats can be difficult, so let’s take a closer look.
As you have seen throughout this document, each base date has two modifiers: _pst and _ms. The former represents ISO 8601-like PST (Pacific Standard Time) and the latter represents milliseconds since UNIX epoch time.
A couple of things you should note:
Be extra careful during Pacific Daylight Time (PDT) because the value remains in PST time.
The easiest format to work with is UNIX epoch time in milliseconds because the majority of modern programming languages can convert it to a native date-time format.
Improve Your Receipt Management
Congratulations! You got through our rundown of decrypted receipt elements.
Hopefully, you now have a better grasp on each of them, but don’t worry if things are still a bit overwhelming. You can always bookmark this page for future reference.
Overall, you’ve probably noticed that decrypted receipts are quite complex. New features are added to the App Store every year and writing good code to manage receipts and leverage everything the Store has to offer is incredibly challenging.
We understand that you may not want to do all of this yourself. That’s precisely why we are here!
If you want to avoid the hassle with StoreKit or don’t want to build your own subscription validation server, you can always turn to Qonversion! You can head to our Apple Receipt Checker right now or explore the Product Center which provides full in-app purchases infrastructure. As developers, you don’t have to perform this time-consuming receipts management anymore. Leave it to us.
iOS developers are familiar with StoreKit, a framework that allows them to monetize apps through in-app purchases and subscriptions. For everything to work smoothly, avoid piracy, and make sure users get access to what they purchased developers need to perform receipt validation.
The process begins once a user makes an in-app purchase. After that, developers have to process the App Store receipt, the data of which is Base64-encoded. For a decoded version, you need to pass it through Apple’s verifyReceipt endpoint.
Unfortunately, understanding the decrypted receipt can be an arduous process. There are many nuances and potential pitfalls in the data structure. That’s why, in this article, we will cover each element of the decrypted receipt and help you get a better grasp on how you can avoid common problems.
![The Ultimate Handbook On App-Store](https://framerusercontent.com/images/q0ydnf29EyKr8Gq1HPkeEvulxM.jpg)
Elements of a Decrypted Receipt
responseBody.Receipt
Now that we’ve covered all the responseBody properties, let’s deep dive into the potential elements of responseBody.Receipt.
![](https://framerusercontent.com/images/7VJvrA2zQHkzjPh8unCJEJy0.png)
This may look overwhelming, but don’t worry. We are going to look over each of these properties in more detail so you can get a better understanding of what they mean.
adam_id and app_item_id
This property is generated by App Store Connect and used to uniquely identify the app corresponding with the receipt. It’s a 64-bit long integer that is assigned solely in production. Thus, expect a unique value in production and a 0 in the sandbox.
application_version
Indicates the app’s version number at the time of the receipt’s receipt_creation_date_ms
. It corresponds to CFBundleVersion
(iOS) or CFBundleShortVersionString
(macOS) in the Info.plist. The value is always “1.0” in the sandbox.
bundle_id
This string is provided on App Store Connect and relates to the value of CFBundleIdentifier in the Info.plist file of the app. It’s a bundle identifier to the app to which the receipt belongs.
download_id
This is a unique identifier for the app download transaction. In the sandbox, the field will be populated with a 0, while in production you will see a unique identifier.
Unfortunately, the download_id is not well covered by Apple. It appears to be connected to the download transaction represented by original_application_version
and original_purchase_date
.
expiration_date, expiration_date_pst, expiration_date_ms
Illustrate the time at which the receipt expires for apps bought through the Volume Purchase Program.
For the expiration_date the date-time format is similar to that of ISO 8601. For the expiration_date_pst it’s in the Pacific Time zone. Finally, for expiration_date_ms
it’s in UNIX epoch time format, in milliseconds.
in_app
This is an array that contains in-app purchase receipt fields for all in-app purchase transactions.
original_application_version
Indicates the version of the app that the user originally acquired. If the originally purchased version was 2.5, the value in this field would be 2.5, even if currently the application runs on version 5.0. In the sandbox, the value is always “1.0”.
This number corresponds to CFBundleVersion (iOS) or CFBundleShortVersionString (macOS) from the Info.plist.
Original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original app purchase.
As was the case with the expiration_date
property, the original_purchase_date
has the date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format. original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
preorder_date, preorder_date_pst, preorder_date_ms
If the app was available for pre-orders, this field would indicate the time the user made the pre-order.
preorder_date
property has a date-time format similar to that of ISO 8601. preorder_date_pst
is in the Pacific Time zone format and preorder_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_creation_date, receipt_creation_date_pst, receipt_creation_date_ms
Specify the time at which the App Store generated the receipt.
You probably already got the idea, but let us detail the formats anyway. receipt_creation_date
property has a date-time format similar to that of ISO 8601. Receipt_creation_date_pst is in the Pacific Time zone format and receipt_creation_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_type
Lists the type of the receipt that was generated. The value relates to the environment in which the app or VPP purchase was made. Possible values include:
Production: the receipt was created in the App Store production environment
ProductionVPP: the receipt was created in the VPP production environment
ProductionSandbox: the receipt was created in the App Store sandbox environment
Production VPPSandbox: the receipt was created in the VPP sandbox environment
request_date, request_date_pst, request_date_ms
Show the time the request to the verifyReceipt
endpoint was processed and generated a response.
For the request_date the date-time format is similar to that of ISO 8601. For the request_date_pst it’s in the Pacific Time zone. Finally, for request_date_ms it’s in UNIX epoch time format, in milliseconds.
version_external_identifier
A random number that specifies a revision of the app. In the sandbox, this value is “0”.
responseBody.latest_receipt_info Properties
Time to move on to the properties of responseBody.latest_receipt_info
![](https://framerusercontent.com/images/OAtCCMgZPQl6ZwiSEQ2BzENgHE.png)
Hopefully, you already got used to our format. Just like before, let’s explore each of these keys individually.
cancellation_date, cancellation_date_pst, cancellation_date_ms
Indicate the time at which the subscription was canceled. A couple of things can cause this. First, Apple’s customer support team may have refunded the transaction. Second, if Family Sharing is set up, changes to access could lead to subscription cancellation. Finally, the user may have simply upgraded to a different product.
For the cancellation_date
the date-time format is similar to that of ISO 8601. For the cancellation_date_pst
it’s in the Pacific Time zone. Lastly, for cancellation_date_ms it’s in UNIX epoch time format, in milliseconds.
cancellation_reason
Lists the reason behind the refunded transaction. Possible values are 1 and 0. “1” means that the customer canceled because of an issue within your app. On the other hand, “0” means the cancellation occurred for another reason. Often, if the customer accidentally made the purchase.
expires_date, expires_date_pst, expires_date_ms
Illustrate the time at which the subscription will expire or renew.
Expires_date property has a date-time format similar to that of ISO 8601. expires_date_pst
is in the Pacific Time zone format and expires_date_ms
is in UNIX epoch time format, in milliseconds.
in_app_ownership_type
In this property, you will see whether the user is the purchaser of the product, or rather a family member with access to it through Family Sharing.
The value will either be FAMILY_SHARED
or PURCHASED
.
is_in_intro_offer_period
Illustrates if an auto-renewable subscription is in the introductory price period or not. Possible values are true
and false
. true
indicates that the subscription is in fact in an introductory price period, while false
negates it.
is_trial_period
Specifies whether a subscription is in the free trial period or not.
is_upgraded
This property is only present for upgraded transactions and illustrates if a subscription has been canceled because of an upgrade. The value can only be true
, signifying that this is what happened.
offer_code_ref_name
Only present when a subscription offer code was redeemed. Indicates the reference name of the offer that was set up in App Store Connect.
original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original auto-renewable subscription purchase.
original_purchase_date
property has a date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format and original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
original_transaction_id
Identifies the original purchase transaction.
product_id
Identifies the product purchased as set up for that product in App Store Connect.
promotional_offer_id
Identifies the user’s redeemed subscription offer.
purchase_date, purchase_date_pst, purchase_date_ms
Showcase the time at which the user’s account was charged by the App Store for a subscription purchase or renewal.
Purchase_date property has a date-time format similar to that of ISO 8601. purchase_date_pst
is in the Pacific Time zone format and purchase_date_ms
is in UNIX epoch time format, in milliseconds.
quantity
Illustrates the number of accessible products purchased. Usually 1-10, typically 1.
subscription_group_identifier
Identifies the group to which the subscription belongs.
web_order_line_item_id
This is the primary key for identifying subscription purchases. It identifies purchase occurrences across devices.
transaction_id
Identifies purchases, restores, and renewals. The transaction is a purchase when transaction_id matches original_transaction_id
. If they don’t match then it’s a restore or renewal.
responseBody.pending_renewal_info Properties
Now, let’s take a look at responseBody.pending_renewal_info
properties!
![](https://framerusercontent.com/images/fhrW0qrv5oljUNsmc0RDZifk78I.png)
} ], "latest_receipt": "[new]", "pending_renewal_info": [ { "expiration_intent": "1", "auto_renew_product_id": "test.vip.6month.3d.3999.1", "is_in_billing_retry_period": "0", "product_id": "product.name.1", "original_transaction_id": "100000000000000", "auto_renew_status": "0" } ], "status": 0 }
Copy
auto_renew_product_id
Identifies customer’s unresolved subscription renewal. You will only see this field if the user has downgraded or crossgraded to a different duration subscription for the following period.
auto_renew_status
Indicates whether an auto-renewable subscription will renew at the end of the current subscription period. “1” illustrates that it will and “0” shows that the customer has canceled automatic renewal.
If you see the latter, the customer is at high risk of churn and it might be worth presenting him with a special offer.
expiration_intent
Showcases the reason for subscription expiry. Possible values are 1-5.
1 = the customer canceled the subscription themselves. Consider sending a win-back campaign.
2 = there was a billing error. Consider sending a reminder to update billing information to avoid losing access.
3 = the user didn’t agree to a price increase.
4 = the product was unavailable at the time of renewal.
5 = unknown
grace_period_expires_date, grace_period_expires_date_pst, grace_period_expires_date_ms
Signify the time when the subscription renewal grace period expires.
grace_period_expires_date
property has a date-time format similar to that of ISO 8601. grace_period_expires_date_pst
is in the Pacific Time zone format and Grace_period_expires_date_ms is in UNIX epoch time format, in milliseconds.
is_in_billing_retry_period
Illustrates if the customer’s auto-renewable subscription is in the billing retry period. Possible values are 1
and 0
. The former indicates that the App Store is attempting to renew the subscription while the latter shows it has stopped attempting to renew. If the value is 1
, this is a good time to send a billing update request.
offer_code_ref_name
Showcases the reference name of the subscription offer you set up in App Store Connect. This field is only visible when a subscription offer code was redeemed.
original_transaction_id
Identifies the transaction of the original purchase.
price_consent_status
Indicates the consent status for the subscription price increase. The customer has either consented to the increase or hasn’t. 1
means that the customer has agreed and 0
illustrates that the customer has been notified of the price increase but hasn’t agreed to it yet.
product_id
Identifies that purchased product per your setup in App Store Connect.
Date Format Variations
You have probably noticed that throughout the decrypted receipt there are various date formats:
ISO 8601 -like GMT
ISO 8601 -like PST
UNIX epoch time in milliseconds
But do you already know what these date-time formats mean?
In its documentation, Apple refers to a data-time format similar to the ISO 8601 or an RFC 3339 date. Converting these string-based formats can be difficult, so let’s take a closer look.
As you have seen throughout this document, each base date has two modifiers: _pst and _ms. The former represents ISO 8601-like PST (Pacific Standard Time) and the latter represents milliseconds since UNIX epoch time.
A couple of things you should note:
Be extra careful during Pacific Daylight Time (PDT) because the value remains in PST time.
The easiest format to work with is UNIX epoch time in milliseconds because the majority of modern programming languages can convert it to a native date-time format.
Improve Your Receipt Management
Congratulations! You got through our rundown of decrypted receipt elements.
Hopefully, you now have a better grasp on each of them, but don’t worry if things are still a bit overwhelming. You can always bookmark this page for future reference.
Overall, you’ve probably noticed that decrypted receipts are quite complex. New features are added to the App Store every year and writing good code to manage receipts and leverage everything the Store has to offer is incredibly challenging.
We understand that you may not want to do all of this yourself. That’s precisely why we are here!
If you want to avoid the hassle with StoreKit or don’t want to build your own subscription validation server, you can always turn to Qonversion! You can head to our Apple Receipt Checker right now or explore the Product Center which provides full in-app purchases infrastructure. As developers, you don’t have to perform this time-consuming receipts management anymore. Leave it to us.
iOS developers are familiar with StoreKit, a framework that allows them to monetize apps through in-app purchases and subscriptions. For everything to work smoothly, avoid piracy, and make sure users get access to what they purchased developers need to perform receipt validation.
The process begins once a user makes an in-app purchase. After that, developers have to process the App Store receipt, the data of which is Base64-encoded. For a decoded version, you need to pass it through Apple’s verifyReceipt endpoint.
Unfortunately, understanding the decrypted receipt can be an arduous process. There are many nuances and potential pitfalls in the data structure. That’s why, in this article, we will cover each element of the decrypted receipt and help you get a better grasp on how you can avoid common problems.
![The Ultimate Handbook On App-Store](https://framerusercontent.com/images/q0ydnf29EyKr8Gq1HPkeEvulxM.jpg)
Elements of a Decrypted Receipt
responseBody.Receipt
Now that we’ve covered all the responseBody properties, let’s deep dive into the potential elements of responseBody.Receipt.
![](https://framerusercontent.com/images/7VJvrA2zQHkzjPh8unCJEJy0.png)
This may look overwhelming, but don’t worry. We are going to look over each of these properties in more detail so you can get a better understanding of what they mean.
adam_id and app_item_id
This property is generated by App Store Connect and used to uniquely identify the app corresponding with the receipt. It’s a 64-bit long integer that is assigned solely in production. Thus, expect a unique value in production and a 0 in the sandbox.
application_version
Indicates the app’s version number at the time of the receipt’s receipt_creation_date_ms
. It corresponds to CFBundleVersion
(iOS) or CFBundleShortVersionString
(macOS) in the Info.plist. The value is always “1.0” in the sandbox.
bundle_id
This string is provided on App Store Connect and relates to the value of CFBundleIdentifier in the Info.plist file of the app. It’s a bundle identifier to the app to which the receipt belongs.
download_id
This is a unique identifier for the app download transaction. In the sandbox, the field will be populated with a 0, while in production you will see a unique identifier.
Unfortunately, the download_id is not well covered by Apple. It appears to be connected to the download transaction represented by original_application_version
and original_purchase_date
.
expiration_date, expiration_date_pst, expiration_date_ms
Illustrate the time at which the receipt expires for apps bought through the Volume Purchase Program.
For the expiration_date the date-time format is similar to that of ISO 8601. For the expiration_date_pst it’s in the Pacific Time zone. Finally, for expiration_date_ms
it’s in UNIX epoch time format, in milliseconds.
in_app
This is an array that contains in-app purchase receipt fields for all in-app purchase transactions.
original_application_version
Indicates the version of the app that the user originally acquired. If the originally purchased version was 2.5, the value in this field would be 2.5, even if currently the application runs on version 5.0. In the sandbox, the value is always “1.0”.
This number corresponds to CFBundleVersion (iOS) or CFBundleShortVersionString (macOS) from the Info.plist.
Original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original app purchase.
As was the case with the expiration_date
property, the original_purchase_date
has the date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format. original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
preorder_date, preorder_date_pst, preorder_date_ms
If the app was available for pre-orders, this field would indicate the time the user made the pre-order.
preorder_date
property has a date-time format similar to that of ISO 8601. preorder_date_pst
is in the Pacific Time zone format and preorder_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_creation_date, receipt_creation_date_pst, receipt_creation_date_ms
Specify the time at which the App Store generated the receipt.
You probably already got the idea, but let us detail the formats anyway. receipt_creation_date
property has a date-time format similar to that of ISO 8601. Receipt_creation_date_pst is in the Pacific Time zone format and receipt_creation_date_ms
is in UNIX epoch time format, in milliseconds.
receipt_type
Lists the type of the receipt that was generated. The value relates to the environment in which the app or VPP purchase was made. Possible values include:
Production: the receipt was created in the App Store production environment
ProductionVPP: the receipt was created in the VPP production environment
ProductionSandbox: the receipt was created in the App Store sandbox environment
Production VPPSandbox: the receipt was created in the VPP sandbox environment
request_date, request_date_pst, request_date_ms
Show the time the request to the verifyReceipt
endpoint was processed and generated a response.
For the request_date the date-time format is similar to that of ISO 8601. For the request_date_pst it’s in the Pacific Time zone. Finally, for request_date_ms it’s in UNIX epoch time format, in milliseconds.
version_external_identifier
A random number that specifies a revision of the app. In the sandbox, this value is “0”.
responseBody.latest_receipt_info Properties
Time to move on to the properties of responseBody.latest_receipt_info
![](https://framerusercontent.com/images/OAtCCMgZPQl6ZwiSEQ2BzENgHE.png)
Hopefully, you already got used to our format. Just like before, let’s explore each of these keys individually.
cancellation_date, cancellation_date_pst, cancellation_date_ms
Indicate the time at which the subscription was canceled. A couple of things can cause this. First, Apple’s customer support team may have refunded the transaction. Second, if Family Sharing is set up, changes to access could lead to subscription cancellation. Finally, the user may have simply upgraded to a different product.
For the cancellation_date
the date-time format is similar to that of ISO 8601. For the cancellation_date_pst
it’s in the Pacific Time zone. Lastly, for cancellation_date_ms it’s in UNIX epoch time format, in milliseconds.
cancellation_reason
Lists the reason behind the refunded transaction. Possible values are 1 and 0. “1” means that the customer canceled because of an issue within your app. On the other hand, “0” means the cancellation occurred for another reason. Often, if the customer accidentally made the purchase.
expires_date, expires_date_pst, expires_date_ms
Illustrate the time at which the subscription will expire or renew.
Expires_date property has a date-time format similar to that of ISO 8601. expires_date_pst
is in the Pacific Time zone format and expires_date_ms
is in UNIX epoch time format, in milliseconds.
in_app_ownership_type
In this property, you will see whether the user is the purchaser of the product, or rather a family member with access to it through Family Sharing.
The value will either be FAMILY_SHARED
or PURCHASED
.
is_in_intro_offer_period
Illustrates if an auto-renewable subscription is in the introductory price period or not. Possible values are true
and false
. true
indicates that the subscription is in fact in an introductory price period, while false
negates it.
is_trial_period
Specifies whether a subscription is in the free trial period or not.
is_upgraded
This property is only present for upgraded transactions and illustrates if a subscription has been canceled because of an upgrade. The value can only be true
, signifying that this is what happened.
offer_code_ref_name
Only present when a subscription offer code was redeemed. Indicates the reference name of the offer that was set up in App Store Connect.
original_purchase_date, original_purchase_date_pst, original_purchase_date_ms
Illustrate the time of the original auto-renewable subscription purchase.
original_purchase_date
property has a date-time format similar to that of ISO 8601. original_purchase_date_pst
is in the Pacific Time zone format and original_purchase_date_ms
is in UNIX epoch time format, in milliseconds.
original_transaction_id
Identifies the original purchase transaction.
product_id
Identifies the product purchased as set up for that product in App Store Connect.
promotional_offer_id
Identifies the user’s redeemed subscription offer.
purchase_date, purchase_date_pst, purchase_date_ms
Showcase the time at which the user’s account was charged by the App Store for a subscription purchase or renewal.
Purchase_date property has a date-time format similar to that of ISO 8601. purchase_date_pst
is in the Pacific Time zone format and purchase_date_ms
is in UNIX epoch time format, in milliseconds.
quantity
Illustrates the number of accessible products purchased. Usually 1-10, typically 1.
subscription_group_identifier
Identifies the group to which the subscription belongs.
web_order_line_item_id
This is the primary key for identifying subscription purchases. It identifies purchase occurrences across devices.
transaction_id
Identifies purchases, restores, and renewals. The transaction is a purchase when transaction_id matches original_transaction_id
. If they don’t match then it’s a restore or renewal.
responseBody.pending_renewal_info Properties
Now, let’s take a look at responseBody.pending_renewal_info
properties!
![](https://framerusercontent.com/images/fhrW0qrv5oljUNsmc0RDZifk78I.png)
} ], "latest_receipt": "[new]", "pending_renewal_info": [ { "expiration_intent": "1", "auto_renew_product_id": "test.vip.6month.3d.3999.1", "is_in_billing_retry_period": "0", "product_id": "product.name.1", "original_transaction_id": "100000000000000", "auto_renew_status": "0" } ], "status": 0 }
Copy
auto_renew_product_id
Identifies customer’s unresolved subscription renewal. You will only see this field if the user has downgraded or crossgraded to a different duration subscription for the following period.
auto_renew_status
Indicates whether an auto-renewable subscription will renew at the end of the current subscription period. “1” illustrates that it will and “0” shows that the customer has canceled automatic renewal.
If you see the latter, the customer is at high risk of churn and it might be worth presenting him with a special offer.
expiration_intent
Showcases the reason for subscription expiry. Possible values are 1-5.
1 = the customer canceled the subscription themselves. Consider sending a win-back campaign.
2 = there was a billing error. Consider sending a reminder to update billing information to avoid losing access.
3 = the user didn’t agree to a price increase.
4 = the product was unavailable at the time of renewal.
5 = unknown
grace_period_expires_date, grace_period_expires_date_pst, grace_period_expires_date_ms
Signify the time when the subscription renewal grace period expires.
grace_period_expires_date
property has a date-time format similar to that of ISO 8601. grace_period_expires_date_pst
is in the Pacific Time zone format and Grace_period_expires_date_ms is in UNIX epoch time format, in milliseconds.
is_in_billing_retry_period
Illustrates if the customer’s auto-renewable subscription is in the billing retry period. Possible values are 1
and 0
. The former indicates that the App Store is attempting to renew the subscription while the latter shows it has stopped attempting to renew. If the value is 1
, this is a good time to send a billing update request.
offer_code_ref_name
Showcases the reference name of the subscription offer you set up in App Store Connect. This field is only visible when a subscription offer code was redeemed.
original_transaction_id
Identifies the transaction of the original purchase.
price_consent_status
Indicates the consent status for the subscription price increase. The customer has either consented to the increase or hasn’t. 1
means that the customer has agreed and 0
illustrates that the customer has been notified of the price increase but hasn’t agreed to it yet.
product_id
Identifies that purchased product per your setup in App Store Connect.
Date Format Variations
You have probably noticed that throughout the decrypted receipt there are various date formats:
ISO 8601 -like GMT
ISO 8601 -like PST
UNIX epoch time in milliseconds
But do you already know what these date-time formats mean?
In its documentation, Apple refers to a data-time format similar to the ISO 8601 or an RFC 3339 date. Converting these string-based formats can be difficult, so let’s take a closer look.
As you have seen throughout this document, each base date has two modifiers: _pst and _ms. The former represents ISO 8601-like PST (Pacific Standard Time) and the latter represents milliseconds since UNIX epoch time.
A couple of things you should note:
Be extra careful during Pacific Daylight Time (PDT) because the value remains in PST time.
The easiest format to work with is UNIX epoch time in milliseconds because the majority of modern programming languages can convert it to a native date-time format.
Improve Your Receipt Management
Congratulations! You got through our rundown of decrypted receipt elements.
Hopefully, you now have a better grasp on each of them, but don’t worry if things are still a bit overwhelming. You can always bookmark this page for future reference.
Overall, you’ve probably noticed that decrypted receipts are quite complex. New features are added to the App Store every year and writing good code to manage receipts and leverage everything the Store has to offer is incredibly challenging.
We understand that you may not want to do all of this yourself. That’s precisely why we are here!
If you want to avoid the hassle with StoreKit or don’t want to build your own subscription validation server, you can always turn to Qonversion! You can head to our Apple Receipt Checker right now or explore the Product Center which provides full in-app purchases infrastructure. As developers, you don’t have to perform this time-consuming receipts management anymore. Leave it to us.
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Start Now for Free
Or book a demo with our team to learn more about Qonversion
Read more
Read more
![Trash Panda App partners with Qonversion](https://framerusercontent.com/images/fIjbGE1BlBzu0OZK7vCihIvo.webp)
Trash Panda Maximizes App Revenue after Setting the Best Subscription Price with A/B Tests
Jul 8, 2024
Jul 8, 2024
![StyleDNA with Qonversion](https://framerusercontent.com/images/0CYKPTzYfOn6vdokDrwSoFR4c.webp)
How StyleDNA Saved 20% Development Time and Unlocked New Features
Jun 19, 2024
Jun 19, 2024
![WWDC 24 updates](https://framerusercontent.com/images/OFmq7UmE6o7QKdnnbRBNKtgo.png)
WWDC24 Updates for App Developers | What's new in Storekit 2 and App Store Server API?
Jun 17, 2024
Jun 17, 2024
![Parenting by Iben Sandahl uses Qonversion](https://framerusercontent.com/images/qJ2twjlmMxXqQ2MggeZqrVbB580.webp)
How A/B Testing with Qonversion Helped Iben Sandahl’s Parenting App Double Their Sales
Jun 13, 2024
Jun 13, 2024
![Trash Panda App partners with Qonversion](https://framerusercontent.com/images/fIjbGE1BlBzu0OZK7vCihIvo.webp)
Trash Panda Maximizes App Revenue after Setting the Best Subscription Price with A/B Tests
Jul 8, 2024
Jul 8, 2024
![StyleDNA with Qonversion](https://framerusercontent.com/images/0CYKPTzYfOn6vdokDrwSoFR4c.webp)
How StyleDNA Saved 20% Development Time and Unlocked New Features
Jun 19, 2024
Jun 19, 2024
![WWDC 24 updates](https://framerusercontent.com/images/OFmq7UmE6o7QKdnnbRBNKtgo.png)
WWDC24 Updates for App Developers | What's new in Storekit 2 and App Store Server API?
Jun 17, 2024
Jun 17, 2024