Shop, trading & IAP
Google Play (Android) purchase flow
- Lua UI fires
pay.action(analytics), thenpay.before.checkwith the internal product id + detected currency. - Server responds with a fresh
selfOrderId(correlation token) + confirmedproductId. - Client invokes native code with
{skuId, itemId: selfOrderId, uid}; Billing LibrarylaunchBillingFlowusessetObfuscatedAccountId(itemId)=selfOrderIdandsetObfuscatedProfileId(currencyCode + "_" + priceMicros)— the game smuggles its own order id and exact price/currency through Google's two generic "obfuscated id" fields because Play Billing lacks custom purchase metadata. - Google Play handles the purchase UI outside game code; on success the client reads the smuggled values from the completed
Purchaseobject. - Client sends SFS
pay:{orderId, productId, purchaseTime, signData (raw receipt JSON), signature, itemId: selfOrderId, pay_closingCurrency, pay_PriceOfClosingCurrency}. The server independently verifiessignData/signatureagainst Google's purchase-verification API; the client-submitted receipt is untrusted input — not forgeable without a genuine Google Play receipt. - Only after server confirmation does the client call
ConsumeProduct(makes the consumable re-purchasable).
| cmd | Platform / purpose |
|---|---|
pay.before.check | Pre-flight, always first, all platforms |
pay | Google Play receipt submission |
pay.ios | App Store (StoreKit) receipt |
pay.amazon / pay.tstore | Amazon Appstore / Korean OneStore |
pay.gold.brick.new | First-party web-payment rail (external checkout, US/JP alt-billing) |
pay.refund.request / .list | Player-initiated refund flow |
get.week.card.info / receive.week.card.reward | Subscription ("week card") claims |
Non-IAP economy (no cryptography)
Trading Center (get.r.exchange.info, money.buy.resource, resource.sell.money), item shop (item.buy, user.shop.buy.new), player-to-player Storage Shop marketplace — plain RPCs gated only by server-side currency balances; no receipts or signing.
Naming trap
purchase.order.refresh/.finish/.delete is not IAP — it's a production-queue feature (grocery store / resident orders). Only pay*/Pay.* commands are real-money purchases.
notes build 2026-11-07 12:10 UTC · lw-notes@9c47e1b · sources: own capture/analysis cross-checked against the public dossier