Android:Inapp Purchase Receipt Validation Google Play

Android : inApp purchase receipt validation google play

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

  • 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
  • C#: https://github.com/googleapis/google-api-dotnet-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!

How to verify purchase for android app in server side (google play in app billing v3)

It sounds what you're looking for is a way to check if the user has premium features enabled on their account, so this is where I would start;

Ensure there is a flag of some sort on your database indicating if the user has premium features and include that in the API response payload when requesting account info. This flag will be your primary authority for "premium features".

When a user makes an in-app purchase, cache the details (token, order id, and product id) locally on the client (i.e the app) then send it to your API.

Your API should then send the purchaseToken to the Google Play Developer API for validation.

A few things might happen from here:

  1. The receipt is valid, your API responds to the client with a 200 Ok status code
  2. The receipt is invalid, your API responds to the client with a 400 Bad Request status code
  3. Google Play API is down, your API responds with a 502 Bad Gateway status code

In the case of 1. or 2. (2xx or 4xx status codes) your client clears the cache of purchase details because it doesn't need it anymore because the API has indicated that it has been received.

Upon a successful validation (case 1.), you should set the premium flag to true for the user.

In the case of 3. (5xx status code) or a network timeout the client should keep trying until it receives a 2xx or 4xx status code from your API.

Depending on your requirements, you could make it wait a few seconds before sending again or just send the details to your API when ever the app is launched again or comes out of background if the purchase details are present on the app cache.

This approach should take care of network timeouts, servers being unavailable, etc.

There are now a few questions you need to consider:

What should happen immediately after a purchase? Should the app wait until validation is successful before providing premium content or should it tentatively grant access and take it away if the validation fails?

Granting tentative access to premium features smooths the process for a majority of your users, but you will be granting access to a number of fraudulent users too while your API validates the purchaseToken.

To put this in another way: Purchase is valid until proven fraudulent or; fraudulent until proven valid?

In order to identify if the user still has a valid subscription when their subscription period comes up for renewal, you will need to schedule a re-validation on the purchaseToken to run at the expiryTimeMillis that was returned in the result.

If the expiryTimeMillis is in the past, you can set the premium flag to false. If it's in the future, re-schedule it again for the new expiryTimeMillis.

Lastly, to ensure the user has premium access (or not), your app should query your API for the users details on app launch or when it comes out of background.

Server side Google Play In App Billing receipt testing

All purchases, including test purchases, must be done using an Android application (via a real device or an emulator). It happens because the purchase is executed by the Google Play Store app, and authenticated by the user.

About the server-side API, according to the Google Play Developer API, you can use the Subscriptions and In-App Purchases API to:

[...] manage your app's catalog of in-app products and subscriptions. In
addition, with the Subscriptions and In-App Purchases API you can
quickly retrieve the details of any purchase using a standard GET
request.

So, after your purchase is completed (starting on the device), you can manage it's status, get details from the API and etc.

Android : inApp purchase receipt validation (Part 2)

Following up on your original question now that I know you're using Java for your server side code, you will want to use the Google API Client Library for Java. I'm not comfortable with Java myself but the documentation is easy to follow.

First of, you need to authenticate, take a look at the example code Google provides. You currently have a JWT (JSON Web Token) but you can keep to the example by instead downloading the p12 certificate file from the same place on the Google API Dashboard.

Your authentication code should look something like this:

HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = JacksonFactory.getDefaultInstance()

GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
.setServiceAccountPrivateKeyFromP12File(new File("key.p12"))
.build();

Also don't forget to set your SERVICE_ACCOUNT_EMAIL and store the key.p12 file somewhere accessible to your server.

If you're interested, this is the docs AndroidPublisherScopes.

As I mentioned, my knowledge of Java is limited so please use your disregard any mistakes I have made.

Google have made some code samples available with downloads and links to GitHub repos. I suggest checking those out.

From here you can use the AndroidPublisher.Purchases.Products.Get method to retrieve the details of a purchase. The docs list the signature as following:

AndroidPublisher.Purchases.Products.Get(java.lang.String packageName, java.lang.String productId, java.lang.String token)

For subscriptions use AndroidPublisher.Purchases.Subscriptions.Get.

If you need more help, consider asking a question with the java and google-api-java-client tags.

Google receipt validation - 401 - permissionDenied

I forgot to add scope ".../auth/androidpublisher" in Google developer console.
enter image description here

After you add scope you should save credentials at the bottom of page.

Validate more than one receipt at a time from Google developer API

I've never heard of this.

What you can do though, is subscribe to real time notifications to know in real time the statuses of your subscriptions:

  • https://developer.android.com/google/play/billing/getting-ready#configure-rtdn
  • https://developer.android.com/google/play/billing/rtdn-reference

