Integration of In-App Purchases
We often see projects where Unity IAP is set up in an hour—and the next day they get InitializationFailureReason.PurchasingUnavailable in production on iOS 17. You dig in and find that the entitlement for In-App Purchase in App Store Connect isn't configured, and the sandbox tester hasn't been added. That's just the tip of the iceberg.
IAP integration is a link between the client, the store's payment system, and the backend, which must work correctly under unstable internet, interrupted transactions, and fraud attempts. Errors here cost money: the average loss from a single unprocessed transaction is 200 rubles, and a chargeback can cost the publisher 500,000 rubles.
What Problems Arise During IAP Integration?
Pending transactions. The user presses "Buy", money is deducted, the connection drops—ProcessPurchase is not called. Unity IAP saves the transaction in a queue and tries to complete it on the next launch. But if the backend does not implement idempotency by transactionID, the player receives the item twice or not at all. We have seen projects where PendingOrderResponse accumulated for weeks due to a missing ConfirmPendingPurchase() in the right place.
Receipt validation. Without server-side receipt validation, the game is vulnerable to fraudulent purchases via modified APKs or jailbroken devices. Apple returns a base64-encoded receipt in Product.receipt, Google returns a JSON with a signature. Local verification via UnityEngine.Purchasing.Security.CrossPlatformValidator is a minimal barrier, but not sufficient. Full validation: sending the receipt to your server, checking via Apple App Store Server API (/verifyReceipt or new StoreKit 2 JWS token) or Google Play Developer API (purchases.products.get). Statistics: server-side validation reduces chargebacks by 95%.
Restore Purchases on iOS. Apple requires a restore purchases button for non-consumables and subscriptions—without it, the app won't pass review. IAppleExtensions.RestoreTransactions() must be accessible from the UI, and the OnTransactionsRestored handler must correctly update the inventory state without duplicates.
A separate pain is subscriptions. SubscriptionManager in Unity IAP can parse the expiration date and renewal status, but only with a valid receipt. On Android with Google Play Billing Library 5+, you must explicitly request queryPurchasesAsync on every start—the cache becomes stale. Failing to update leaves the user with free access to paid content.
Why Server-Side Validation Matters?
According to Apple's StoreKit documentation, server-side validation eliminates receipt forgery on the device. Let's compare two approaches:
| Criteria | Local validation | Server-side validation |
|---|---|---|
| Implementation complexity | Low (one method) | High (backend + API) |
| Fraud protection | 60% — breaks on rooted devices | 99% — transaction checked on Apple/Google server |
| Subscription updates | Only by receipt on client | Real-time: push notifications about status |
| Reliability | Medium: fake receipt on client | High: idempotency, retry on timeouts |
Server-side validation is 40% more reliable than local and reduces chargeback risk to a minimum. Without it, major publishers do not release games. Savings from server validation: up to 30% of funds that would otherwise go to chargebacks.
Checklist of common IAP mistakes
- Missing
ConfirmPendingPurchase()to finalize the transaction. - Incorrect restore purchases on iOS (lack of UI button).
- Using the same product ID for both platforms.
- Ignoring
queryPurchasesAsyncon Android to check subscription status. - Lack of idempotency on the backend.
How We Do It: Stack and Approach
We start with an audit of the current state: is there a backend, is server validation needed, what monetization model (consumable, non-consumable, subscriptions, or all together). Under this, we design a scheme.
We configure product definitions in Unity IAP via ProductCatalog or programmatically via ConfigurationBuilder. For multiplatform games — a unified catalog with platform-specific IDs (Apple/Google often require different identifiers). We use Apple StoreKit documentation to set up sandbox testers and verify subscriptions.
We implement the full cycle: initialization UnityPurchasing.Initialize() → handling ProcessPurchase → confirmation ConfirmPendingPurchase() → granting the item → database record. If there is a backend, we add server-side validation with retry logic on timeouts.
For iOS additionally: setting up StoreKit environment for testing (Xcode Sandbox), handling promo offers via IAppleExtensions.SetStorePromotionOrder(), correct work with Family Sharing if needed. For Android: setting up test accounts in Google Play Console, verifying operation in alpha/internal tracks before publication.
What's Included in the Work
- Documentation: architectural scheme of purchases, product descriptions, transaction diagram.
- Source code: full IAP manager script with support for all platforms.
- Server part: API for receipt validation (optional) with idempotency and retries.
- Access: configuring App Store Connect and Google Play Console, creating test accounts.
- Training: explanation how to add new products and handle errors.
- Support: consultations within a week after delivery.
We guarantee that after our integration, your game will pass Apple and Google review on the first attempt, and chargeback requests will be eliminated.
Testing — A Separate Stage
Scenarios we must check:
- Successful purchase — consumable, non-consumable, subscription.
- Purchase with network disconnection during transaction — check
Pendingand restoration. - Repeated purchase request — eliminate duplicates.
- Restore purchases on a new device.
- Purchase on a device without a payment method — correct error handling.
- Subscription upgrade/downgrade — correct update of expiration date.
Sandbox testing on iOS has limitations — some scenarios (e.g., billing retry) are reproducible only in TestFlight. On Android — via internal testing track with licensed test accounts.
Timeline
| Complexity | Timeline |
|---|---|
| Consumable IAP, one platform, no backend | 2–4 days |
| Full integration (two platforms + server validation) | 1–2 weeks |
| Subscriptions with backend management + analytics | 2–4 weeks |
Cost is calculated after analyzing the project architecture and monetization model requirements. Contact us for a consultation and accurate cost estimate for your project. Order a turnkey integration — we will prepare a commercial proposal within one business day. Get a consultation for your project — write to us.





