Legacy Android In-App Purchase
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
)
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 —
GameDatais not available at login time. CallrestorePurchasesexplicitly 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
- User taps Buy → Google Play confirms payment
- SDK saves transaction + GameData to ObjectBox — does NOT call
consumeAsyncyet - SDK sends
purchaseTokento OEG server for S2S verification - On server success or HTTP 409: SDK calls
consumeAsyncfirst, then removes the pending entry - If app crashes before step 3 completes, the entry survives in ObjectBox
- On next
restorePurchasescall, the SDK re-verifies using stored GameData
Ordering guarantee:
consumeAsyncis 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
productIdthat matches what OEG configured for the game. - Keep
serverId,roleId, andaccountIdaligned with the active player session.