Skip to main content

Subscriptions

List and inspect​

ascelerate sub groups <bundle-id>
ascelerate sub list <bundle-id>
ascelerate sub info <bundle-id> <product-id>

All three accept --json for machine-readable output (conventions); info reports the missing-prices warning as a hasPricing boolean.

Create, update, and delete subscriptions​

ascelerate sub create <bundle-id> --name "Monthly" --product-id <product-id> --period ONE_MONTH --group-id <group-id>
ascelerate sub update <bundle-id> <product-id> --name "Monthly Plan"
ascelerate sub delete <bundle-id> <product-id>

Subscription groups​

ascelerate sub create-group <bundle-id> --name "Premium"
ascelerate sub update-group <bundle-id> --name "Premium Plus"
ascelerate sub delete-group <bundle-id>

Submit for review​

ascelerate sub submit <bundle-id> <product-id>

A product can be submitted whenever it has a pending version: any version in Prepare for Submission, Ready for Review, or a rejected state. This includes approved products with edits since their last approval. Without a pending version the command stops before making any request. sub info shows the pending version when there is one.

Subscription localizations​

ascelerate sub localizations view <bundle-id> <product-id>
ascelerate sub localizations export <bundle-id> <product-id>
ascelerate sub localizations import <bundle-id> <product-id> --file sub-de.json

Group localizations​

ascelerate sub group-localizations view <bundle-id>
ascelerate sub group-localizations export <bundle-id>
ascelerate sub group-localizations import <bundle-id> --file group-de.json

The import commands create missing locales automatically with confirmation, so you can add new languages without visiting App Store Connect.

Pricing​

Subscription pricing is per-territory. There is no auto-equalize concept like IAPs have — every territory you want to price needs its own record. The CLI either sets a single territory or fans the price out across all territories using Apple's local-currency tier equivalents.

# Show current per-territory prices (warns if none)
ascelerate sub pricing show <bundle-id> <product-id>

# Show them as JSON (price, currency, start date, and preserved flag per territory)
ascelerate sub pricing show <bundle-id> <product-id> --json

# List available tiers for a territory
ascelerate sub pricing tiers <bundle-id> <product-id> --territory USA

# Set the price for a single territory
ascelerate sub pricing set <bundle-id> <product-id> --price 4.99 --territory USA

# Fan out a price across all territories (one POST per territory)
ascelerate sub pricing set <bundle-id> <product-id> --price 4.99 --equalize-all-territories

Price changes and existing subscribers​

