---
title: "Get Products"
method: GET
path: "/iap/products"
tags: ["Products"]
---

# Get Products

`GET /iap/products`

Fetches the product catalog for your app, including web and StoreKit prices, checkout configuration, trial eligibility, and any active migration campaign. Pass `user_id` to get per-user trial eligibility.

## Query parameters

- `user_id` string
- `demo` 'migration' | 'upgrade'

## Response `200`

Product catalog with checkout configuration

- object
  - `products` Product[], required
    - `id` string — The product's reference ID (e.g., `com.app.premium.monthly`).
    - `display_name` string — Human-readable product name.
    - `product_description` string — Product description text.
    - `type` 'consumable' | 'non_consumable' | 'non_renewing_subscription' | 'auto_renewable_subscription' — The product type.
    - `web_price` Price — A price in micros (1/1,000,000 of the currency unit).
      - `amount_micros` integer — Price in micros. For example, $4.99 = 4990000.
      - `currency_code` string — ISO 4217 currency code (e.g., `USD`).
    - `storekit_price` Price — A price in micros (1/1,000,000 of the currency unit).
      - `amount_micros` integer — Price in micros. For example, $4.99 = 4990000.
      - `currency_code` string — ISO 4217 currency code (e.g., `USD`).
    - `subscription_group_id` integer, nullable — The subscription group this product belongs to, or null for non-subscription products.
    - `free_trial_duration` string, nullable — ISO 8601 duration for the free trial period (e.g., `P7D` for 7 days), or null if no trial is configured.
    - `is_trial_eligible` boolean, nullable — Whether the current user is eligible for a free trial on this product. Null if `user_id` was not provided in the request.
    - `trial` object, nullable — Trial mode details for this product. Present only for `auto_renewable_subscription` products that have a free trial configured AND whose trial eligibility was resolved (i.e., `user_id` was included in the request and the user is trial-eligible). Absent for non-subscription products, products without a trial, and anonymous requests.
      - `mode` 'free' | 'paid' | 'auth_hold' — How the trial is collected. `free`: no charge during the trial period; the payment method is saved and billed at trial end. `paid`: a real upfront charge of `upfront_amount_cents` is collected immediately and kept; the full subscription price is billed at trial end. `auth_hold`: a temporary authorization hold of `hold_amount_cents` is placed (shown as a pending charge); released when the subscription converts or is cancelled.
      - `duration` string — Duration token for the trial period (e.g., `1_week`, `3_days`, `1_month`). This is a ZeroSettle token, not an ISO 8601 duration. The app should map this to its own display copy.
      - `upfront_amount_cents` integer — For `paid` mode: the real charge collected at checkout, in cents. Zero for `free` and `auth_hold` modes.
      - `hold_amount_cents` integer — For `auth_hold` mode: the authorization hold amount placed at checkout, in cents. Zero for `free` and `paid` modes.
      - `validates_card` boolean — `true` for `paid` and `auth_hold` modes (a real or pending charge verifies the card); `false` for `free` mode.
  - `checkout_config` CheckoutConfig, required — Configuration for how the SDK should present checkout.
    - `sheet_type` 'webview' | 'native' — Default checkout presentation: `native` for Apple Pay / Google Pay payment sheet, `webview` for embedded web checkout.
    - `is_enabled` boolean — Whether web checkout is enabled for this app.
    - `jurisdictions` object — Per-jurisdiction checkout overrides.
      - `us` JurisdictionConfig — Checkout configuration for a specific jurisdiction.
        - `sheet_type` 'webview' | 'native' — Checkout presentation type for this jurisdiction.
        - `is_enabled` boolean — Whether web checkout is enabled in this jurisdiction.
      - `eu` JurisdictionConfig — Checkout configuration for a specific jurisdiction.
        - `sheet_type` 'webview' | 'native' — Checkout presentation type for this jurisdiction.
        - `is_enabled` boolean — Whether web checkout is enabled in this jurisdiction.
      - `other` JurisdictionConfig — Checkout configuration for a specific jurisdiction.
        - `sheet_type` 'webview' | 'native' — Checkout presentation type for this jurisdiction.
        - `is_enabled` boolean — Whether web checkout is enabled in this jurisdiction.
    - `apple_merchant_id` string, nullable — Apple Merchant ID for Apple Pay, if configured.
  - `migration_campaign` MigrationCampaign — An active Switch & Save migration campaign.
    - `should_show` boolean — Whether the migration offer should be displayed to the user.
    - `product_id` string — The product the migration offer applies to.
    - `discount_percent` integer — Discount percentage offered (e.g., 20 for 20% off).
    - `min_subscription_days` integer — Minimum number of days the user must have been subscribed to be eligible.
    - `max_subscription_days` integer — Maximum number of subscription days for eligibility.
    - `free_trial_days` integer — Number of free trial days offered in the migration.
    - `title` string — Title text for the migration offer UI.
    - `message` string — Body text for the migration offer UI.
    - `variant_id` integer, nullable — Experiment variant ID if the campaign is part of an A/B test.
  - `offer` Offer — Unified offer payload for migration and upgrade flows.
    - `flow_type` 'migration' | 'upgrade', required — The type of offer flow.
    - `product_id` string, required — Target product reference ID.
    - `eligible_product_ids` string[], required — Product IDs the user might currently have.
    - `savings_percent` integer, required — Annualized savings percentage (0 if not computable).
    - `display` OfferDisplay, required — Server-configurable copy for every tip card state. Empty strings mean the SDK should use its hardcoded defaults.
      - `offer_title` string, required — Title for the offer card (e.g., 'Thanks for being with us!').
      - `offer_message` string, required — Main offer body text.
      - `offer_cta` string, required — CTA button text (e.g., 'Save 20% Forever').
      - `accepted_title` string, required — Post-checkout title (e.g., 'Thanks for switching!').
      - `accepted_message` string, required — Post-checkout message with Apple cancel instructions.
      - `accepted_cta` string, required — Post-checkout CTA (e.g., 'Cancel Apple Billing').
      - `completed_title` string, required — Success title (e.g., 'Congratulations!').
      - `completed_message` string, required — Success message (e.g., 'You are now saving 20% forever.').
    - `free_trial_days` integer, required — Free trial days (computed at checkout time from product config).
    - `min_subscription_days` integer, required — Minimum days subscribed before eligibility.
    - `max_subscription_days` integer, nullable, required — Maximum days subscribed for eligibility.
    - `rollout_percent` integer, required — Percentage of eligible users who see this offer (0-100).
    - `upgrade_type` 'storekit_to_web' | 'web_to_web', nullable — Upgrade subtype. Only present when flow_type is upgrade.
    - `from_product_id` string, nullable — User's current product (upgrades only).
    - `to_product_id` string, nullable — Upgrade target product (upgrades only).
    - `variant_id` integer, nullable — Experiment variant ID (when A/B testing).
    - `per_product_prompts` object, nullable — Per-product display overrides keyed by product ID.
    - `checkout_presentation` 'inline' | 'sheet', nullable — How the SDK presents checkout: inline within tip card or overlay sheet.

## Other responses

- `401` — Invalid or missing API key.
- `403` — Account disabled or insufficient permissions.

---

[API](https://skmtc.net/zerosettle/apis/zerosettle-iap-api.md) · [All operations](https://skmtc.net/zerosettle/apis/zerosettle-iap-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zerosettle/zerosettle-iap-api/versions/1a7aa12f3d5e/schema)
