mcpField
A
asc-subscriptions

asc-subscriptions

github.com/tddworks营销与增长5101 次安装5 周前更新
代码仓库

关于 asc-subscriptions

使用 `asc` CLI 管理 App Store Connect 自动续订订阅的技能,涵盖订阅组、定价、本地化、优惠、兑换码和审核截图。

主要功能

  1. 01创建和管理订阅组及层级
  2. 02配置各地区的订阅价格
  3. 03管理本地化内容和订阅优惠
  4. 04创建并停用优惠码
  5. 05上传和管理审核截图

适用场景

  1. 01在 App Store Connect 配置订阅产品
  2. 02调整特定地区的价格
  3. 03创建入门优惠或挽回优惠
  4. 04生成并获取优惠码批次

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tddworks/asc-cli-skills --skill asc-subscriptions

安装后在 Claude Code 中输入/asc-subscriptions确认已加载。

详细介绍

asc 订阅

通过 asc CLI 管理自动续期订阅组、层级、本地化、定价、优惠和审核素材。

订阅组

asc subscription-groups list   --app-id <APP_ID>
asc subscription-groups create --app-id <APP_ID> --reference-name "Premium Plans"
asc subscription-groups update --group-id <GROUP_ID> --reference-name "Premium"
asc subscription-groups delete --group-id <GROUP_ID>
组本地化(每个地区的显示名称 + 自定 App 名称)
asc subscription-group-localizations list   --group-id <GROUP_ID>
asc subscription-group-localizations create --group-id <GROUP_ID> --locale en-US --name "Premium Plans" [--custom-app-name "Premium App"]
asc subscription-group-localizations update --localization-id <LOC> [--name "..."] [--custom-app-name "..."]
asc subscription-group-localizations delete --localization-id <LOC>

订阅(生命周期)

asc subscriptions list   --group-id <GROUP_ID>
asc subscriptions create --group-id <GROUP_ID> --name "Monthly Premium" \
  --product-id "com.app.monthly" --period ONE_MONTH \
  [--family-sharable] [--group-level 1]
asc subscriptions update --subscription-id <SUB_ID> \
  [--name "..."] [--family-sharable | --not-family-sharable] [--group-level <n>] [--review-note "..."]
asc subscriptions delete --subscription-id <SUB_ID>
asc subscriptions submit   --subscription-id <SUB_ID>          # state must be READY_TO_SUBMIT
asc subscriptions unsubmit --submission-id <SUBMISSION_ID>     # withdraw from review (manual Request<Void>)
asc subscriptions versions list --subscription-id <SUB_ID>     # review versions + state (addToSubmission when submittable)
asc subscription-groups versions list --group-id <GROUP_ID>    # a group's first subscription needs the group version too

首次提交的订阅? Apple 只会将其与 App 版本(及其所属组的版本)一同审核,因此 asc subscriptions submit 对此类订阅会失败。请与 App 一同提交:asc versions submit --version-id <VERSION_ID> --with-products(先使用 --dry-run 运行)。请参阅 submit-with-products.md。

--period ∈ ONE_WEEK、ONE_MONTH、TWO_MONTHS、THREE_MONTHS、SIX_MONTHS、ONE_YEAR。

订阅定价(按地区,包含 proceedsYear2)

asc subscriptions price-points list --subscription-id <SUB_ID> [--territory USA]

asc subscriptions prices set \
  --subscription-id <SUB_ID> \
  --territory USA \
  --price-point-id <PP> \
  [--start-date 2026-06-01] \
  [--preserve-current-price]

订阅按地区定价(没有基础地区)。每个价格点都包含 customerPrice、proceeds 和 proceedsYear2。

订阅本地化

asc subscription-localizations list   --subscription-id <SUB_ID>
asc subscription-localizations create --subscription-id <SUB_ID> --locale en-US --name "Monthly Premium" [--description "..."]
asc subscription-localizations update --localization-id <LOC> [--name "..."] [--description "..."]
asc subscription-localizations delete --localization-id <LOC>

入门优惠

asc subscription-offers list   --subscription-id <SUB_ID>

# Free trial
asc subscription-offers create --subscription-id <SUB_ID> \
  --duration ONE_MONTH --mode FREE_TRIAL --periods 1