Apple treats price changes differently for existing subscribers depending on the direction. sub pricing set fetches the current price for each affected territory, classifies the change, and enforces the right behavior:

  • Decrease: existing subscribers automatically move to the lower price. Interactive runs prompt with a warning. In --yes mode, you must add --confirm-decrease to acknowledge the revenue impact — plain --yes is not enough.
  • Increase: you must explicitly choose how to handle existing subscribers. The command errors unless one of the following is set:
    • --preserve-current — grandfather existing subscribers at their old price
    • --no-preserve-current — push the new price to existing subscribers (after Apple's notification period)
  • New territory (no existing price): no existing subscribers; flags optional.
  • Unchanged: skipped silently.

The same rules apply aggregated across --equalize-all-territories. If any territory in the fan-out is an increase, the preserve flag is required for all of them. If any is a decrease in --yes mode, --confirm-decrease is required.

# Standard global price raise: $4.99 → $9.99 across all territories,
# grandfather existing subscribers at the old price
ascelerate sub pricing set myapp com.example.monthly \
--price 9.99 --territory USA --equalize-all-territories \
--preserve-current

Copy prices between products​

# Export every territory's current price to JSON
ascelerate sub pricing export <bundle-id> <product-id> --output prices.json

# Apply it to another subscription — in the same app or a different one
ascelerate sub pricing import <other-bundle-id> <other-product-id> --file prices.json

The file stores customer prices keyed by territory code (preserved/grandfathered and future-scheduled prices are excluded from the export). On import, each price is matched against the target subscription's own tiers by customer price, so the same file works across products and apps. Import only touches territories listed in the file, skips ones already at the listed price, and enforces the same increase/decrease safety rules as set — including --preserve-current/--no-preserve-current and --confirm-decrease.

A price that isn't one of the target's tiers fails the import, which lists the nearest tiers; with --snap, each such price takes the nearest tier instead (the cheaper when two are as close), and the snapped prices are listed before you confirm.

Transient App Store Connect errors (HTTP 429/5xx) during multi-territory writes are retried automatically — first in place with backoff, then in a second sweep at the end of the run. Territories that still fail are listed in the final report and the command exits non-zero; re-running the same command retries just those, since already-updated territories are skipped as unchanged.

Availability​

Each subscription has its own territory availability, independent of the app's. By default a subscription inherits its app's territories; once you call sub availability with changes, the subscription has an explicit list.

# View current per-subscription territories
ascelerate sub availability <bundle-id> <product-id>

# Edit the territory list (each edit replaces the full list)
ascelerate sub availability <bundle-id> <product-id> --add CHN,RUS
ascelerate sub availability <bundle-id> <product-id> --remove ITA
ascelerate sub availability <bundle-id> <product-id> --available-in-new-territories true
ascelerate sub availability <bundle-id> <product-id> --plan monthly --add DEU,FRA

Annual subscriptions can also be sold as Monthly with 12-Month Commitment (billed monthly; not offered in the United States and Singapore). That billing plan has its own territory list: add --plan monthly to view or edit it. Without --plan, the command manages the regular upfront plan.

Introductory offers​

Introductory offers target new subscribers — free trials and intro discounts.

ascelerate sub intro-offer list <bundle-id> <product-id>

# Free trial (no price needed; --periods + --duration set the trial length)
ascelerate sub intro-offer create <bundle-id> <product-id> \
--mode FREE_TRIAL --duration ONE_WEEK --periods 1 --territories all

# Pay-as-you-go discount (3 months at $0.99/mo, scoped to USA)
ascelerate sub intro-offer create <bundle-id> <product-id> \
--mode PAY_AS_YOU_GO --duration ONE_MONTH --periods 3 \
--territories USA --price 0.99

# Update only the end date (other fields require delete + recreate)
ascelerate sub intro-offer update <bundle-id> <product-id> <offer-id> --end-date 2026-12-31

ascelerate sub intro-offer delete <bundle-id> <product-id> <offer-id>

Modes: FREE_TRIAL, PAY_AS_YOU_GO, PAY_UP_FRONT. --territories is required: territory codes such as USA,TUR, or all. Apple keeps one offer per territory, and ascelerate creates them in a single request, skipping territories where the offer would overlap an existing one or that already have a future offer. A paid offer's --price is in the first territory's currency; the other territories get Apple's comparable price. --price is required for the two paid modes and forbidden for FREE_TRIAL.

Promotional offers​

Promotional offers target existing subscribers — typically used for in-app upsell flows. The offer code (the --code value) must be embedded in a signed payload your server generates at runtime before clients can redeem it.

ascelerate sub promo-offer list <bundle-id> <product-id>
ascelerate sub promo-offer info <bundle-id> <product-id> <offer-id>

# Create — same single-territory or --equalize-all-territories pattern
ascelerate sub promo-offer create <bundle-id> <product-id> \
--name "Loyalty 50%" --code LOYALTY50 \
--mode PAY_AS_YOU_GO --duration ONE_MONTH --periods 3 \
--price 4.99 --territory USA --equalize-all-territories

# Update only prices (other fields require delete + recreate)
ascelerate sub promo-offer update <bundle-id> <product-id> <offer-id> \
--price 5.99 --equalize-all-territories

ascelerate sub promo-offer delete <bundle-id> <product-id> <offer-id>

Retention messages and offers​

When a subscriber goes to cancel in their App Store subscription settings, the App Store can show them a retention message: a header and body in their language, an optional image, and offers to stay. A message belongs to the app and goes through App Review; each subscription shows one message, with any of its retention offers.

ascelerate sub retention-message list <bundle-id>
ascelerate sub retention-message info <bundle-id> "Stay with us"
ascelerate sub retention-message create <bundle-id> --name "Stay with us" \
--locale en-US --header "Before you go" --body "Your plan gets new features every month."
ascelerate sub retention-message localizations set <bundle-id> "Stay with us" \
--locale de-DE --header "Bevor Sie gehen" --body "Ihr Abo erhält jeden Monat neue Funktionen."
ascelerate sub retention-message image upload <bundle-id> "Stay with us" ./retention.png
ascelerate sub retention-message submit <bundle-id> "Stay with us"
ascelerate sub retention-message new-version <bundle-id> "Stay with us"

# Retention offers, then the message and offers a subscription shows
ascelerate sub retention-offer create <bundle-id> <product-id> \
--name "Half off" --offer-id stay.half --mode PAY_AS_YOU_GO --duration ONE_MONTH --periods 3 \
--paid-months 6 --wait-months 12 --price 4.99 --territories all
ascelerate sub retention-offer update <bundle-id> <product-id> stay.half --paid-months 3
ascelerate sub retention-message assign <bundle-id> <product-id> "Stay with us" --offers stay.half
  • Text and image: the header takes 66 characters and the body 144. The image is 16:9 without transparency: 3840×2160 (PNG or JPEG) or 5244×2950 (PNG), one per version.
  • Versions: a message has one unreleased version at a time. Once App Review has it, new-version starts the next. submit adds the message to the draft submission; send it with apps review submit.
  • Who gets an offer: subscribers who have paid for at least --paid-months (1–24, 36, 48 or 60) and, with --wait-months, whose last offer was 2–24 months ago. Only these two change after an offer is created, and a wait can't be removed once set.
  • Prices: a paid offer's --price is in the first of --territories; the others get Apple's comparable price. A free trial takes none. --plan monthly targets the monthly billing plan of an annual subscription (upfront by default).

Offer codes​

Offer codes are redeemable codes for subscriptions, with two flavors:

  • One-time-use codes: Apple generates N unique codes in a batch (asynchronously). Each can only be redeemed once.
  • Custom codes: developer-supplied string redeemable N times.
ascelerate sub offer-code list <bundle-id> <product-id>
ascelerate sub offer-code info <bundle-id> <product-id> <offer-code-id>

# Create an offer code (with all the offer-style attributes)
ascelerate sub offer-code create <bundle-id> <product-id> \
--name "Launch Free Month" \
--eligibility NEW \
--offer-eligibility STACK_WITH_INTRO_OFFERS \
--mode FREE_TRIAL --duration ONE_MONTH --periods 1 \
--price 0 --territory USA --equalize-all-territories

ascelerate sub offer-code toggle <bundle-id> <product-id> <offer-code-id> --active true

# Generate one-time-use codes (async)
ascelerate sub offer-code gen-codes <bundle-id> <product-id> <offer-code-id> \
--count 500 --expires 2026-12-31

# Fetch the actual code values once generation completes
ascelerate sub offer-code view-codes <one-time-use-batch-id> --output codes.txt

# Add a developer-supplied custom code
ascelerate sub offer-code add-custom-codes <bundle-id> <product-id> <offer-code-id> \
--code SUBPROMO --count 1000 --expires 2026-12-31

Customer eligibilities for subscription offer codes: NEW, EXISTING, EXPIRED. Offer eligibility: STACK_WITH_INTRO_OFFERS or REPLACE_INTRO_OFFERS.

Submit subscription group for review​

Subscription groups are reviewed alongside the next app version. sub submit-group is the group-level mirror of sub submit.

ascelerate sub submit-group <bundle-id>

The group needs a pending version of its own (for example edited group localizations); otherwise the command stops before making any request.

Promotional images​

Upload promotional artwork shown alongside the subscription in the App Store.

ascelerate sub images list <bundle-id> <product-id>
ascelerate sub images upload <bundle-id> <product-id> ./hero.png
ascelerate sub images delete <bundle-id> <product-id> <image-id>

App Review screenshot​

Each subscription can have at most one App Review screenshot. Uploading replaces any existing one.

ascelerate sub review-screenshot view <bundle-id> <product-id>
ascelerate sub review-screenshot upload <bundle-id> <product-id> ./review.png
ascelerate sub review-screenshot delete <bundle-id> <product-id>

Image and screenshot uploads use Apple's 3-step file upload flow (reserve → PUT chunks → commit with MD5). The CLI handles all three steps in a single upload call.

Win-back offers​

Win-back offers are for people whose subscription ended: the App Store offers them a discount or free time to come back, from a start date to an optional end date. Only an approved subscription takes them.

ascelerate sub win-back-offer list <bundle-id> <product-id>
ascelerate sub win-back-offer info <bundle-id> <product-id> comeback.half
ascelerate sub win-back-offer create <bundle-id> <product-id> \
--name "Come back" --offer-id comeback.half --mode PAY_AS_YOU_GO --duration ONE_MONTH --periods 3 \
--since-months 3-12 --paid-months 6 --end-date 2027-01-31 --priority high --promote \
--price 4.99 --territories all
ascelerate sub win-back-offer update <bundle-id> <product-id> comeback.half --since-months 2-24 --end-date 2027-03-31
ascelerate sub win-back-offer delete <bundle-id> <product-id> comeback.half
  • Who gets one: people whose subscription ended --since-months ago (a range, from 1–23 to 2–24 months), who had paid for at least --paid-months (1–24, 36, 48 or 60) and, with --wait-months, whose last offer was 2–24 months ago.
  • Dates: it starts on --start-date (tomorrow at the earliest, and by default) and, with --end-date, ends at least 3 days later.
  • On the App Store: --priority high puts it before other offers; --promote lets the App Store promote it with assets Apple generates.
  • Prices: as for retention offers, --price is in the first of --territories and the others get Apple's comparable price; a free trial takes none. A pay-as-you-go offer lasts the subscription's own period (ONE_YEAR for an annual one).
  • Changes: the eligibility, dates, priority and promotion can change; for anything else, delete the offer and create it again.