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.