Android : inApp purchase receipt validation google play
Solution 1
Google provides receipt validation through the Google Play Developer API, within the API are two endpoints you will be most interested in: Purchases.products: get and Purchases.subscriptions: get.
Purchases.products: get
can be used to verify a non-auto-renewing product purchase, where Purchases.subscriptions: get
is for verifying and re-verifying auto-renewing product subscriptions.
To use either endpoint you must know the packageName
, productId
, purchaseToken
all of these can be found in the payload you received on purchase. You also need an access_token
which you can get by creating a Google API service account.
To get started with a service account first go to the Google play Developer console API access settings page and click the Create new project button:
You should now see a new Linked Project and a few new sections, in the the Service Account section, click the Create service account button.
You will be presented with an info box with instructions to create your service account. Click the link to Google Developers Console and a new tab will spawn.
Now click Create new Client ID, select Service account from the options and click Create Client ID.
A JSON file will download, this is your JSON Web Token you will use to exchange for an access_token
so keep it safe.
Next, switch tabs back to the Google play Developer console and click Done in the info box. You should see your new service account in the list. Click on Grant access next to the service account email.
Next under the Choose a role for this user, select Finance and click Add user.
You have now set up your service account and it has all the necessary access to perform receipt validations. Next up is exchanging your JWT for an access_token.
The access_token
expires after one hour of exchange you so need some server code to handle this and Google have provided several libraries in many languages to handle this (list not exhaustive):
- Ruby: https://github.com/google/google-api-ruby-client
- Node.js: https://github.com/google/google-api-nodejs-client
- Java: https://github.com/google/google-api-java-client
- Python: https://github.com/google/google-api-python-client
I won't go into detail because there is plenty of documentation on how to use these libraries, but I will mention you want to use the https://www.googleapis.com/auth/androidpublisher
as the OAuth2 scope, the client_email
from the JWT as the issuer
and the public key you can get from the private_key
and the passphrase notasecret
will be used for the signing_key
.
Once you have the access_token
you're good to go (at least for the next hour at which point you will want to request a new one following the same process in the above paragraph).
To check the status of a consumable (non-auto-renewing) purchase make a http get
request to: https://www.googleapis.com/androidpublisher/v2/applications/com.example.app/purchases/products/exampleSku/tokens/rojeslcdyyiapnqcynkjyyjh?access_token=your_access_token
If you get a 200 http response code, everything went as planed and your purchase was valid. A 404 will mean your token is invalid so the purchase was most likely a fraud attempt. A 401 will mean your access token is invalid and a 403 will mean your service account has insufficient access, check that you have enabled Finance for the access account in the Google Play Developer console.
The response from a 200 will look similar to this:
{
"kind": "androidpublisher#productPurchase",
"purchaseTimeMillis": long,
"purchaseState": integer,
"consumptionState": integer,
"developerPayload": string
}
For an explanation of each property see https://developers.google.com/android-publisher/api-ref/purchases/products.
Subscriptions are similar however the endpoint looks like this:
https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/token?access_token=you_access_token
And the response should contain these properties:
{
"kind": "androidpublisher#subscriptionPurchase",
"startTimeMillis": long,
"expiryTimeMillis": long,
"autoRenewing": boolean
}
See https://developers.google.com/android-publisher/api-ref/purchases/subscriptions for the property descriptions and note that startTimeMillis
and expiryTimeMillis
will be subject to change depending on the duration of the subscription.
Happy validating!
Solution 2
Marc's answer is excellent. I will only add that the Google Play Developer API Client Library for Java makes it much simpler when connecting from your server to the Google Play servers. The library automatically handles refreshing the auth token and also provides a typesafe API so you don't have to muck around with URLs.
Here's how you setup the Publisher
singleton:
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
jsonFactory = JacksonFactory.getDefaultInstance();
credential = GoogleCredential.fromStream(getClass().getResourceAsStream("/path/to/your/key.json")).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));
publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential).setApplicationName(APP_NAME).build();
The following code queries a product purchase:
ProductPurchase product = publisher.purchases().products().get(PACKAGE_NAME, sku, token).execute();
Integer purchaseState = product.getPurchaseState();
product.getPurchaseTimeMillis();
product.getConsumptionState();
product.getDeveloperPayload();
You can similarly query for subscriptions:
SubscriptionPurchase sub = publisher.purchases().subscriptions().get(PACKAGE_NAME, sku, token).execute();
sub.getAutoRenewing();
sub.getCancelReason();
...
Solution 3
@marc-greenstock provided a great answer, however, there is a very important thing about receipt validation using Google Play Android Developer API.
If you have any problems with using this API and you added your in-app product BEFORE granting permission or linking to your service account, you need to open "In-app products" and perform some update. You can for example edit description of your product and save. You should instantly get permission.
I spent a few hours thinking what did I do wrong...
Solution 4
I faced a similar issue, the problem is in the settings we do in google developer project.
Refer to create-play-service-credentials for settings. Use the same primary account with which you created your in-app products.
Make sure you remove the previous one.
Link to a Google Developer Project Your Play Developer account needs to be linked to a Google Developer Project.
1a. Open the Settings > Developer account menus and select API access
1b. Select Link to connect your Play account to a Google Developer Project
1c. Agree to the terms and conditions
2. Create Service Account Next we need to create a service account. This is done from the Google API Console.
2a. Select Create Service Account
2b. Create Service account key credentials
2c. Enter details for service account
2d. Download your JSON credential:
3. Grant Access
3a. In Play Console, select Grant Access on the newly created service account
3b. Grant the following permissions:
After this wait for 48 hours to allow Google to propagate all access rights for APIs.
Solution 5
This answer is excellent. One more issue we ran into while following the direction was that the service account didn't show up in the Google Play Console. We ended up finding this solution to help: Service account doesn't show up in Google Console after creation
Basically, go to IAM on Google API Console and add the new service account, then it will show up on Google Play Console. screenshot
Related videos on Youtube
![Binil Surendran](https://i.stack.imgur.com/yzDMd.png?s=256&g=1)
Binil Surendran
Am always act with wisdom, am dosen't make decisions before weighed the pros and cons.
Updated on February 09, 2022Comments
-
Binil Surendran over 2 years
I am using google wallet for my payment gateway, after purchasing the product google giving me a below response that
{ "orderId":"12999763169054705758.1371079406387615", "packageName":"com.example.app", "productId":"exampleSku", "purchaseTime":1345678900000, "purchaseState":0, "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ", "purchaseToken":"rojeslcdyyiapnqcynkjyyjh" }
I am trying to make use of Receipt Validation that google play newly introduced.In Google Developer console I made certificate key by Service Account in the Permission. But I am confused how to make use of Receipt Validation after purchasing a Product from the Google Play-store.
So can anyone please help me how to do the Receipt validation of
InApp
Purchase.-
Anshul Tyagi over 8 yearsHello Binil, have you completed it for subscription purchasing ?
-
Binil Surendran over 8 yearsits manage product @Anshul Tyag
-
Pallavi over 7 years@BinilSurendran .. My question is different from your question, but I need to know the email id that was used for in-app purchase. can you please help how I can get that email , as I need it for further reference in my app
-
Binil Surendran over 7 years@Pallavi. sorry, i don't have the idea for getting the buyer email id. as the response given by google after purchase have no email_id
-
-
Binil Surendran over 8 yearsI add a new user in the developer console and i got a JSON certificate that get from the console.Can you please help me how to do receipt validation with the downloaded file @Marc Greenstock
-
Marc Greenstock over 8 years@BinilS You will need to be more specific, what server-side language are you to be writing your code in?
-
Binil Surendran over 8 yearsam using java in server side @Marc Greenstock
-
user1269586 almost 7 yearsThanks you @MarcGreenstock for this perfect answer. How can I exchanging my JWT for an access_token in PHP ? Any ideas ? Thanks ;)
-
Marc Greenstock almost 7 years@user1269586 Take a look at the PHP Google API Client Libraries
-
user1269586 almost 7 yearsThanks. How can I automatically genere access_token ? It always ask manual connection to Google account. Link to my stack overflow topic : stackoverflow.com/questions/44883839/…
-
user almost 7 yearsThis is code on a Java server, or executed on Android before calling out to an arbitrary server?
-
Anonymous almost 7 yearsThis is the first time i've seen a detailed guide to implement server payment validation in 2 days of searching. Thumbs up. Is there a ready to use server code somewhere? I find it very weird that I can't find something like that anywhere
-
Muhammad Hassan over 6 yearsI am getting status code 400 when I am running this process on Test subscription. My response is
<HttpError 400 when requesting https://www.googleapis.com/androidpublisher/v2/applications/com.frt.ballogyapp/purchases/subscriptions/android.test.purchased/tokens/inapp%3Acom.frt.ballogyapp%3Aandroid.test.purchased?alt=json returned "Invalid Value">
Is this expected behavior or I am doing something wrong? -
StuartDTO over 6 yearsCan you help me with this question please?
-
ZW1404 over 6 years@M Hassan That is the expected result if you pass an invalid token value.
-
Lavakush over 6 years@MarcGreenstock Thanks for the detailed answer.
-
blizzard over 6 years@jeshurun Thanks for the code. To other readers
APP_NAME = APP_PACKAGE_NAME
. -
Babken Vardanyan over 6 yearsWhat about Python?
-
António Almeida over 6 yearsThank you! For me instead of
getClass().getResourceAsStream(...
I usednew FileInputStream(...
. -
Admin about 6 years@MarcGreenstock is it possible to use just an API Key instead of OAuth to verify purchase tokens on my own server?
-
Marc Greenstock about 6 years@Antinous You can use the authentication process described on developers.google.com/android-publisher/authorization instead which may be easier
-
Admin about 6 years@MarcGreenstock I got it working in PHP in about 5 lines of code in the end. Was really straight forward. You just need to set up a Service Account and feed in the
credentials.json
file to it with the package ID, sku ID, and purchase token, which can be sent to your server via TLS POST. PS great main asnwer :-D -
Comtaler about 6 yearsI know validating the receipt through Google API is recommended here. However, if the receipt is validated up to step 3 and server remembers what orderId has been validated before, do I still need step 4?
-
Mathews Sunny almost 6 yearsCan you add description here. Else once if the link is revoked your answer turns invalid
-
Petr over 5 years@Marc Greenstock can you please post a link to google docs on return codes (200, 4**, 5**) ? Current Google documentation on v3 api is very snippy
-
Marc Greenstock over 5 years@Comtaler Response codes can be found here: developers.google.com/search-ads/v2/standard-error-responses
-
rmlarsen over 5 years@MarcGreenstock "...tokens/token?access_token=you_access_token" is wrong. According to their docs this should actually be the purchase token given to the device by the play store.
-
grooble about 5 yearsThanks. Very useful. However, I also needed to add:
credential.refreshToken();
between getting the credential and the publisher. -
Adi over 4 yearsWhat should be the role of the account added?
-
GuardianX over 4 yearsThank you for this brilliant answer! This should be in the official Google Play Store docs but all I see is different pieces of information juggling Google-specific terms like Service Account instead of providing a simple yet clear answer like you did there. Thanks again!
-
Muntasir Aonik about 4 years@MarcGreenstock Can you share an example for getting access token?
-
Jay Rathod RJ over 3 yearsHi , I have followed this steps to access Google Play Android Developer API.. While Granting this permission it is asking me to Invite User .. what should we do it is showing me "service account id" will be invited to access this developer account.. any idea ?
-
Rahul Kahale over 3 yearsIs this alternative to sasikanth.dev/posts/iap-verification-using-cloud-functions ? I am thoroughly confused whether to use Firebase.....which seems not sufficient by itself, as there is a need of database (from the blog) I would suggest saving purchase information to database and cross checking with other users to avoid duplicate subscriptions
-
Houman over 3 yearsStrange, Step 3 doesn't work for me. Play Console still doesn't show the service account created.
-
dead_can_dance about 3 years@Houman There seems to be an additional step between 2d + 3 that is now required (May '21). After 2d you need to click on IAM on the left hand side and add your new service account as a new member. It should then show up in the Play Console to continue with Step 3.
-
Ankit Jindal about 3 years@dead_can_dance can you add that new step between 2nd and 3rd?
-
Omar Salem over 2 yearsdevelopers.google.com/api-client-library/java/apis/… is giving 404