# Paid intro offer — price-point-id required for PAY_AS_YOU_GO / PAY_UP_FRONT
asc subscription-offers create --subscription-id <SUB_ID> \
  --duration THREE_MONTHS --mode PAY_AS_YOU_GO --periods 3 \
  --territory USA --price-point-id <PP>

asc subscription-offers delete --offer-id <OFFER_ID>

--duration ∈ THREE_DAYS、ONE_WEEK、TWO_WEEKS、ONE_MONTH、TWO_MONTHS、THREE_MONTHS、SIX_MONTHS、ONE_YEAR。--mode ∈ FREE_TRIAL、PAY_AS_YOU_GO、PAY_UP_FRONT。

促销优惠(App 内优惠,按地区定价)

asc subscription-promotional-offers list   --subscription-id <SUB_ID>

asc subscription-promotional-offers create --subscription-id <SUB_ID> \
  --name "Loyalty25" --offer-code loyalty25 \
  --duration THREE_MONTHS --mode PAY_AS_YOU_GO --periods 3 \
  --price USA=spp-1 --price GBR=spp-2          # repeatable: TERRITORY=PRICE_POINT_ID

asc subscription-promotional-offers delete       --offer-id <OFFER_ID>
asc subscription-promotional-offers prices list  --offer-id <OFFER_ID>

--price 使用 ${newPromoOfferPrice-N} 内联编码,其中 N 为从 1 开始的本地 ID(与 ASC 网页 UI 的结构一致)。

挽回优惠(已流失的订阅者)

asc win-back-offers list --subscription-id <SUB_ID>

asc win-back-offers create --subscription-id <SUB_ID> \
  --reference-name "Lapsed Q4" --offer-id lapsedQ4 \
  --duration ONE_MONTH --mode FREE_TRIAL --periods 1 \
  --paid-months 3 --since-min 1 --since-max 6 --wait-months 2 \
  --start-date 2026-04-01 --end-date 2026-12-31 \
  --priority HIGH --promotion-intent USE_AUTO_GENERATED_ASSETS \
  [--price USA=spp-1 ...]

asc win-back-offers update --offer-id <OFFER_ID> \
  [--start-date YYYY-MM-DD] [--end-date YYYY-MM-DD] \
  [--priority HIGH|NORMAL] [--promotion-intent NOT_PROMOTED|USE_AUTO_GENERATED_ASSETS] \
  [--paid-months <n>] [--since-min <n>] [--since-max <n>] [--wait-months <n>]

asc win-back-offers delete       --offer-id <OFFER_ID>
asc win-back-offers prices list  --offer-id <OFFER_ID>

资格模型:--paid-months(要求作为付费订阅者的月数)、--since-min..--since-max(距上次订阅的月数范围)、--wait-months(向同一客户展示优惠之间的间隔)。由于生成的 SDK 中 WinBackOfferPriceInlineCreate 缺少 territory 和 subscriptionPricePoint 关系,挽回优惠的创建请求体需要手动编码。

订阅优惠码(3 级层级结构)

第 1 级 — 优惠码
asc subscription-offer-codes list   --subscription-id <SUB_ID>

asc subscription-offer-codes create --subscription-id <SUB_ID> \
  --name "SUMMER2026" \
  --duration ONE_MONTH --mode FREE_TRIAL --periods 1 \
  --eligibility NEW --eligibility LAPSED \
  --offer-eligibility STACKABLE \
  --price USA=spp-usa --price JPN=spp-jpn \
  --free-territory BRA \
  [--auto-renew true|false]

asc subscription-offer-codes update       --offer-code-id <OC> --active false
asc subscription-offer-codes prices list  --offer-code-id <OC>   # per-territory pricing (read-only)

价格仅在创建时设置一次(之后 prices 为只读;详情请参阅 IAP 技能中的说明)。使用 --auto-renew false 可创建不续期的一次性优惠;此时 ASC 仅接受 --mode FREE_TRIAL。

--eligibility(可重复)∈ NEW、LAPSED、WIN_BACK、PAID_SUBSCRIBER。--offer-eligibility ∈ STACKABLE、INTRODUCTORY、SUBSCRIPTION_OFFER。

