Android : inApp purchase receipt validation google play

87,051

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:

Create a new Google API Project

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.

Create a new Service Account

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.

Open the Google Developers Console

Now click Create new Client ID, select Service account from the options and click Create Client ID.

Create a new 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.

Grant access

Next under the Choose a role for this user, select Finance and click Add user.

Set the role to Finance

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):

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

API-access

1b. Select Link to connect your Play account to a Google Developer Project

choose-project-link

1c. Agree to the terms and conditions

agree-terms-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

create-service-account

2b. Create Service account key credentials

service-account

2c. Enter details for service account

enter-service-account-details

2d. Download your JSON credential: json-credentials

3. Grant Access

3a. In Play Console, select Grant Access on the newly created service account

grant-access

3b. Grant the following permissions:

apply-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

Share:
87,051

Related videos on Youtube

Binil Surendran
Author by

Binil Surendran

Am always act with wisdom, am dosen't make decisions before weighed the pros and cons.

Updated on February 09, 2022

Comments

  • Binil Surendran
    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
      Anshul Tyagi over 8 years
      Hello Binil, have you completed it for subscription purchasing ?
    • Binil Surendran
      Binil Surendran over 8 years
      its manage product @Anshul Tyag
    • Pallavi
      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
      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
    Binil Surendran over 8 years
    I 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
    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
    Binil Surendran over 8 years
    am using java in server side @Marc Greenstock
  • user1269586
    user1269586 almost 7 years
    Thanks you @MarcGreenstock for this perfect answer. How can I exchanging my JWT for an access_token in PHP ? Any ideas ? Thanks ;)
  • Marc Greenstock
    Marc Greenstock almost 7 years
    @user1269586 Take a look at the PHP Google API Client Libraries
  • user1269586
    user1269586 almost 7 years
    Thanks. 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
    user almost 7 years
    This is code on a Java server, or executed on Android before calling out to an arbitrary server?
  • Anonymous
    Anonymous almost 7 years
    This 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
    Muhammad Hassan over 6 years
    I 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/p‌​urchases/subscriptio‌​ns/android.test.purc‌​hased/tokens/inapp%3‌​Acom.frt.ballogyapp%‌​3Aandroid.test.purch‌​ased?alt=json returned "Invalid Value"> Is this expected behavior or I am doing something wrong?
  • StuartDTO
    StuartDTO over 6 years
    Can you help me with this question please?
  • ZW1404
    ZW1404 over 6 years
    @M Hassan That is the expected result if you pass an invalid token value.
  • Lavakush
    Lavakush over 6 years
    @MarcGreenstock Thanks for the detailed answer.
  • blizzard
    blizzard over 6 years
    @jeshurun Thanks for the code. To other readers APP_NAME = APP_PACKAGE_NAME.
  • Babken Vardanyan
    Babken Vardanyan over 6 years
    What about Python?
  • António Almeida
    António Almeida over 6 years
    Thank you! For me instead of getClass().getResourceAsStream(... I used new FileInputStream(....
  • Admin
    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
    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
    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
    Comtaler about 6 years
    I 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
    Mathews Sunny almost 6 years
    Can you add description here. Else once if the link is revoked your answer turns invalid
  • Petr
    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
    Marc Greenstock over 5 years
    @Comtaler Response codes can be found here: developers.google.com/search-ads/v2/standard-error-responses
  • rmlarsen
    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
    grooble about 5 years
    Thanks. Very useful. However, I also needed to add: credential.refreshToken(); between getting the credential and the publisher.
  • Adi
    Adi over 4 years
    What should be the role of the account added?
  • GuardianX
    GuardianX over 4 years
    Thank 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
    Muntasir Aonik about 4 years
    @MarcGreenstock Can you share an example for getting access token?
  • Jay Rathod RJ
    Jay Rathod RJ over 3 years
    Hi , 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
    Rahul Kahale over 3 years
    Is 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
    Houman over 3 years
    Strange, Step 3 doesn't work for me. Play Console still doesn't show the service account created.
  • dead_can_dance
    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
    Ankit Jindal about 3 years
    @dead_can_dance can you add that new step between 2nd and 3rd?
  • Omar Salem
    Omar Salem over 2 years