HELIX 3 Docs
Helix Phone

In-app purchases

Sell consumables, unlocks, and subscriptions inside a phone app — priced in LIX, idempotent, and declared in your manifest.

Phone apps monetize with in-app purchases (IAP) priced in LIX. You declare a product catalog in your manifest; players buy with phone.payments.

Declare products

// in the app manifest
iap: [
  { sku: "demo_boost_1",    name: "Demo Boost",      priceLix: 150, type: "consumable" },
  { sku: "demo_theme_pack", name: "Demo Theme Pack", priceLix: 500, type: "non_consumable" },
  { sku: "pro_monthly",     name: "Pro",             priceLix: 999, type: "subscription", period: "P1M" },
]
TypeMeaning
consumableCan be bought repeatedly (boosts, currency packs). Each purchase is a new entitlement.
non_consumableBought once, owned forever (a theme, an unlock). Re-purchase returns the existing entitlement.
subscriptionRecurring access with an expiresAt.

Purchase

The client requests; the server validates against the manifest, applies idempotency, and grants:

const ent = await phone.payments.purchase("demo_theme_pack", {
  idempotencyKey: crypto.randomUUID(),
});
if (ent) unlockTheme(ent.sku);

Always pass an idempotencyKey

Networks retry. With a stable idempotencyKey, a retried purchase returns the same entitlement instead of charging twice. Generate it once per purchase attempt.

Read what the player owns

const owned = await phone.payments.getEntitlements();
const hasPro = owned.some(e => e.sku === "pro_monthly" && !isExpired(e));

// on a fresh device:
await phone.payments.restore();

An entitlement:

type PhoneIapEntitlement = {
  sku: string;
  productName: string;
  productType: "consumable" | "non_consumable" | "subscription";
  priceLix: number;
  expiresAt: string | null;   // future date for subscriptions
  mock: boolean;              // true until LIX settlement ships
};

Settlement status

Mock settlement today

Purchases currently grant entitlements but do not debit LIX — they're recorded with mock: true (settlement: pending_lix_purchase_sheet). When LIX settlement ships, the same phone.payments.purchase(...) call will present the platform purchase sheet and debit the player's wallet server-side; your code won't change. Build against this API now. Tracked on Proposed & in-progress.

Server authority

As everywhere in Helix, value is server-authoritative: the client can't grant itself an entitlement. The server checks the payments scope, verifies the sku exists in your manifest, applies idempotency, and (soon) charges LIX. Mirror the platform economy rules — never trust a client-reported purchase.

On this page