Error Reference
This page is a complete reference for every error code the AppCoins iOS SDK can return, covering both the native Swift interface and the Unity IAP v5 integration. For each error you will find what it means, the most common causes, and the recommended fix.
Swift Errors (AppCoinsSDKError)
All errors thrown by the Swift SDK are of type AppCoinsSDKError. The enum has six cases.
networkError
A network request made by the SDK failed before a response was received.
Common causes:
- Device has no internet connection.
- The Aptoide billing server was temporarily unreachable.
- The request timed out.
How to fix:
- Check connectivity before calling SDK methods (e.g.
NWPathMonitor). - Implement a retry with exponential back-off for transient failures.
- Show the user a message such as "Check your connection and try again."
do {
let products = try await Product.products()
} catch let error as AppCoinsSDKError {
if case .networkError(let description) = error {
print("Network error: \(description)")
// Show retry UI
}
}
systemError
An internal AppCoins system error occurred, or the server returned an unexpected response.
Common causes:
- An SDK internal failure not caused by user action or connectivity.
- An unexpected or malformed response from the Aptoide billing server.
How to fix:
- Log the full description for diagnostics.
- Retry the operation once after a short delay.
- If the error persists across sessions, report it to Aptoide support with the logged description.
if case .systemError(let description) = error {
print("System error: \(description)")
}
notEntitled
The host application is missing the Keychain Sharing entitlement that the SDK requires to store wallet information.
Common causes:
- The Keychain Sharing capability has not been added to the target.
- The keychain group is set to something other than
com.aptoide.appcoins-wallet(for example, the app's own bundle identifier).
How to fix:
- In Xcode, select your target and go to the Signing & Capabilities tab.
- Click + and add the Keychain Sharing capability.
- In the Keychain Groups list, replace any existing entry with exactly
com.aptoide.appcoins-wallet. - Clean and rebuild.
com.aptoide.appcoins-wallet with no prefix and no suffix. Xcode sometimes pre-fills your Team ID or bundle identifier — delete that entry and type the value above manually.if case .notEntitled = error {
// Configuration error — cannot be recovered at runtime.
// Fix in Xcode Signing & Capabilities.
print("Missing Keychain Sharing entitlement.")
}
productUnavailable
The requested SKU could not be found or is not currently available for purchase.
Common causes:
- The SKU identifier in your code does not exactly match the one defined in Aptoide Connect.
- The app has not yet been reviewed and approved on Aptoide Connect.
- The product has been disabled in Aptoide Connect.
How to fix:
- Open Aptoide Connect and verify that the SKU identifiers match character-for-character (they are case-sensitive).
- Check that your app has been submitted and approved on Aptoide Connect. Products cannot be queried until the app passes review.
- Confirm the product is enabled and not archived.
if case .productUnavailable(let description) = error {
print("Product unavailable: \(description)")
}
purchaseNotAllowed
The user is not permitted to make purchases in this context.
Common causes:
- Parental controls are enabled on the device and restrict purchases.
- The user's account has regional restrictions that prevent this purchase.
- Screen Time or another restriction profile is blocking in-app purchases.
How to fix: This error cannot be resolved by your app. Display a message explaining that purchases are not allowed in the current context, and suggest the user check their device restrictions.
if case .purchaseNotAllowed(let description) = error {
// Inform the user — nothing the app can do programmatically.
print("Purchase not allowed: \(description)")
}
unknown
An error occurred that does not fall into any of the categories above.
How to fix:
- Log the description returned by the error for diagnostics.
- Treat it as a transient failure and allow the user to retry.
- If the error appears consistently, report it to Aptoide support with the full description.
if case .unknown(let description) = error {
print("Unknown error: \(description)")
}
Unity Errors (AppCoinsSDKError mapped to Unity IAP)
The Unity IAP v5 integration translates AppCoins errors into standard Unity IAP failure reasons. The table below shows the full mapping.
| AppCoins Error | Unity IAP Reason | Applies to |
|---|---|---|
productUnavailable | ProductFetchFailureReason.ProductsUnavailable | OnProductsFetchFailed |
networkError | ProductFetchFailureReason.ProviderUnavailable | OnProductsFetchFailed |
productUnavailable | PurchaseFailureReason.ProductUnavailable | OnPurchaseFailed |
purchaseNotAllowed | PurchaseFailureReason.PaymentDeclined | OnPurchaseFailed |
notEntitled | PurchaseFailureReason.PaymentDeclined | OnPurchaseFailed |
systemError | PurchaseFailureReason.Unknown | OnPurchaseFailed |
unknown | PurchaseFailureReason.Unknown | OnPurchaseFailed |
Handling purchase failures in Unity IAP v5:
_controller.OnPurchaseFailed += OnPurchaseFailed;
private void OnPurchaseFailed(FailedOrder order)
{
switch (order.FailureReason)
{
case PurchaseFailureReason.UserCancelled:
// User dismissed the payment sheet — no action needed.
break;
case PurchaseFailureReason.ProductUnavailable:
// SKU not found in Aptoide Connect — check your product configuration.
Debug.LogError("Product unavailable: " + order.Details);
break;
case PurchaseFailureReason.PaymentDeclined:
// Parental controls, region restriction, or missing Keychain entitlement.
// Show the user a message; check Xcode entitlements if this is unexpected.
Debug.LogError("Payment declined: " + order.Details);
break;
default:
// Transient or unknown failure — allow retry.
Debug.LogError($"Purchase failed ({order.FailureReason}): {order.Details}");
break;
}
}
Handling product fetch failures in Unity IAP v5:
_controller.OnProductsFetchFailed += OnProductsFetchFailed;
private void OnProductsFetchFailed(ProductFetchFailed failure)
{
Debug.LogError("Products fetch failed: " + failure.FailureReason);
foreach (var product in failure.FailedFetchProducts)
Debug.LogError("Failed to fetch product: " + product.id);
}
Verification Errors
Swift — VerificationResult.unverified
When a purchase succeeds, the SDK performs a local signature check. If the signature cannot be verified, the result is .unverified(transaction, error).
case .success(let verificationResult):
switch verificationResult {
case .verified(let purchase):
// Signature check passed — safe to grant the item.
try await purchase.finish()
case .unverified(let purchase, let verificationError):
// Signature check failed. Decide based on your business logic:
// Option A (lenient): grant the item anyway and finish.
// try await purchase.finish()
// Option B (strict): do NOT finish — Aptoide will refund after 24 hours.
print("Unverified purchase: \(verificationError)")
}
purchase.finish() on an unverified transaction, the purchase is automatically refunded after 24 hours. Account for this in your business logic before shipping.Unity — verificationResult field in the receipt
The receipt attached to every PendingOrder is a JSON string. Parse the Payload field to find verificationResult, which is either "verified" or "unverified".
private void OnPurchasePending(PendingOrder order)
{
// The receipt is a JSON string: { "Store": "...", "TransactionID": "...", "Payload": "..." }
// Parse Payload to inspect verificationResult.
string receipt = order.Info.Receipt;
// Forward the receipt to your backend for Remote Check validation (optional).
// Then decide whether to grant and confirm:
GiveItemToUser(order);
_controller.ConfirmPurchase(order); // Consumes the purchase.
}
If you use server-side validation via Remote Check and the server returns unverified, you may choose to withhold the item and let the purchase time out (the user will be refunded). If you grant the item, call ConfirmPurchase to consume it immediately.
For setup and configuration problems that surface as runtime failures, see the Troubleshooting guide.