Skip to main content

Legacy Android In-App Purchase

Deprecated — do not use for new games

Legacy Android SDK is in maintenance-only mode and will be removed. New games must use SDK v2 IAP.

Prepare GameData

val gameData = GameData(
serverId = 1,
level = 50,
roleId = "Hero_1001",
accountId = "Hero_1001",
extInfo = "",
productId = "YOUR_PRODUCT_ID"
)

Launch the Payment UI

OegSdk.showPayment(
gameData = gameData,
callback = object : IabCallBack {
override fun onIabResult(iabResult: WorkResult<PurchaseInfo>) {
if (iabResult.isSuccess()) {
// 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 {
println(iabResult.error()?.message)
}
}
},
orientation = OegSdk.ScreenOrientation.PORTRAIT
)
Server-authoritative delivery

isSuccess only confirms that the OEG backend verified the receipt with Google Play. It is not a signal to grant items from the client. Item entitlement is performed by your game server, which receives a delivery callback from the OEG backend after verification.

See Server Integration → Mobile IAP for the API contract your game server must implement.

Restore Pending Purchases

Re-verifies all pending purchases for the current user. Call this after the user enters the game and GameData is available — for example, after character selection.

OegSdk.restorePurchases(
gameData = gameData,
callback = object : IabCallBack {
override fun onIabResult(iabResult: WorkResult<PurchaseInfo>) {
if (iabResult.isSuccess()) {
// Item verified and delivered — refresh inventory
} else {
// Entry retained — will retry next call
}
}
}
)

Callbacks fire per entry — one callback per pending transaction processed. If there are 3 pending entries, your callback fires 3 times.

There is no auto-restore on login for legacy Android — GameData is not available at login time. Call restorePurchases explicitly once GameData is known.

Check for Pending Purchases

Lightweight check — no network call. Returns true if the store has entries for the current logged-in user.

if (OegSdk.hasPendingPurchasesForCurrentUser()) {
// Call restorePurchases with GameData
}

How It Works

  1. User taps Buy → Google Play confirms payment
  2. SDK saves transaction + GameData to ObjectBox — does NOT call consumeAsync yet
  3. SDK sends purchaseToken to OEG server for S2S verification
  4. On server success or HTTP 409: SDK calls consumeAsync first, then removes the pending entry
  5. If app crashes before step 3 completes, the entry survives in ObjectBox
  6. On next restorePurchases call, the SDK re-verifies using stored GameData

Ordering guarantee: consumeAsync is always called before the store entry is removed. If the app crashes between the two steps, the entry is still present → next session re-verifies → server returns 409 → clean removal.

Duplicate Transaction (HTTP 409)

If the app crashes after the server grants items but before consumeAsync is called, the next restorePurchases call re-verifies. The server returns HTTP 409.

The SDK handles this automatically — calls consumeAsync, removes the pending entry, and returns a success result. 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. restorePurchases filters entries by the current user's UUID — no cross-account item delivery.

Notes

  • The SDK owns the purchase UI and checkout flow.
  • Use a stable productId that matches what OEG configured for the game.
  • Keep serverId, roleId, and accountId aligned with the active player session.