Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug All Google IAP are automatically refunding on my live game.

Discussion in 'Unity IAP' started by unitynoob24, Sep 13, 2023.

  1. unitynoob24

    unitynoob24

    Joined:
    Dec 27, 2014
    Posts:
    398
    Hello, I shipped a mobile game a little over a week ago and was overall a smooth launch.

    I noticed today however, on Google, 100% of my android IAP's were refunded. I reached out to some android players on my discord and asked if anyone purchased and returned stuff. The people that purchased did not return anything. They did say they received refund emails however.

    I'm using In App Purchasing 4.9.4 and Unity 2020.3.45 - using the codeless IAP and catalog how everything outlines to do so. Am I missing a step? Is this a bug? How can this be corrected?

    @John_Corbett
     
    Last edited: Sep 13, 2023
  2. unitynoob24

    unitynoob24

    Joined:
    Dec 27, 2014
    Posts:
    398
    UPDATE: It appears to only be happening with my non-consumable offering. My game has 1 non-consumable and 5 or so consumable IAP's. @John_Corbett
     
  3. unitynoob24

    unitynoob24

    Joined:
    Dec 27, 2014
    Posts:
    398
  4. unitynoob24

    unitynoob24

    Joined:
    Dec 27, 2014
    Posts:
    398
    @John_Corbett Thanks for getting back to me.

    I discovered after hours of digging around that we aren't actually supposed to be using the codeless IAP for deployment. This isn't stated anywhere that I could see anyway within the documentation for IAP. Furthermore, it is the first page when you navigate to the docs for Unity's IAP; where it is presented in such a way that this is the super simple no code required approach to be up and running with IAP in your game! Maybe consider having a large flashing red banner or something that says to never use this for games that are going to be live on Google?

    The actual fix I came up with was more of a hacky workaround. I did start creating my own coded IAP solution (which is the ideal approach and the one that should be plastered to the top of the documentation), but realized after doing additional digging that pretty much the sole reason my Non-Consumable product was automatically refunding on Google only is due to the state that the purchase event callback defaults them to using the codeless button (which is pending) basically for anyone else reading this, when a status of pending is sent if it never becomes complete Google will automatically refund. This is problematic because nothing anywhere really states this; we are presented with a thing that claims to be super simple to use and ready for our games. To 'fix' it for now, I am just forcing my Non-Consumable codeless IAP button to Consume Purchase (the check box under the button type on the IAP Button script) this checkbox actually will make it return Complete which I suppose is also what then internally acknowledges the purchase with Google, thereby making it so nothing is automatically refunding due to being pending forever.

    Ideally I would have taken the time to finish a purely coded IAP solution (because the current 'fix' still leaves me open to fraud I suppose), having known this all from the beginning. I get that you guys at Unity are busy and that I am a small fish - but as a paying customer for basically a decade now, I am loyal of course, at least a quick reply saying oh don't use codeless would have sufficed. What if I was Disney or Warner Bros - you guys would call me within minutes probably? If I was those guys.. losing all of my first two weeks of in app purchases on one of my platforms due to this could be a MAJOR loss.

    It was still a loss, but thankfully for the scope of this project and the fact that it is a free to play game that I created to expand my user base, not really worrying as much about the apps generated revenue - it was only a mildly annoying thing to discover. It sucks that I didn't discover it during my three months of QA testing or when I was actively developing this game - but I just followed the documentation as it had been outlined.

    Unity, please do better.
     
    Last edited: Sep 14, 2023
  5. markmozza

    markmozza

    Joined:
    Oct 16, 2015
    Posts:
    85
    This sounds like your not Acknowledging the Google receipt. This is normally done server side. If you dont acknowledge, the sale will be refunded. This is NOT a Unity problem. This has to be done for all Google IAPs.

    Also Codeless is totally acceptable in a production environment. Altough i dont use it, it calls all the same functions as if it was coded. EDIT: Upon reading more forum posts it seems that Unity have not updated codeless. Which is a bit disapointing but not suprised.

    Here is my Server Side Acknowledgement function. If you need any more help on the matter. Join my Discord server. https://discord.gg/AbChMswB

    Code (JavaScript):
    1. /**
    2. * Sends Acknowledgement for a purchase directly to google.
    3. * @param receipt
    4. * @param package_name
    5. * @param product_id
    6. * @param purchase_token
    7. * @param access_token
    8. * @param cb
    9. */
    10. async function AcknowledgeGoogleReceipt(receipt, package_name, product_id, purchase_token, access_token, cb)
    11. {
    12.  
    13.     /**
    14.      * Setup params for the post request.
    15.      * @type {{headers: {"Content-Type": string}, method: string, json: boolean, url: string}}
    16.      */
    17.     let params = {
    18.         method: 'POST',
    19.         url: "https://androidpublisher.googleapis.com/androidpublisher/v3/applications/"+package_name+"/purchases/products/"+product_id+"/tokens/"+purchase_token+":acknowledge?access_token="+access_token,
    20.         headers: {
    21.             'Content-Type': 'application/json'
    22.         },
    23.         body: {
    24.             "developerPayload": ""
    25.         },
    26.         json: true
    27.     };
    28.  
    29.     console.log("Acknowledgement Request: ", params)
    30.  
    31.     /**
    32.      * Send Request.
    33.      */
    34.     // await new Promise(resolve => setTimeout(resolve, 10000));
    35.     request(params, (error, response, body) => {
    36.         console.log("Acknowledgement Request Response: ", body);
    37.         if (typeof error !== 'undefined' && error) return cb(error);
    38.         if (typeof body !== 'undefined' && typeof body.error !== 'undefined' && body.error) return cb(body.error);
    39.         cb(null, body);
    40.     });
    41.  
    42. }
    43.  
     
    Last edited: Sep 15, 2023