Legacy iOS In-App Purchase
Legacy iOS SDK is in maintenance-only mode and will be removed. New games must use SDK v2 StoreKit.
Initiate Purchase
[[OEGManager sharedManager] inAppPurchaseWithServerID:@"server_01"
roleID:@"role_123"
levels:@"50"
accountID:@"acc_456"
productID:@"com.game.gems100"
extInfo:@""
callback:^(OEGIAPStatus status, NSString *message, NSError *error) {
if (status == OEGVerified) {
// OEG server verified the receipt — DO NOT grant items here.
// Item delivery is handled by your game server via the OEG entitlement
// webhook (S2S). Refresh player inventory from your game server instead.
} else if (status == OEGPurchased) {
// Apple charged but server verify failed — item will be re-verified automatically on next login
} else if (status == OEGFailed) {
// Purchase cancelled or failed
}
}];
Important: All in-game items are consumable. Apple's
restoreCompletedTransactionsdoes NOT return consumable transactions. Recovery works via the SDK's ownUserDefaultspersistence — pending context survives app restarts and is re-verified automatically after login.
OEGVerified only confirms that the OEG backend verified the StoreKit receipt with Apple. It is not a signal to grant items from the client. Item entitlement must be performed by your game server, which receives a delivery callback from the OEG backend after verification. Granting items client-side can lead to double-grants or fraud.
See Server Integration → Mobile IAP for the API contract your game server must implement.
Check for Pending Purchases
Lightweight synchronous check — no network call. Checks both UserDefaults and the live StoreKit queue. Use this to decide whether to show a "Restore Purchases" button.
if ([[OEGManager sharedManager] hasPendingPurchasesForCurrentUser]) {
// Show restore button or prompt
}
Silent Re-verify on Login / Shop Screen
Re-sends pending transactions to the server silently. Safe to call at any time. Does not trigger Apple's restore flow. The SDK already calls this automatically after every successful login.
[[OEGManager sharedManager] processPendingPurchasesWithCallback:^(OEGIAPStatus status, NSString *message, NSError *error) {
if (status == OEGVerified) {
// Item was delivered — refresh player inventory
}
}];
Auto-process on Game Load (Recommended)
Call this once after your game finishes loading. The SDK checks silently — no UI, no parameters. Covers the case where the user's session was already active (token valid from a previous session) and the login flow was never triggered this launch.
// In your game's main scene or after confirming user is logged in:
[[OEGManager sharedManager] checkAndProcessPendingPurchases];
The SDK already calls this automatically after every login. You only need checkAndProcessPendingPurchases for sessions where the user was already logged in when the app launched.
How It Works
- Player taps Buy →
SKPaymentQueuereceivesSKPaymentTransactionStatePurchased - SDK saves transaction context to
UserDefaults(kOEGPendingIAPTransactions) — does NOT callfinishTransactionyet - SDK sends receipt + context to OEG server for S2S verification
- Only on
OEGVerifieddoes the SDK callfinishTransactionand clear the pending record - If the app is killed before step 3 completes, StoreKit re-delivers the transaction on next launch
- On next launch,
processPendingTransactionsForCurrentUserruns automatically after login and re-verifies
This prevents item loss if the app crashes or network fails between purchase and server confirmation.
Duplicate Transaction (HTTP 409)
If the app crashes after the server grants items but before finishTransaction is called, StoreKit re-delivers the transaction on the next launch. The server returns HTTP 409 (duplicate transaction ID).
The SDK handles this automatically:
- Calls
finishTransactionto remove it from the StoreKit queue permanently - Clears the pending context from
UserDefaults - Returns
OEGVerifiedto your callback — items were already granted in the previous session
You do not need to handle 409 in your game code.
Multi-Account Safety
Each pending entry is tagged with the purchasing user's UUID. If a different user is logged in when restore runs, their entries are filtered out — no cross-account item delivery. The transaction stays in the StoreKit queue until the correct user logs in and processPendingTransactionsForCurrentUser verifies and finishes it.
TTL
Entries older than 30 days are pruned automatically. A [CS-ALERT] warning is logged for CS follow-up on any pruned entries. The platform transaction is also finished at prune time to keep the StoreKit queue clean.