第 2 级 — 自定义可兑换码
asc subscription-offer-code-custom-codes list   --offer-code-id <OC>
asc subscription-offer-code-custom-codes create --offer-code-id <OC> \
  --custom-code "SUMMER2026" --number-of-codes 1000 [--expiration-date 2026-12-31]
asc subscription-offer-code-custom-codes update --custom-code-id <CC> --active false
第 3 级 — 一次性使用代码批次
asc subscription-offer-code-one-time-codes list   --offer-code-id <OC>
asc subscription-offer-code-one-time-codes create --offer-code-id <OC> \
  --number-of-codes 5000 --expiration-date 2026-12-31 [--environment production|sandbox]
asc subscription-offer-code-one-time-codes update --one-time-code-id <OTC> --active false

# Download the CSV of redemption codes (raw String — not JSON):
asc subscription-offer-code-one-time-codes values --one-time-code-id <OTC>

--environment 默认为 production。Sandbox 批次使用 Sandbox 测试账户兑换(上限约为每季度 10,000 个);production 批次使用正式账户兑换(上限约为每季度 150,000 个)。每个 SubscriptionOfferCode 都会通过 productionCodeCount / sandboxCodeCount 报告两种环境下的使用情况,每个一次性使用代码行都带有 environment,可用于筛选。

REST 等效项:

GET    /api/v1/subscription-offer-codes/{offerCodeId}/one-time-codes
POST   /api/v1/subscription-offer-codes/{offerCodeId}/one-time-codes   # body: {numberOfCodes, expirationDate, environment?}
PATCH  /api/v1/subscription-offer-code-one-time-codes/{oneTimeCodeId}  # body: {isActive: false}

订阅审核屏幕截图(单例)

asc subscription-review-screenshot get    --subscription-id <SUB_ID>          # empty data:[] when none
asc subscription-review-screenshot upload --subscription-id <SUB_ID> --file ./review.png
asc subscription-review-screenshot delete --screenshot-id <RS>                # suppressed while AWAITING_UPLOAD

上传使用 ASC 的预留 → 分块上传 → 使用 MD5 提交协议。

CAEOAS 支持的操作

SubscriptionGroup 提供:

{
  "affordances": {
    "createLocalization":  "asc subscription-group-localizations create --group-id <ID> --locale en-US --name <name>",
    "createSubscription":  "asc subscriptions create --group-id <ID> --name <name> --product-id <id> --period ONE_MONTH",
    "delete":              "asc subscription-groups delete --group-id <ID>",
    "listLocalizations":   "asc subscription-group-localizations list --group-id <ID>",
    "listSubscriptions":   "asc subscriptions list --group-id <ID>",
    "update":              "asc subscription-groups update --group-id <ID> --reference-name <name>"
  }
}

Subscription 除现有键之外,还提供:

{
  "createPromotionalOffer": "asc subscription-promotional-offers create --subscription-id <ID> ...",
  "delete":                 "asc subscriptions delete --subscription-id <ID>",
  "getReviewScreenshot":    "asc subscription-review-screenshot get --subscription-id <ID>",
  "listPromotionalOffers":  "asc subscription-promotional-offers list --subscription-id <ID>",
  "listVersions":           "asc subscriptions versions list --subscription-id <ID>",
  "listWinBackOffers":      "asc win-back-offers list --subscription-id <ID>",
  "update":                 "asc subscriptions update --subscription-id <ID> --name <name>"
}

仅当 state == READY_TO_SUBMIT 时才能执行 submit。SubscriptionSubmission 提供 unsubmit。SubscriptionLocalization 提供 update + delete。SubscriptionGroupLocalization 提供 update + delete。仅当 territory != nil 时,SubscriptionPricePoint 才提供 setPrice。SubscriptionPromotionalOffer 提供 delete + listPrices。WinBackOffer 提供 update + delete + listPrices。仅当 assetState.isComplete || hasFailed 时,SubscriptionReviewScreenshot 才提供 delete。仅当 isActive == true 时,*OfferCode* 自定义码和一次性码才提供 deactivate。

解析 App ID

请参阅 project-context.md — 在询问用户或运行 asc apps list 之前,先检查 .asc/project.json。

典型工作流

