TN3122: Receipt validation with the App Store fails with a non-zero error code
Identify common configurations that cause unsuccessful receipt validation with the App Store.
Overview
Receipt validation with the App Store requires that you send a JSON object with the receipt-data and password keys, and optionally the exclude-old-transactions key as detailed in requestBody. The App Store responds with a value of 0 if validation was successful, and a status code if validation failed. This document lists reasons for unsuccessful validations.
Encoding of the receipt data failed
Validating the receipt with the App Store requires encoding the receipt data using Base64 in your app before sending it to your server. Use Data.base64EncodedString(options:) as detailed in Fetch the Receipt Data or a Base64 algorithm of your choosing to encode the receipt data. if you use a different Base64 algorithm, confirm that it successfully covers and encodes all possible characters in a receipt.
Shared secret is invalid
In App Store Connect, you can generate or regenerate a primary shared secret for all of your apps, or an app-specific shared secret for each of your apps. When you regenerate the primary shared secret, you invalidate the previous shared secret for all of your apps that use it. Confirm that the password key is set to the latest value of the primary shared secret for all of your apps that use it. See Generate a shared secret for details.
When you generate an app-specific shared secret for an app, that app can no longer use the primary shared secret. Confirm that password is set to the
latest value of the app-specific shared secret for this app. The app-specific shared secret becomes invalid for the app when you regenerate it.
Object posted to the App Store is invalid
On your server, create and format an object as JSON. This JSON object is a dictionary that contains the receipt-data and password keys. Each key pair in the dictionary is separated by a comma.
{
"receipt-data": "your_Base64_encoded_receipt_data",
"password": "your_shared_secret",
}For receipts that contain auto-renewable subscriptions, optionally add exclude-old-transactions to the JSON object. The latest_receipt_info key contains the most recent entry for any subscriptions when exclude-old-transactions is set to true and all renewal entries, otherwise.
{
"receipt-data": "your_Base64_encoded_receipt_data",
"password": "your_shared_secret",
"exclude-old-transactions": true
}If exclude-old-transactions is absent in the JSON object, then the default value is false.
Validation request was posted to the incorrect URL
Use the sandbox URL to verify receipts when testing in the sandbox and while your app is in review:
https://sandbox.itunes.apple.com/verifyReceiptUse the production URL to verify receipts when your app is live in the App Store:
https://buy.itunes.apple.com/verifyReceiptFirst, verify your receipt with the production URL. If you receive a 21007 status code, as outlined in verifyReceipt, verify with the sandbox URL instead.
Validate the receipt locally
Consider validating your receipt locally with the App Store to ensure your implementation works as designed. Use the curl command to test your JSON object.
To validate your receipt in the sandbox environment, run:
% curl -d
'{
"receipt-data": "your_Base64_encoded_receipt_data",
"password": "your_shared_secret"
}'
https://sandbox.itunes.apple.com/verifyReceiptTo validate your receipt in the production environment, run:
% curl -d
'{
"receipt-data": "your_Base64_encoded_receipt_data",
"password": "your_shared_secret"
}'
https://buy.itunes.apple.com/verifyReceiptTo validate your receipt in the production environment and limit the content of the latest_receipt_info key to only the most recent entry, run:
% curl -d
'{
"receipt-data": "your_Base64_encoded_receipt_data",
"password": "your_shared_secret",
"exclude-old-transactions": true
}'
https://buy.itunes.apple.com/verifyReceiptRevision History
2022-05-24 Made minor editorial changes.
2022-04-26 First published.
See Also
Latest
TN3205: Low-latency communication with RDMA over ThunderboltTN3206: Updating Apple Pay certificatesTN3179: Understanding local network privacyTN3190: USB audio device design considerationsTN3194: Handling account deletions and revoking tokens for Sign in with AppleTN3193: Managing the on-device foundation model’s context windowTN3115: Bluetooth State Restoration app relaunch rulesTN3192: Migrating your iPad app from the deprecated UIRequiresFullScreen keyTN3151: Choosing the right networking APITN3111: iOS Wi-Fi API overviewTN3191: IMAP extensions supported by Mail for iOS, iPadOS, and visionOSTN3134: Network Extension provider deploymentTN3189: Managing Mail background traffic loadTN3187: Migrating to the UIKit scene-based life cycleTN3188: Troubleshooting In-App Purchases availability in the App Store