Agent Wranglers

MOB-37Required

Restore and acknowledge every store purchase

Give every app that sells subscriptions or permanent unlocks a Restore Purchases button. Acknowledge each Google Play purchase within three days of it becoming paid.

How to do it

Apple asks for a restore option for any purchase that can be restored, under guideline 3.1.1. People change phones, reinstall the app or sign in on a tablet. Restore reads the store's current transactions, and your server checks them as verify every store purchase on your server says. On StoreKit 2 that is AppStore.sync(), and on Google Play it is queryPurchasesAsync(). Google Play refunds and revokes a purchase that is not acknowledged within three days. The window starts when a pending payment turns into purchased. Acknowledge from the server once access is granted, and never while the purchase is still pending. Call queryPurchasesAsync() at start and on resume too. It catches purchases made outside the app, or lost when the network dropped.

Examples

Plain text example

func restorePurchases() async throws {
    try await AppStore.sync()
    for await result in Transaction.currentEntitlements {
        if case .verified(let transaction) = result {
            try await api.post("/store/apple/transactions", ["id": String(transaction.id)])
        }
    }
}

Kotlin example

suspend fun restorePurchases() {
    val params = QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.SUBS).build()
    billingClient.queryPurchasesAsync(params).purchasesList
        .filter { it.purchaseState == Purchase.PurchaseState.PURCHASED }
        .forEach { api.post("/store/google/purchases", mapOf("token" to it.purchaseToken)) }
}

How to check

On a fresh install, signed in to the store sandbox with an active test subscription, Restore Purchases gives access within 30 seconds. A server query lists no Google Play purchase older than 48 hours whose acknowledgementState is still pending.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/mobile-apps/store-review-and-listing/restore-and-acknowledge-purchases">Agent Wranglers mobile apps playbook</a>. In code you write, add a comment next to it with the same link.