APP_ID=$(cat .asc/project.json 2>/dev/null | jq -r '.appId // empty')

# 1. Group + tier + group-localization
GROUP_ID=$(asc subscription-groups create --app-id "$APP_ID" --reference-name "Premium" \
  | jq -r '.data[0].id')
asc subscription-group-localizations create --group-id "$GROUP_ID" --locale en-US \
  --name "Premium Plans" --custom-app-name "Premium App"

SUB_ID=$(asc subscriptions create --group-id "$GROUP_ID" --name "Monthly Premium" \
  --product-id "com.app.monthly" --period ONE_MONTH | jq -r '.data[0].id')
asc subscription-localizations create --subscription-id "$SUB_ID" --locale en-US \
  --name "Monthly Premium" --description "Unlock everything"

# 2. Per-territory pricing
USA_PP=$(asc subscriptions price-points list --subscription-id "$SUB_ID" --territory USA \
  | jq -r '.data[] | select(.customerPrice == "9.99") | .id')
asc subscriptions prices set --subscription-id "$SUB_ID" --territory USA --price-point-id "$USA_PP"

# 3. Review screenshot + submit (first-time subscription: with the app version instead,
#    `asc versions submit --version-id "$VERSION_ID" --with-products`)
asc subscription-review-screenshot upload --subscription-id "$SUB_ID" --file ./review.png
asc subscriptions submit --subscription-id "$SUB_ID"

# 4. Promotional offer with per-territory pricing
asc subscription-promotional-offers create --subscription-id "$SUB_ID" \
  --name "Loyalty25" --offer-code loyalty25 \
  --duration THREE_MONTHS --mode PAY_AS_YOU_GO --periods 3 \
  --price USA=$USA_PP

# 5. Win-back campaign
asc win-back-offers create --subscription-id "$SUB_ID" \
  --reference-name "Lapsed Q4" --offer-id lapsedQ4 \
  --duration ONE_MONTH --mode FREE_TRIAL --periods 1 \
  --paid-months 3 --since-min 1 --since-max 6 --wait-months 2 \
  --start-date 2026-04-01 --end-date 2026-12-31 \
  --priority HIGH --promotion-intent USE_AUTO_GENERATED_ASSETS

# 6. Offer code + one-time redemption batch
OC_ID=$(asc subscription-offer-codes create --subscription-id "$SUB_ID" \
  --name "SUMMER2026" --duration ONE_MONTH --mode FREE_TRIAL --periods 1 \
  --eligibility NEW --eligibility LAPSED --offer-eligibility STACKABLE \
  | jq -r '.data[0].id')
asc subscription-offer-code-one-time-codes create --offer-code-id "$OC_ID" \
  --number-of-codes 5000 --expiration-date 2026-12-31
# Distribute the codes:
asc subscription-offer-code-one-time-codes values --one-time-code-id <OTC_ID> > codes.csv

状态语义

SubscriptionState 提供语义布尔值:

布尔值状态为以下值时为 True
isEditableMISSING_METADATA、REJECTED、DEVELOPER_ACTION_NEEDED
isPendingReviewWAITING_FOR_REVIEW、IN_REVIEW
isApproved / isLiveAPPROVED

SubscriptionCustomerEligibility ∈ NEW、LAPSED、WIN_BACK、PAID_SUBSCRIBER。 SubscriptionOfferEligibility ∈ STACKABLE、INTRODUCTORY、SUBSCRIPTION_OFFER。 WinBackOfferPriority ∈ HIGH、NORMAL。WinBackOfferPromotionIntent ∈ NOT_PROMOTED、USE_AUTO_GENERATED_ASSETS。

SubscriptionReviewScreenshot.AssetState 提供 isComplete 和 hasFailed。

JSON 输出中会省略值为 nil 的可选字段。PATCH 响应(更新命令)会返回父级 ID 为 "" 的资源,因为 ASC 的 PATCH 响应不包含父级 ID——如果需要父级,请通过 list 重新获取。

参考

完整的领域模型和 REST 详情,请参阅 docs/features/iap-subscriptions.md 和 iap-subscriptions/ 子文档(生命周期、定价、优惠码、群组本地化、促销优惠、挽回优惠、审核资源)。

评论

支持 Markdown