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)
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
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
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.
- Prepare the receipt information and pass it to the app server. Also set
requestTypeof the receipt verification request that the app server sends to2(purchase restoration). - The app server verifies the receipt with the Hive Axyl Server API.
- When verification is complete, deliver the product and finish the transaction.