Skip to content

iap.yaml reference

One iap.yaml describes the whole billing catalog for a project. Each provider reads only the fields it needs. Copy iap.example.yaml and edit the identifiers.

Field Type Notes
appName string Display name used in reports / default group naming.
bundleId string App Store bundle id.
packageName string Google Play package name.
entitlement object The single “what you unlock” key shared across stores.
pricing object The single territory/region/currency provisioned.
products list The purchasable items.
revenuecat object RevenueCat-specific knobs (optional).
appstore object App Store-specific knobs.
screenshotsDir string Base dir for relative reviewScreenshot paths (optional; default: CWD).
Field Notes
key e.g. pro — the entitlement identifier your app checks. Required.
displayName e.g. Pro access.

storectl provisions a single territory/region/currency (multi-region is a deliberate non-goal of the first version).

Field Example Notes
territory JPN App Store territory code (ISO-3166 alpha-3).
region JP Google Play region code (ISO-3166 alpha-2).
currency JPY ISO-4217. Required.

Each product is either an auto-renewable subscription (default) or a non-consumable one-time purchase (type: nonConsumable). Subscriptions use period / playBasePlanId; non-consumables ignore them.

Field Applies to Notes
key all Logical name, e.g. monthly. Required, unique.
type all subscription (default) or nonConsumable.
appStoreId all App Store Connect productId.
playProductId all Play subscription / managed-product id.
playBasePlanId subscriptions Play base plan id.
period subscriptions ISO-8601: P1W P1M P2M P3M P6M P1Y. Required for subscriptions.
price all Major-currency units; decimals OK (4.99 = $4.99, 600 = ¥600). Must be > 0.
rcPackage all RevenueCat package key, e.g. $rc_monthly.
localizations all Per-locale store listing (see below).
reviewScreenshot all App Store only. Path to the IAP/subscription review screenshot (one per product, required before submission). Placed, not generated; resolved via screenshotsDir. Idempotent on the stored MD5.
intro subscriptions Introductory offer (free trial / intro price). See below.

A free trial or introductory price, applied on both stores (App Store subscriptionIntroductoryOffers in the configured territory; Google Play a base-plan offer in the configured region). RevenueCat reads it from the stores automatically. Idempotent on the offer shape; plan reports create/drift/exists.

Field Notes
mode freeTrial / payAsYouGo / payUpFront.
period Offer duration: P3D P1W P2W P1M P2M P3M P6M P1Y.
cycles payAsYouGo only — number of billing periods (default 1).
price Paid modes only; configured-currency major units. Omit for freeTrial.
intro: { mode: freeTrial, period: P1W }
# or an intro price:
intro: { mode: payAsYouGo, period: P1M, cycles: 3, price: 300 }
Field Notes
locale BCP-47, e.g. ja, en-US. Play maps jaja-JP automatically.
name Display name / title. App Store IAP limit: ≤ 30 chars.
description Optional. App Store IAP limit: ≤ 45 chars.

Skipped entirely if REVENUECAT_API_KEY is unset.

Field Notes
project Project name, used to resolve project_id (or set REVENUECAT_PROJECT_ID).
offering Offering lookup_key, e.g. default.
Field Notes
subscriptionGroup Subscription group referenceName, e.g. Sonir Pro.

A complete iap.yaml: two auto-renewable subscriptions and one non-consumable, across four locales. Copy it and swap in your identifiers.

# iapctl desired-state. One file drives App Store Connect, Google Play, RevenueCat.
appName: Sonir
bundleId: app.sonir.app # App Store bundle id (= PRODUCT_BUNDLE_IDENTIFIER)
packageName: app.sonir.app # Google Play package name (= applicationId)
screenshotsDir: ./review-shots # base dir for reviewScreenshot paths (App Store only)
entitlement:
key: pro # the entitlement identifier your app checks
displayName: Pro access
# A single territory/region/currency is provisioned (multi-region is a non-goal).
pricing:
territory: JPN # App Store territory (ISO-3166 alpha-3)
region: JP # Google Play region (ISO-3166 alpha-2)
currency: JPY # ISO-4217
products:
# ── Auto-renewable subscription (default type) ──────────────────────────────
- key: monthly
appStoreId: sonir.pro.monthly # ASC productId
playProductId: sonir_pro_monthly # Play subscription id (lowercase/digits/_/.)
playBasePlanId: monthly # Play base plan id (lowercase/hyphens)
period: P1M # ISO-8601: P1W P1M P2M P3M P6M P1Y
price: 500 # major units, decimals OK (¥500; 4.99 = $4.99)
rcPackage: $rc_monthly # RevenueCat package key
reviewScreenshot: monthly/review.png # App Store review screenshot (one per product)
# App Store IAP limits: name <=30, description <=45.
localizations:
- { locale: ja, name: "Sonir Pro(月額)", description: "全機能を月額で。" }
- { locale: en-US, name: "Sonir Pro (Monthly)", description: "All features, billed monthly." }
- { locale: de-DE, name: "Sonir Pro (Monatlich)", description: "Alle Funktionen, monatlich." }
- { locale: fr-FR, name: "Sonir Pro (mensuel)", description: "Toutes les fonctions, par mois." }
- key: yearly
appStoreId: sonir.pro.yearly
playProductId: sonir_pro_yearly
playBasePlanId: yearly
period: P1Y
price: 5400
rcPackage: $rc_annual
intro: { mode: freeTrial, period: P1W } # 1-week free trial (both stores)
localizations:
- { locale: ja, name: "Sonir Pro(年額)", description: "全機能を年額で。3か月分お得。" }
- { locale: en-US, name: "Sonir Pro (Yearly)", description: "All features, billed yearly." }
- { locale: de-DE, name: "Sonir Pro (Jährlich)", description: "Alle Funktionen, jährlich." }
- { locale: fr-FR, name: "Sonir Pro (annuel)", description: "Toutes les fonctions, par an." }
# ── Non-consumable (one-time). type: nonConsumable drops period/playBasePlanId.
- key: lifetime
type: nonConsumable
appStoreId: sonir.pro.lifetime
playProductId: sonir_pro_lifetime
price: 11000
rcPackage: $rc_lifetime
localizations:
- { locale: ja, name: "Sonir Pro(買い切り)", description: "全機能を一度の購入で永続解放。" }
- { locale: en-US, name: "Sonir Pro (Lifetime)", description: "Unlock all features with one purchase." }
- { locale: de-DE, name: "Sonir Pro (Einmalig)", description: "Alle Funktionen mit einem Kauf." }
- { locale: fr-FR, name: "Sonir Pro (à vie)", description: "Toutes les fonctions en un seul achat." }
revenuecat:
project: Sonir # project NAME → resolves project_id (or set REVENUECAT_PROJECT_ID)
offering: default # offering lookup_key
appstore:
subscriptionGroup: Sonir Pro # subscription group referenceName

By design (one-time human setup): account creation, Paid Apps Agreement / banking / tax, RevenueCat app registration, build upload / Submit-for-Review, and pricing beyond the single configured territory.