2

At the moment, I am authenticating as my linked android apps google service account to verify and try to acknowledge android in app Subscriptions. I can verify them using the GET call, but when i make the POST and append :acknowledge to the end of the URL, i receive the following error

{
    "error": {
        "code": 400,
        "message": "The product purchase is not owned by the user.",
        "errors": [
            {
                "message": "The product purchase is not owned by the user.",
                "domain": "androidpublisher",
                "reason": "productNotOwnedByUser"
            }
        ]
    }
}

The service account has been granted all permissions as far as i can tell via the android app store App store image

when i make a GET call without :acknowledge I receive responses like this and can see that the subscription still has not been acknowledged.

{
    "startTimeMillis": "1647982226152",
    "expiryTimeMillis": "1647982480099",
    "autoRenewing": false,
    "priceCurrencyCode": "USD",
    "priceAmountMicros": "490000",
    "countryCode": "US",
    "developerPayload": "",
    "cancelReason": 2,
    "orderId": "GPA.3361-7700-2612-89511..0",
    "linkedPurchaseToken": "helcpfajhpkoabgbklojcjlh.AO-J1OzgU2Fpxp9CAKnnqz3kGm8-dIxNV7cO5l_lguaM-M8eTyOUCYnAo1F9xE16ynTTovA8KDyGA_qaV775sqWEEaeAJmF683GuIhIQyd-7bxV6Mk9E5Gw",
    "purchaseType": 0,
    "acknowledgementState": 0,
    "kind": "androidpublisher#subscriptionPurchase"
}

The entire code

exports.acknowledgeAndroidSubscription = functions.https.onRequest((request, response) => {
  // require these first
  const {google} = require("googleapis");
  const axios = require("axios");
  const googleServiceAccountKey = require("./pc-api-6835501382478242417-177-5781829bedc5.json"); // see docs on how to generate a service account
  
  // get the token and subscription id from the request
  const {purchaseToken, subscriptionID, type} = request.body;
  functions.logger.log('incoming data', purchaseToken, type, subscriptionID);
  
  // set your
  const packageID = "edu.fit.my.jgibb2018.pob";

  const returnTheResponse = (data) => {
    response.status(200).send(data);
  };

  const acknowledgeSubscription = (err, tokens) => {
    //making this call as a POST to  url: `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageID}/purchases/subscriptions/${subscriptionID}/tokens/${purchaseToken}:acknowledge` results in an error. 
    functions.logger.log("trying to verify" + tokens.access_token);
    const config = {
      method: "get",
      url: `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageID}/purchases/subscriptions/${subscriptionID}/tokens/${purchaseToken}`,
      headers: {
        "Authorization": `Bearer ${tokens.access_token}`,
      },
    };

    axios(config)
        .then(function(r) {
          console.log(JSON.stringify(r.data));
          returnTheResponse(r.data);
        })
        .catch(function(error) {
          console.log(error);
          returnTheResponse(error);
        });
  };


  const getAccessToken = () => {
    const jwtClient = new google.auth.JWT(
        googleServiceAccountKey.client_email,
        null,
        googleServiceAccountKey.private_key,
        ["https://www.googleapis.com/auth/androidpublisher"],
        null,
    );
    try {
      if (type == "subscriptionAcknowledge") {
        //this is the only potential outcome to this if/else statement
        jwtClient.authorize(acknowledgeSubscription);
      } else if (type == "subscriptionVerify") {
        //not possible at this time during testing
        jwtClient.authorize(verifySubscription);
      } else {
        //not possible at this time during testing
        jwtClient.authorize(verifyPurchase);
      }
    } catch (error) {
      functions.logger.log(error);
      response.status(500).send("getting auth", error);
    }
  };

  getAccessToken();
});

When using the google-play-billing-validator node package, only twice have I seen a successful acknowledged purchase. It happened the first time i tried, then after cancelling a subscription during testing, and retrying, i am unable to acknowledge it again. then they continuously cancel.

exports.googlePlayBillingValidator = functions.https.onRequest((request, response) => {
  // capture the data from the request
  const { purchaseObject, subscriptionID, type } = request.body;
  console.log(subscriptionID, type);
  // inclue your app bundle id
  const bundleID = "edu.fit.my.jgibb2018.pob";
  // require the service account info
  const googleServiceAccountKey = require("./pc-api-6835501382478242417-177-5781829bedc5.json"); // see docs on how to generate a service account
  // require the verify module
  const Verifier = require("google-play-billing-validator");
  // create verifier opitons object
  const options = {
    "email": googleServiceAccountKey.client_email,
    "key": googleServiceAccountKey.private_key,
  };
  // create a new verifier instance
  const verifier = new Verifier(options);
  // create a receipt object
  const receipt = {
    packageName: bundleID,
    productId: purchaseObject.productId,
    purchaseToken: purchaseObject.purchaseToken,
    
  };
  if (type.contains("subscriptionAcknowledge")) {
    // add the following string to the receipt object `developerPayload: "some unique identifier",`
    receipt.developerPayload = "some unique identifier";
  }
  // acknowledge the receipt
  const promiseData = verifier.verifySub(receipt);

  promiseData.then(function (r) {
    response.send(r);
  })
    .catch(function (error) {
      functions.logger.error(error);
      response.send(error);
    });
});
JaredGibb
  • 83
  • 7

2 Answers2

0

The error seems to stem from rapid testing.

When i wait a long while (1+ hour) between a cancelled subscription and the next time i try to purchase it, i am able to test my subscription purchases no issue. when i test immediately or within a short period, i see the error above.

JaredGibb
  • 83
  • 7
0

I received this error as well. However, when I simply tried the whole thing again it worked.

I suspect what's happening here is that you're doing your purchase in the test environment (I know I am). I'm purchasing subscriptions and a monthly subscription in the test environment expires after 5 minutes - when I tried to acknowledge an expired subscription (through my API, using a service account), I received this pretty unhelpful message about how "The product purchase is not owned by the user."

Note also that the :acknowledge request returns a 204 NoContent response, not a 200 OK response, so that might also be a problem in your case.

However, when I got my ducks lined up and was able to acknowledge the subscription very soon after completing the purchase, it worked fine.

Mick Byrne
  • 14,394
  • 16
  • 76
  • 91