--- name: store-subscriptions description: Set up auto-renewable subscriptions on the App Store and Google Play from one config - Apple subscription groups, levels, localizations, equalized prices with overrides and a price CSV, introductory offers, promotional offers, offer codes and custom codes; Play subscriptions with base plans, regional prices, intro and developer-chosen offers; first submission with a version, the disclosure Apple 3.1.2 and Play's subscription policy require, Terms of Use (EULA) links, price changes and the catalog parity report. Use when the user sells subscriptions, adds a free trial, changes subscription prices, or gets a 3.1.2 / subscription policy rejection. --- # Subscriptions on both stores CLI: `storebound apple subscriptions`, `storebound play subscriptions` (both `--dry` first; they print the plan and ask before writing), `storebound catalog diff` (read-only parity of the whole catalog), `storebound validate`. Config: `subscriptions: [{ name, listings, subscriptions: [{ id, period, level, usd, overrides, listings, intro, offers, offerCodes, reviewScreenshot, basePlanId, gracePeriod, platforms }] }]`, `app.termsUrl`. ## Model - **Apple**: a subscription group per product line (people hold one subscription per group); `level` 1 = highest service (upgrades and downgrades follow it). Prices: the USA price point for `usd`, its equalizations for every territory, then `overrides` and rows from `--csv store/prices.csv` (same CSV as `storebound prices`, rows with a future `start_date` become scheduled price changes). `preserveCurrentPrice` is always true: existing subscribers keep their price; raising it for them is a separate, consent-bound step in App Store Connect. - **Google Play**: no groups. Each entry is a Play subscription with one auto-renewing base plan (`basePlanId` default from the period: monthly, yearly, ...), prices from `convertRegionPrices` + overrides + CSV. A base plan price change applies to new subscribers; existing ones keep their price until you run a price migration in the Console. - **Intro offer** (`intro`): free trial, pay as you go (`periods` at `usd`), or pay up front. Apple: per territory, first-time subscribers of the group. Play: an offer for people who never had this subscription (pay as you go is a relative discount, so it follows every regional price). - **Promotional offers** (`offers`, Apple + Play): Apple promotional offers (your server signs them at purchase time); Play offers with an offer tag and no acquisition targeting (your app decides who sees them). - **Offer codes** (`offerCodes`, Apple): a campaign (eligibility NEW / EXISTING / EXPIRED, replace or stack with the intro offer). Custom codes are created only with `--codes` from a terminal that confirms (anyone with the code can redeem it). One-time-use codes: the owner generates them in App Store Connect. **Play promo codes have no API**: Play Console > Monetize > Promo codes. ## Steps 1. Prerequisites: Apple Paid Applications agreement, banking and tax; Play payments profile and a build with the billing library on a track. 2. `storebound check` (limits: Apple name 30 / description 45; Play description 200, up to 4 benefits). 3. `storebound apple subscriptions --dry` and `storebound play subscriptions --dry`; show the plan, then run them yourself (`--yes`): new subscriptions, first prices, listings, base plans and offers are written. A price change of an existing subscription is a live price and `--yes` never applies it: the run writes everything else, prints `price change on ( -> ) needs the owner: re-run with --allow-price-changes` and exits 3. After the owner's yes in chat for that diff, run it again with `--yes --allow-price-changes`. Flows never pass that flag. 4. Review screenshot of the paywall per subscription (`reviewScreenshot`), uploaded by `apple subscriptions`. 5. **First subscriptions go with an app version** (and a new group with at least one of its subscriptions): `storebound apple iap-submit --with-version --dry` plans one review submission with the app version, the subscription versions and the group version; the owner runs it without `--dry` (it asks, and submitting it submits the app), or adds `--no-submit` and presses "Submit for Review" in App Store Connect. Details and the exact limits: store-iap-setup skill, step 3. 5b. **Win-back offers** for lapsed subscribers (`winBack` on a subscription, `storebound apple win-back`) once the subscription is approved: app-store-promotion skill. 6. `storebound validate` (states, localizations, group names, review screenshots, active Play base plans, terms URL) and `storebound catalog diff` (both stores against the config, prices per region). ## Disclosure (review checks it) - Purchase screen: plan name, length, **full renewal price per period as the most prominent price**, what is included, trial length and what is charged after it, how to cancel, Restore Purchases, links to the **Terms of Use** and the **Privacy Policy** (Apple 3.1.2 and "Clearly describing subscriptions", https://developer.apple.com/app-store/subscriptions/; Google Play subscriptions policy, https://support.google.com/googleplay/android-developer/answer/9900533). - Metadata: the Terms of Use link in the App Store description, or a custom EULA in App Information > License Agreement; the privacy policy URL field (`storebound apple listing`). `validate` warns when a description has no Terms link. 3.1.2(a): a subscription must give ongoing value and last at least 7 days. - Review notes: where the paywall is, that the demo account can buy in the sandbox (`review-access`). - Remote paywalls (RevenueCat Paywalls, Superwall, Adapty, Qonversion, Purchasely, Apphud) or flags: say in the review notes that paywall designs / prices shown change remotely (2.3.1, `scan` warns; store-pitfalls 74); moving features behind the subscription after review needs a new review and a description that discloses it. ## Gotchas - A product id, a billing period or a subscription's group cannot change; make a new id. - Apple applies one introductory offer per customer per group; offers cannot be edited, only replaced. - Account deletion does not cancel a subscription: say so (`account-deletion`). - Unverified (no live account during development): free promotional offers and offer codes are sent with territories but no price point; check the first run in App Store Connect.