Manual/Gameplay Systems/Shop, trading & IAP
v1.0.364 notes · build 2026-11-07 12:10 UTC

Shop, trading & IAP

Google Play flow · obfuscated-id smuggling · non-IAP economy
#shop #iap #economy

Google Play (Android) purchase flow

  1. Lua UI fires pay.action (analytics), then pay.before.check with the internal product id + detected currency.
  2. Server responds with a fresh selfOrderId (correlation token) + confirmed productId.
  3. Client invokes native code with {skuId, itemId: selfOrderId, uid}; Billing Library launchBillingFlow uses setObfuscatedAccountId(itemId) = selfOrderId and setObfuscatedProfileId(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.
  4. Google Play handles the purchase UI outside game code; on success the client reads the smuggled values from the completed Purchase object.
  5. Client sends SFS pay: {orderId, productId, purchaseTime, signData (raw receipt JSON), signature, itemId: selfOrderId, pay_closingCurrency, pay_PriceOfClosingCurrency}. The server independently verifies signData/signature against Google's purchase-verification API; the client-submitted receipt is untrusted input — not forgeable without a genuine Google Play receipt.
  6. Only after server confirmation does the client call ConsumeProduct (makes the consumable re-purchasable).
cmdPlatform / purpose
pay.before.checkPre-flight, always first, all platforms
payGoogle Play receipt submission
pay.iosApp Store (StoreKit) receipt
pay.amazon / pay.tstoreAmazon Appstore / Korean OneStore
pay.gold.brick.newFirst-party web-payment rail (external checkout, US/JP alt-billing)
pay.refund.request / .listPlayer-initiated refund flow
get.week.card.info / receive.week.card.rewardSubscription ("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