Android : inApp purchase receipt validation google play
Asked Answered
S

5

116

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.

Syncopation answered 1/2, 2016 at 9:35 Comment(4)
Hello Binil, have you completed it for subscription purchasing ?Pamphylia
its manage product @Anshul TyagSyncopation
@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 appPsychosis
@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_idSyncopation
W
269

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!

Wolfgang answered 1/2, 2016 at 19:40 Comment(20)
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 GreenstockSyncopation
@BinilS You will need to be more specific, what server-side language are you to be writing your code in?Wolfgang
am using java in server side @Marc GreenstockSyncopation
Thanks you @MarcGreenstock for this perfect answer. How can I exchanging my JWT for an access_token in PHP ? Any ideas ? Thanks ;)Ximenes
@Ximenes Take a look at the PHP Google API Client LibrariesWolfgang
Thanks. How can I automatically genere access_token ? It always ask manual connection to Google account. Link to my stack overflow topic : #44884339Ximenes
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 anywhereUnblinking
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/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?Bifoliate
Can you help me with this question please?Subinfeudation
@M Hassan That is the expected result if you pass an invalid token value.Farwell
@MarcGreenstock is it possible to use just an API Key instead of OAuth to verify purchase tokens on my own server?Joyce
@Antinous You can use the authentication process described on developers.google.com/android-publisher/authorization instead which may be easierWolfgang
@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 :-DJoyce
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?Sixtyfour
@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 snippyReplica
@Sixtyfour Response codes can be found here: developers.google.com/search-ads/v2/standard-error-responsesWolfgang
@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.Favoritism
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!Pituitary
@MarcGreenstock Can you share an example for getting access token?Albacore
This damn thing is so complicateApiculture
S
31

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();
...
Sienese answered 18/3, 2017 at 5:16 Comment(6)
This is code on a Java server, or executed on Android before calling out to an arbitrary server?Thermometer
@jeshurun Thanks for the code. To other readers APP_NAME = APP_PACKAGE_NAME.Placeman
What about Python?Beatific
Thank you! For me instead of getClass().getResourceAsStream(... I used new FileInputStream(....Kaliope
Thanks. Very useful. However, I also needed to add: credential.refreshToken(); between getting the credential and the publisher.Cislunar
developers.google.com/api-client-library/java/apis/… is giving 404Pampuch
E
13

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 - There is an "optional" step for granting role access. Make sure you grant access to the current user role.

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.

Exegetics answered 16/11, 2020 at 10:20 Comment(5)
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 ?Giverin
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 subscriptionsCarolyncarolyne
Strange, Step 3 doesn't work for me. Play Console still doesn't show the service account created.Cutter
@Cutter 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.Kola
@Kola can you add that new step between 2nd and 3rd?Exegetics
O
9

@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...

Oneman answered 15/3, 2020 at 11:30 Comment(0)
S
2

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

Sangraal answered 19/9, 2018 at 16:2 Comment(2)
Can you add description here. Else once if the link is revoked your answer turns invalidZoologist
What should be the role of the account added?Lance

© 2022 - 2024 — McMap. All rights reserved.