← All @molecule/* packages · App templates

@molecule/app-iap

Feature · iap · App (browser) · v1.0.1 · Apache-2.0

In-app purchase and subscription management

npm install @molecule/app-iap

npm · Source on GitHub

How it works

@molecule/app-iap is a ready-made iap feature for the app (browser) side. It composes the core interfaces it needs, so it works with whichever providers your app has bonded.

import {
  createNoopIAPProvider,
  initialize,
  order,
  finish,
  register,
  refresh,
  setProvider,
  verify,
} from '@molecule/app-iap'

// Wire the provider at app startup (swap for an iOS/Android bond in production)
setProvider(createNoopIAPProvider())
await initialize()
register([{ id: 'com.example.pro_monthly', alias: 'pro_monthly', type: 'subscription' }])
await refresh()

const result = await order('pro_monthly')
if (result.success && result.product) {
  await verify(result.product, '/api/iap/verify')
  finish(result.product)
}

Works with: @molecule/app-bond, @molecule/app-i18n

Reference

Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit src/index.ts JSDoc, not this file.

In-App Purchases interface for molecule.dev.

Provides a unified API for in-app purchases that works across different platforms (iOS App Store, Google Play, web Stripe).

Quick Start

import {
  createNoopIAPProvider,
  initialize,
  order,
  finish,
  register,
  refresh,
  setProvider,
  verify,
} from '@molecule/app-iap'

// Wire the provider at app startup (swap for an iOS/Android bond in production)
setProvider(createNoopIAPProvider())
await initialize()
register([{ id: 'com.example.pro_monthly', alias: 'pro_monthly', type: 'subscription' }])
await refresh()

const result = await order('pro_monthly')
if (result.success && result.product) {
  await verify(result.product, '/api/iap/verify')
  finish(result.product)
}

Type

feature

Installation

npm install @molecule/app-iap @molecule/app-bond @molecule/app-i18n

API

Interfaces

IAPError

In-app purchase error with error code, product ID, and platform-specific details.

interface IAPError {
  /**
   * Error code.
   */
  code: string | number

  /**
   * Error message.
   */
  message: string

  /**
   * Product ID (if applicable).
   */
  productId?: string

  /**
   * Raw error.
   */
  raw?: unknown
}

IAPProvider

In-App Purchases provider interface.

interface IAPProvider {
  /**
   * Initializes the IAP system.
   */
  initialize(): Promise<void>

  /**
   * Registers products for purchase.
   */
  register(products: ProductDefinition[]): void

  /**
   * Refreshes product information from the store.
   */
  refresh(): Promise<void>

  /**
   * Gets a product by ID or alias.
   */
  get(idOrAlias: string): Product | undefined

  /**
   * Gets all registered products.
   */
  getAll(): Product[]

  /**
   * Checks if a product can be purchased.
   */
  canPurchase(idOrAlias: string): boolean

  /**
   * Initiates a purchase.
   */
  order(idOrAlias: string): Promise<PurchaseResult>

  /**
   * Finishes a transaction (must be called after successful verification).
   */
  finish(product: Product): void

  /**
   * Verifies a purchase with the server.
   */
  verify(
    product: Product,
    verifyUrl: string,
    additionalData?: Record<string, unknown>,
  ): Promise<VerificationResult>

  /**
   * Restores previous purchases.
   */
  restore(): Promise<Product[]>

  /**
   * Opens the subscription management page.
   */
  manageSubscriptions(): void

  /**
   * Subscribes to product events.
   */
  when(idOrAlias: string): {
    updated: (handler: ProductEventHandler) => void
    approved: (handler: ProductEventHandler) => void
    finished: (handler: ProductEventHandler) => void
    cancelled: (handler: ProductEventHandler) => void
    error: (handler: ErrorEventHandler) => void
  }

  /**
   * Subscribes to global events.
   */
  on(event: IAPEvent, handler: IAPEventHandler): () => void

  /**
   * Unsubscribes from events.
   */
  off(handler: IAPEventHandler): void

  /**
   * Gets the platform name.
   */
  getPlatform(): 'ios' | 'android' | 'web' | 'unknown'

  /**
   * Checks if IAP is available.
   */
  isAvailable(): boolean

  /**
   * Destroys the IAP system.
   */
  destroy(): void
}

Product

Full in-app product details (ID, type, state, pricing, ownership, transaction, subscription info).

interface Product {
  /**
   * Product ID (SKU).
   */
  id: string

