Skip to main content

Legacy iOS In-App Purchase

Deprecated — do not use for new games

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 restoreCompletedTransactions does NOT return consumable transactions. Recovery works via the SDK's own UserDefaults persistence — pending context survives app restarts and is re-verified automatically after login.

Server-authoritative delivery

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
}
}];

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​

  1. Player taps Buy → SKPaymentQueue receives SKPaymentTransactionStatePurchased
  2. SDK saves transaction context to UserDefaults (kOEGPendingIAPTransactions) — does NOT call finishTransaction yet
  3. SDK sends receipt + context to OEG server for S2S verification
  4. Only on OEGVerified does the SDK call finishTransaction and clear the pending record
  5. If the app is killed before step 3 completes, StoreKit re-delivers the transaction on next launch
  6. On next launch, processPendingTransactionsForCurrentUser runs 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 finishTransaction to remove it from the StoreKit queue permanently
  • Clears the pending context from UserDefaults
  • Returns OEGVerified to 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.