I have done all the setup to verify my receipts server side (in python with the requests
package).
Here is my code :
url = "https://buy.itunes.apple.com/verifyReceipt"
request_body = {"receipt-data": token}
headers = {'Content-Type': 'application/json'}
response = requests.post(url=url, headers=headers, data=request_body)
The only variable here is token
that is sent from the client (flutter
) and that is : purchaseDetails.verificationData.serverVerificationData
.
I can't verify the receipt because if i pass token
as string
, i receive always a 21002 error (malformed).
If i try something like this in python :
token = base64.b64encode(token)
It throws this error : a bytes-like object is required, not 'str'
which i don't understand because i am actually passing a bytes
object.
What is the correct format to pass to the POST request to verify the iOS receipt ? Is the flutter one correct or should we encode something ?
Any concrete example will be accepted because i could not find any.
PS : i am redirected to the sandbox url "https://sandbox.itunes.apple.com/verifyReceipt"
if the production one fails. The sandbox response
is the same as the production one (statusCode: 21002
)
It looks like either your receipt is not correct ( sandbox has issues sometimes ) or your server-side setup is wrong
For the first point, you can try creating a receipt by generating a storeKit config file. This can't be done in flutter, you have to open iOS module with code and setup storekit config file by going here.
After setting up the storekit file, you can either run the app from xCode directly or just close xCode and run from your preferred flutter IDE
Now, iOS will never hit the production purchase identifiers when you try to fetch/buy products from the app, and instead fetch the products from your storekit config and generate a receipt from those. This receipt is accepted by apple sandbox verification endpoint, you can also test refunds and subscription cancellations from xCode using a storekit config.
For the second point, you have to enable the app specific shared secret in iTunes connect and then use that in the 'password' key in the receipt validation API. Here is where you find it AppStoreConnect > Your app > Subscriptions
If it still doesn't solve the issue, I'd be happy to assist further.
EDIT: I just tested purchasing an auto renewable subscription purchased in sandbox (not storeki t) and then validating it using the sandbox URL and it returned the correct receipt data. In your post above, you don't need to base64 encode the purchaseDetails.verificationData.serverVerificationData since its already encoded. Have you tested this on postman? It Works there
EDIT: so the request is malformed because you are not sending data as String so you need to dump the dict
:
request_body = json.dumps({"receipt-data": token})