  /**
   * Product alias.
   */
  alias: string

  /**
   * Product type.
   */
  type: ProductType

  /**
   * Product state.
   */
  state: ProductState

  /**
   * Product title.
   */
  title: string

  /**
   * Product description.
   */
  description: string

  /**
   * Formatted price string.
   */
  price: string

  /**
   * Price in micros (cents * 10000).
   */
  priceMicros: number

  /**
   * Currency code (ISO 4217).
   */
  currency: string

  /**
   * Whether the product can be purchased.
   */
  canPurchase: boolean

  /**
   * Whether the product is owned.
   */
  owned: boolean

  /**
   * Transaction information (if applicable).
   */
  transaction?: Transaction

  /**
   * Subscription period (for subscriptions).
   */
  subscriptionPeriod?: SubscriptionPeriod

  /**
   * Introductory price (for subscriptions with trial).
   */
  introPrice?: string

  /**
   * Trial period in days.
   */
  trialPeriodDays?: number

  /**
   * Product group.
   */
  group?: string

  /**
   * Raw platform-specific data.
   */
  raw?: unknown
}

ProductDefinition

Product definition for registration.

interface ProductDefinition {
  /**
   * Product ID (SKU) - platform-specific identifier.
   */
  id: string

  /**
   * Product alias - cross-platform identifier.
   */
  alias: string

  /**
   * Product type.
   */
  type: ProductType

  /**
   * Product group (for subscription grouping).
   */
  group?: string
}

PurchaseResult

Outcome of a purchase attempt (success flag, product, transaction, or error).

interface PurchaseResult {
  /**
   * Whether the purchase was successful.
   */
  success: boolean

  /**
   * The purchased product.
   */
  product?: Product

  /**
   * Transaction information.
   */
  transaction?: Transaction

  /**
   * Error (if purchase failed).
   */
  error?: IAPError
}

Transaction

Purchase transaction record (ID, receipt, purchase token, timestamps, validity).

interface Transaction {
  /**
   * Transaction ID.
   */
  id: string

  /**
   * Platform-specific receipt.
   */
  receipt?: string

  /**
   * App Store receipt (iOS).
   */
  appStoreReceipt?: string

  /**
   * Purchase token (Android).
   */
  purchaseToken?: string

  /**
   * Purchase time.
   */
  purchaseTime?: Date

  /**
   * Expiration time (for subscriptions).
   */
  expirationTime?: Date

  /**
   * Whether the purchase is valid.
   */
  isValid?: boolean

  /**
   * Raw platform-specific data.
   */
  raw?: unknown
}

VerificationResult

Verification result from server.

interface VerificationResult {
  /**
   * Whether the receipt is valid.
   */
  valid: boolean

  /**
   * Subscription expiration time.
   */
  expirationTime?: Date

  /**
   * Whether the subscription is active.
   */
  isActive?: boolean

  /**
   * Plan/tier information.
   */
  plan?: string

  /**
   * Server response data.
   */
  data?: unknown
}

Types

ErrorEventHandler

Event handler called with an IAPError when a purchase error occurs.

type ErrorEventHandler = (error: IAPError) => void

IAPEvent

IAP lifecycle events: ready, product-updated, approved, finished, cancelled, error, pending, expired, restored.

type IAPEvent =
  | 'ready'
  | 'product-updated'
  | 'approved'
  | 'finished'
  | 'cancelled'
  | 'error'
  | 'pending'
  | 'expired'
  | 'restored'

IAPEventHandler

Generic event handler for IAP events.

type IAPEventHandler<T = unknown> = (data: T) => void

ProductEventHandler

Event handler called with a Product when a product-related event occurs.

type ProductEventHandler = (product: Product) => void

ProductState

Purchase lifecycle state of an in-app product (registered, valid, approved, owned, cancelled, etc.).

type ProductState =
  | 'registered'
  | 'valid'
  | 'invalid'
  | 'requested'
  | 'initiated'
  | 'approved'
  | 'finished'
  | 'owned'
  | 'cancelled'
  | 'downloading'

ProductType

In-app purchase product categories: one-time consumable, permanent non-consumable, or recurring subscription.

type ProductType = 'consumable' | 'non-consumable' | 'subscription'

SubscriptionPeriod

Subscription billing interval: weekly, monthly, yearly, or lifetime.

type SubscriptionPeriod = 'weekly' | 'monthly' | 'yearly' | 'lifetime'

Functions

createNoopIAPProvider()

