Skip to content

Restore purchases

Retrieve again the undelivered purchases whose payment was completed but whose products were not received because of a communication error or an abnormal termination, and deliver the missing products. This reduces payment-related complaints and protects the assets that users purchased.

Run purchase restoration when the app launches or when the user retries after a failed payment.

Follow the process below to restore undelivered purchases.

1. Retrieve undelivered receipts again

Use the restoration-related methods provided by the Apple payment plugin (IAppleStoreKitPlugin) to get the purchase receipts of undelivered products from the Apple App Store again.

1.1. Sync purchases (Restore Purchases)

Method

SyncAsync

When you call SyncAsync(), it runs Apple's AppStore.sync to sync the purchase history. This call may display an Apple ID re-authentication dialog to the user. Call it when the app launches or when the user explicitly selects a "Restore Purchases" button.

Call parameters

Field name Type Required Description
request SyncRequest Required The sync request data object. It has no parameters.
ct CancellationToken Optional The cancellation token.

Call example

Cases where the request cannot be performed, such as network or store problems, are handled as a common failure (Failure). For how to distinguish the HiveError contained in Failure from domain-specific results (Outcome) such as user cancellation, see Common error handling.

using Hive.Axyl.Core;
using Hive.Axyl.Payments.Addon.Apple;
using System.Threading;

// Retrieve the Apple StoreKit plugin
if (!HiveCore.TryResolve<IAppleStoreKitPlugin>(out var applePlugin))
{
    Debug.LogError("The Apple StoreKit plugin is not registered.");
    return;
}

AppleStoreKitServiceSyncResult result = await applePlugin.SyncAsync(new SyncRequest(), CancellationToken.None);

switch (result)
{
    case AppleStoreKitServiceSyncResult.Success:
        // Sync succeeded. Proceed to get unfinished transactions.
        Debug.Log("Purchase sync succeeded");
        break;

    case AppleStoreKitServiceSyncResult.UserCanceled:
        // When the user canceled Apple ID re-authentication
        Debug.Log("The user canceled the sync.");
        break;

    case AppleStoreKitServiceSyncResult.UnknownOutcome:
        Debug.LogWarning("Unknown sync result.");
        break;

    case AppleStoreKitServiceSyncResult.Failure failure:
        Debug.LogError($"Sync failed: {failure}");
        break;

    default:
        Debug.LogWarning($"Unhandled result: {result.GetType().Name}");
        break;
}

Response status

The returned object AppleStoreKitServiceSyncResult branches into one of the following cases.

Response case Description App client handling
Success Purchase sync succeeded Proceed to get unfinished transactions
UserCanceled The user canceled Apple ID re-authentication Display a cancellation notice UI
UnknownOutcome Unknown result Retry or show an error message
Failure Common Failure. See Common error handling. Handle it according to the common error handling guidelines

1.2. Get unfinished transactions

Method

GetUnfinishedTransactionsAsync

When you call GetUnfinishedTransactionsAsync(), it retrieves the list of transactions that have not yet been finished with FinishTransactionAsync(). Use it to find purchases whose payment was completed but whose products could not be delivered.

var unfinishedResult = await applePlugin.GetUnfinishedTransactionsAsync(
    new GetUnfinishedTransactionsRequest(), CancellationToken.None);

switch (unfinishedResult)
{
    case { } success when success is AppleStoreKitServiceGetUnfinishedTransactionsResult.Success s:
        foreach (AppleTransaction tx in s.Data.Transactions)
        {
            // Verify the receipt and deliver the product for each unfinished transaction
            Debug.Log($"Unfinished transaction — product: {tx.ProductId}, transaction ID: {tx.Id}");
            string receipt = tx.JwsRepresentation; // JWS receipt for server verification
        }
        break;

    default:
        Debug.LogWarning($"Failed to get unfinished transactions: {unfinishedResult.GetType().Name}");
        break;
}

1.3. Optional: Get current entitlements

Method

GetCurrentEntitlementsAsync

When you call GetCurrentEntitlementsAsync(), it retrieves the list of transactions for the active purchases that the user currently owns (such as non-consumable products and active subscriptions). Use it to check subscription status or to restore non-consumable products.

var entitlementsResult = await applePlugin.GetCurrentEntitlementsAsync(
    new GetCurrentEntitlementsRequest(), CancellationToken.None);

switch (entitlementsResult)
{
    case { } success when success is AppleStoreKitServiceGetCurrentEntitlementsResult.Success s:
        foreach (AppleTransaction tx in s.Data.Transactions)
        {
            Debug.Log($"Active entitlement — product: {tx.ProductId}, type: {tx.ProductType}");
        }
        break;

    default:
        Debug.LogWarning($"Failed to get entitlements: {entitlementsResult.GetType().Name}");
        break;
}

2. Verify receipts and deliver products

Pass the receipt (JwsRepresentation) of the undelivered purchase you got again as AxylReceipt in the payment result data save request of Step 3. Purchase a product, the same as for a new purchase, but set RequestType to 2 (purchase restoration).

With the receipt you got again, repeat the following process.

  1. Prepare the receipt information and pass it to the app server. Also set requestType of the receipt verification request that the app server sends to 2 (purchase restoration).
  2. The app server verifies the receipt with the Hive Axyl Server API.
  3. When verification is complete, deliver the product and finish the transaction.