Sample of Android In-App Purchase receipt(response)

Google returns

1: Response Code: Value is 0 if the purchase was successful, error otherwise.

2: Signature

3: Purchase data subscription contains autoRenewing property while managed product does not.

UPDATE: Android billing library's new version includes acknowledged property. I don't have new response for the product at hand.

Subscription:{
"orderId":"GPA.2023-9153-0180-49403",
"packageName":"com.package.name",
"productId":"subscription.name.sku",
"purchaseTime":1565763897962,
"purchaseState":0,
"purchaseToken":"kkoohioagkpieamagedjoiji.AO-J1Owj3YPtGxM9YOBSCywUo07BwcX79dAS24w7DvvxVi-gEzsXeRvkY5NGETBH8oDUaWc0oF4M8K3EiJ2v9JUfoGzxPazO51qpksIXGOkVPHI0DVJE3FzOdDd7bqbAIPVLFUo7u6SzdN1nRUlg9xoakvzqY8Kwow",
"autoRenewing":true,
"acknowledged":false
}

The old response:

Subscription:
{
"orderId":"string",
"packageName":"string",
"productId":"string",
"purchaseTime":1423956863083,
"purchaseState":0,
"purchaseToken":"apafgjjemjhnoiadmmpffiil.AO-J1OySPl3pYGk4JliUkLj_Fro7FvGWiArPP0R1imx49HOmnJ4MroJNbSwkLk1WfYJmp_8g5ek5C9AAIjG_6GhC03-X0QMwfyc4epN_ZdkZqlxIKj0V5m6QQZDRhLW-8smEQ5R_USG4dtq6JTsK9UoxMO2YFXziGQ",
"autoRenewing":true
}

Products:
{
"orderId":"GPA.6027-7343-7915-33484",
"packageName":"com.app.package.name",
"productId":"quotation.1",
"purchaseTime":1523956202686,
"purchaseState":0,
"purchaseToken":"kjcjjlmljnbifnlpcobchldi.AO-J1OyD96lBh3dYpPpf3yW3H4EzH_2XXFjNjL3jrVf-oPk-T7ZQvf-DF1Zd0LFtzPBn8hqdL_2ML6AXLgzBRkDcFAljIbv4Ck0ARxz-L4LPXAFgQvHGIn4Of00msbbkiI2ENpNKBgd6_MlxT7oTaMU3ltQmld7X2A"
}

Check a Google Play Purchase from Java Server

I finally could check my purchases with Google play. When I buy something from my mobile App, Google Play send me a receipt. Then, I send this receipt to my server, and I just had to do two things server side:

-Use the previously generated service account Json to get my google credentials

-Use the google credentials and the receipt to get the purchase info from google play.

And I used these two functions to perform it:

private static GoogleCredential getGoogleCredential() throws IOException {
List<String> scopes = new ArrayList<String>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);

ClassLoader classLoader = MY_CLASS.class.getClassLoader();
GoogleCredential credential = GoogleCredential.fromStream(classLoader.getResourceAsStream(GOOGLE_KEY_FILE_PATH))
.createScoped(scopes);
return credential;
}

private static ProductPurchase getPurchase(GoogleReceipt receipt, GoogleCredential credential)
throws GeneralSecurityException, IOException {
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
.setApplicationName(YOUR_APPLICATION_NAME).build();
AndroidPublisher.Purchases purchases = publisher.purchases();

final Get request = purchases.products().get(receipt.getPackageName(), receipt.getProductId(),
receipt.getPurchaseToken());
final ProductPurchase purchase = request.execute();
return purchase;
}

With the purchase object I was able to validate the buy in just a minute.

Edit: Oh, dont look for GoogleReceipt class on the API packages. It's just a basic class I created to parse the receipt info.

How do we verify Android in-app billing receipt on the server side?

Update: You can use the getPurchases() method to retrieve "un-consumed" purchases, as explained in the developer docs:

http://developer.android.com/google/play/billing/billing_reference.html#getPurchases

Original Answer (now out of date)

The Google Checkout API is deprecated. You should now use the Purchase Status API.

If you plan to use the Purchase Status API, the link above mentions these limitations:

  • You can use the API to check the status of individual items only — bulk requests for order status are not supported at this time.
  • You can query for the details of orders placed on or after 12 June 2013, but not for orders placed earlier.
  • You can query purchases of any item type made with the In-app Billing v3 API, or purchases of managed items made with In-app Billing v1 and v2. You can not use the Purchase Status API to query purchases of unmanaged items made with In-app Billing v1 or v2.


Related Topics



Leave a reply



Submit