When using the Java Google Play Developer API (version 3), and requesting purchase information for a valid purchase token, I get the below exception. The API call returns a 400 Bad Request response with the following message.
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
Unfortunately there is no further information. I do not know what value is invalid.
First, we have contacted Google support about this. Unfortunately we have been going back and forth with Google support for almost 2 months and they still haven't even indicated they correctly understand what our problem is. Every time they reply, they give us suggestions that have literally nothing to do with the Google Play Developer API, even after thoroughly explaining the problem multiple times. This is the most frustrating support experience I've had in 20 years. Google support is clearly not going to be of any help here.
Second, we have successfully linked our Google Play account and our back-end. All necessary configuration is complete and working. On our back-end we are getting notifications from Google Play whenever an Android in-app purchase is made, and these notifications include a purchase token. This took some substantial effort, but I am confident this is now all correct, our service account is configured correctly, and all permissions and such are good.
I am able to successfully call the API that returns a list of available in-app-purchase products. I get a full and correct listing of the products we have configured in Google Play for users to purchase in our app. In order to make this call, we must provide credentials, and I assume the server is validating these credentials when we make this call. Since I can successfully make this call, I am assuming the "Invalid Value" is not related to our credentials. We are using a Google-generated JSON file created for a specific service account (not using a p12 file).
I have searched StackOverflow, and the rest of the internet looking for information on this issue. I have found many pages indicating the same or similar problem, but using an older version of the Google Play Developer API, which apparently did things differently. The solutions offered do not seem to apply to the v3 API. I have been searching for many weeks and trying various solutions I've come across all with no success.
I have written a test app that I run on my local PC which works when I am requesting a listing of in-app products, but does not work when requesting the purchase details for a given purchase token. I have tried with many different purchase tokens. I read that the test tokens are not actually valid for use with this particular API, so I actually released to production a build of our app that I am able to make a real, actual purchase with. I have done this, been charged by Google, and our back-end has received real and valid purchase tokens from these purchases.
private static void testGooglePlayDevAPI_Purchase() throws Throwable {
final String productIdSku = "[the_product_sku]";
final String purchaseToken = "[a_valid_purchase_token]";
final String packageName = "[our_app_id]";
final File GOOGLE_PLAY_DEV_API_CREDENTIALS =
new File("path_to_file/google-api-credentials.json");
final FileInputStream credentials =
new FileInputStream(GOOGLE_PLAY_DEV_API_CREDENTIALS);
final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
final HttpTransport TRANSPORT =
GoogleNetHttpTransport.newTrustedTransport();
String scope = AndroidPublisherScopes.ANDROIDPUBLISHER;
GoogleCredential credential = GoogleCredential
.fromStream(credentials, TRANSPORT, JSON_FACTORY)
.createScoped(Arrays.asList(scope));
AndroidPublisher publisher = new AndroidPublisher
.Builder(TRANSPORT, JSON_FACTORY, credential)
.setApplicationName(packageName)
.build();
try {
AndroidPublisher.Purchases purchases = publisher.purchases();
AndroidPublisher.Purchases.Products products = purchases.products();
AndroidPublisher.Purchases.Products.Get get =
products.get(packageName, productIdSku, purchaseToken);
ProductPurchase product = get.execute();
System.out.println(String.format(
"Product purchase data found [developerPayload=%s]",
product.getDeveloperPayload()));
} catch (Throwable t) {
System.out.println(ExceptionSupport.getExceptionDetails(t));
}
}
I expect the above code to give me a response with valid product purchase data (a valid ProductPurchase instance that I can interrogate and process). Instead, all I ever get here is a 400 Bad Request response indicating that SOME VALUE (I don't know which) is invalid. The actual response is:
com.google.api.client.googleapis.json.GoogleJsonResponseException:
400 Bad Request
{
"code" : 400,
"errors" : [ {
"domain" : "global",
"message" : "Invalid Value",
"reason" : "invalid"
} ],
"message" : "Invalid Value"
}
UPDATE:
I've provided my own answer to this question below.