Creates a no-op IAP provider for web/testing.

function createNoopIAPProvider(): IAPProvider

Returns: A no-op IAP provider that stubs all purchase operations.

finish(product)

Finishes a pending transaction, acknowledging delivery to the store.

function finish(product: Product): void
  • product — The product whose transaction should be finalized.

Returns: Nothing.

get(idOrAlias)

Gets a product by its store ID or registered alias.

function get(idOrAlias: string): Product | undefined
  • idOrAlias — The product store ID or alias to look up.

Returns: The matching product, or undefined if not found.

getAll()

Gets all registered products.

function getAll(): Product[]

Returns: An array of all available products.

getErrorMessage(error, t)

Gets a user-friendly error message.

function getErrorMessage(
  error: unknown,
  t?: (
    key: string,
    values?: Record<string, unknown>,
    options?: { defaultValue?: string },
  ) => string,
): string
  • error — The IAP error object or unknown thrown value to translate.
  • t — Optional i18n translation function for localized messages.

Returns: A user-friendly error message string.

getProvider()

Gets the current IAP provider. Falls back to a no-op provider if none has been bonded — on web this is correct (no store exists), but on iOS/Android a missing real provider means every order() reports unavailable. The fallback warns when it engages so the omission is visible rather than a silent failure.

function getProvider(): IAPProvider

Returns: The active IAP provider instance.

hasProvider()

Checks if an IAP provider has been bonded.

function hasProvider(): boolean

Returns: Whether an IAP provider is currently registered.

initialize()

Initializes the IAP system via the active provider.

function initialize(): Promise<void>

Returns: A promise that resolves when initialization is complete.

isAvailable()

Checks if in-app purchases are available on the current platform.

function isAvailable(): boolean

Returns: Whether the IAP system is available and functional.

manageSubscriptions()

Opens the platform's subscription management UI.

function manageSubscriptions(): void

Returns: Nothing.

order(idOrAlias)

Initiates a purchase order for a product.

function order(idOrAlias: string): Promise<PurchaseResult>
  • idOrAlias — The product store ID or alias to purchase.

Returns: A promise that resolves with the purchase result.

refresh()

Refreshes product information from the store.

function refresh(): Promise<void>

Returns: A promise that resolves when product data has been refreshed.

register(products)

Registers product definitions with the IAP provider.

function register(products: ProductDefinition[]): void
  • products — The product definitions to register for purchase availability.

Returns: Nothing.

restore()

Restores previously completed purchases from the store.

function restore(): Promise<Product[]>

Returns: A promise that resolves with an array of restored products.

setProvider(provider)

Sets the IAP provider.

function setProvider(provider: IAPProvider): void
  • provider — The IAP provider implementation to bond.

verify(product, verifyUrl, additionalData)

Verifies a purchase receipt with a server endpoint.

function verify(
  product: Product,
  verifyUrl: string,
  additionalData?: Record<string, unknown>,
): Promise<VerificationResult>
  • product — The product whose purchase receipt to verify.
  • verifyUrl — The server URL to send the verification request to.
  • additionalData — Extra data to include in the verification payload.

Returns: A promise that resolves with the server verification result.

Constants

errorMessages

Error code mapping for user-friendly messages. Derived from defaultTranslations to avoid duplicating strings.

const errorMessages: Record<string, string>

Injection Notes

Requirements

Peer dependencies:

  • @molecule/app-bond ^1.0.1
  • @molecule/app-i18n ^1.0.1

Runtime Dependencies

  • @molecule/app-bond

  • @molecule/app-i18n

  • NO store provider ships with the fleet yet: the only built-in implementation is createNoopIAPProvider(), and getProvider() silently self-bonds it when nothing is wired — so without a real provider order() ALWAYS fails with E_NOT_AVAILABLE, verify() returns { valid: false }, and isAvailable() is false. To sell on iOS / Android, implement IAPProvider yourself (e.g. wrapping cordova-plugin-purchase, StoreKit 2, or Play Billing) and wire it with setProvider() at startup.

  • verify() POSTs the purchase to YOUR server: implement the endpoint with @molecule/api-payments-apple / @molecule/api-payments-google (receipt validation) and call finish() only after the server says the receipt is valid — finishing first loses the purchase if validation fails.

  • Error messages route through t('iap.error.*') with English fallbacks; the @molecule/app-locales-iap bond supplies 79 translations.

Translations

Translation strings are provided by @molecule/app-locales-iap.