Solved

Checking feature unlock status and handling refunds with Consumable in-app purchase

  • 14 June 2024
  • 2 replies
  • 41 views

Badge +1

My app is a paid app, and I’m transitioning the pricing model to the same model as Due app (https://dueapp.zendesk.com/hc/en-us/articles/360053244591-What-is-the-Upgrade-Pass). The difference is instead of using a subscription, I use a consumable in-app purchase.

Each feature in the app has its own release date. To determine if a feature is unlocked, I compare its release date with the upgrade end date. If the release date is the same as or earlier than the upgrade end date, the feature is unlocked. I calculate the upgrade end date from the CustomerInfo object returned from Purchases.shared.getCustomerInfo:


Purchases.shared.getCustomerInfo(fetchPolicy: .notStaleCachedOrFetched) { customerInfo, error in

    if let customerInfo {

        let purchaseDate = customerInfo.purchaseDate(forProductIdentifier: productIdentifier) ?? customerInfo.originalPurchaseDate

        let endDate = Calendar.current.date(byAdding: .month, value: 12, to: purchaseDate)

        // Further logic here

    } else if let error {

        // Handle error

    }

}

Is it the correct way to check the feature unlock status?

Regarding refunds, I haven't been able to test them yet. According to the article at https://www.revenuecat.com/docs/subscription-guidance/refunds, if an in-app purchase key is configured for the app in RevenueCat, consumable in-app purchase refunds will be detected. Does this mean I do not need to implement any additional handling for refunds? Will Purchases.shared.getCustomerInfo automatically return an updated CustomerInfo object when a refund is detected?

Thank you!

icon

Best answer by jeffrey_bunn 18 June 2024, 19:32

View original

This post has been closed for comments

2 replies

Userlevel 2
Badge +4

Hi @arnold! Your proposed flow should work as expected, with a few caveats:

  • originalPurchaseDate (for Apple) is not actually the purchase date; it's when the user first downloaded your app (unless the product is a subscription). So your fallback code won't work if the original call to purchaseDate returns null.
  • If your user deletes the app and redownloads it, the consumables are not in the receipt and can't be restored unless you allow your users to log in. So if you don't offer authentication, you'll want to before proceeding with this.
  • Refunds are captured in customerInfo's expirationDate, and we also send a refund webhook that you can catch on your backend if necessary. 
  • For Google refunds, you should try to refund via our dashboard (vs in Google Play console) as we've found this is more reliable for us to capture the refund event from Google.

If you have a backend, you could also consider storing the purchase (and refund) dates for your consumables, particularly if you plan to release more complex feature gating logic in the future. Though with your current setup, this shouldn’t be necessary. Please let me know if I can clarify anything!

Badge +1

I just learnt that consumables are not in the receipt. Since my app does not have a backend, consumables will not work for me. I ended up switching to subscription instead. Thank you!