用途
该技能面向通过 Shopify 原生订阅功能销售订阅制商品的店铺,将活跃订阅合约聚合为财务团队常用的 SaaS 风格指标:月度经常性收入(MRR)、年度经常性收入(ARR)、活跃订阅者数、每订阅者平均收入(ARPU)以及滚动流失率。技能为只读,不执行任何变更操作。
前提条件
- 已认证的 Shopify CLI 会话:
shopify store auth --store <domain> --scopes read_own_subscription_contracts - API 权限范围:
read_own_subscription_contracts
参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| store | string | 是 | — | 店铺域名(例如 mystore.myshopify.com) |
| churn_window_days | integer | 否 | 30 | 流失率计算的滚动窗口(取消数 / 窗口起始订阅者数) |
| as_of | string | 否 | 今天(UTC) | “截至”快照标签的 ISO 日期 |
| include_paused | bool | 否 | false | 是否将 PAUSED 合约视为活跃经常性收入 |
| format | string | 否 | human | 输出格式:human 或 json |
安全性
只读技能,不执行任何变更。仅当店铺销售订阅商品时才有意义。如果 subscriptionContracts 返回 0 个合约,报告以 $0 MRR 退出——这是正确答案,不是错误。
经常性收入模型
每个订阅合约对 MRR 的贡献取决于其计费周期:
billing_amount = sum(line.currentPrice × line.quantity) for each line in contract
mrr_contribution =
billing_amount if interval = MONTH and intervalCount = 1
billing_amount / intervalCount if interval = MONTH (e.g., every 3 months → /3)
billing_amount × 4.345 if interval = WEEK (avg weeks per month)
billing_amount × 4.345 / intervalCount if interval = WEEK with intervalCount > 1
billing_amount / 12 if interval = YEAR
billing_amount × 30 / intervalCount if interval = DAY
聚合项:
- MRR = 所有 ACTIVE(以及 include_paused 时的 PAUSED)合约的 mrr_contribution 之和
- ARR = MRR × 12
- 活跃订阅者 = 唯一 customer.id 计数
- ARPU = MRR / 活跃订阅者
- 流失率(周期)= churn_window_days 内取消的合约数 ÷ 窗口开始时处于活跃状态的合约数
- 净新增订阅者 = 窗口内新合约数 − 窗口内取消合约数
工作流程步骤
- OPERATION: subscriptionContracts — 查询
- 输入:first: 250,选择 id、status、createdAt、updatedAt、nextBillingDate、customer { id, displayName }、currencyCode、billingPolicy { interval, intervalCount }、lines { edges { node { currentPrice { amount, currencyCode }, quantity, productId, variantId, title } } }、分页游标
- 预期输出:所有订阅合约;分页直到 hasNextPage: false
- 按状态对每个合约分类:ACTIVE、PAUSED、CANCELLED、EXPIRED、FAILED
- 使用上述模型为每个活跃(以及按需包含的暂停)合约计算 mrr_contribution
- 聚合 MRR / ARR / 订阅者 / ARPU
- 流失率:统计 updatedAt 在 churn_window_days 内且状态变为 CANCELLED 的取消数;统计在 as_of - churn_window_days 时已存在且为 ACTIVE 的合约数
- 构建按产品细分,便于财务查看哪些订阅 SKU 贡献 MRR
GraphQL 操作
# subscriptionContracts:query — validated against api_version 2025-01
query SubscriptionMRR($after: String) {
subscriptionContracts(first: 250, after: $after) {
edges {
node {
id
status
createdAt
updatedAt
nextBillingDate
currencyCode
customer {
id
displayName
defaultEmailAddress { emailAddress }
}
billingPolicy { interval intervalCount minCycles maxCycles }
deliveryPolicy { interval intervalCount }
lines(first: 50) {
edges {
node {
id
productId
variantId
title
quantity
currentPrice { amount currencyCode }
}
}
}
}
}
pageInfo { hasNextPage endCursor }
}
}
会话跟踪
Claude 必须在每个阶段输出以下内容,这是强制要求。
开始时输出:
╔══════════════════════════════════════════════╗
║ SKILL: Subscription MRR Tracker ║
║ Store: <store domain> ║
║ As of: <YYYY-MM-DD> ║
║ Started: <YYYY-MM-DD HH:MM UTC> ║
╚══════════════════════════════════════════════╝
每步之后输出:
[N/TOTAL] <QUERY|MUTATION> <OperationName>
→ Params: <brief summary of key inputs>
→ Result: <count or outcome>
完成时输出:
format: human(默认):
══════════════════════════════════════════════
SUBSCRIPTION MRR REPORT (as of <date>)
Active contracts: <n>
Paused contracts: <n>
Cancelled (last <n>d): <n>
─────────────────────────────
MRR: $<amount>
ARR: $<amount>
Active subscribers: <n>
ARPU: $<amount>
Churn rate (<n>d): <pct>%
Net new (<n>d): <n>
Top subscription products by MRR:
"<title>" Subs: <n> MRR: $<n>
"<title>" Subs: <n> MRR: $<n>
Output: subscription_mrr_<date>.csv
══════════════════════════════════════════════
format: json:
{
"skill": "subscription-mrr-tracker",
"store": "<domain>",
"as_of": "<YYYY-MM-DD>",
"active_contracts": 0,
"paused_contracts": 0,
"cancelled_in_window": 0,
"mrr": 0,
"arr": 0,
"active_subscribers": 0,
"arpu": 0,
"churn_rate_pct": 0,
"net_new": 0,
"currency": "USD",
"by_product": [],
"output_file": "subscription_mrr_<date>.csv"
}
输出格式
CSV 文件 subscription_mrr_<YYYY-MM-DD>.csv,列包括:
contract_id, status, customer_id, customer_email, created_at, next_billing_date, interval, interval_count, billing_amount, mrr_contribution, currency, product_titles
错误处理
| 错误 | 原因 | 恢复方式 |
|---|---|---|
| THROTTLED | 超过 API 速率限制 | 等待 2 秒,最多重试 3 次 |
| subscriptionContracts 为空 | 店铺没有订阅商品 | 干净退出——报告 $0 MRR;这是正确值,不是错误 |
| 多币种合约 | 每个合约的 currencyCode 不同 | 按币种分组 MRR;不要跨币种求和——在输出中分别呈现 |
| 预付费合约(设置了 maxCycles) | 客户预付了 N 个周期 | 在 ACTIVE 期间仍贡献 MRR,但合约将在 maxCycles 后结束;在输出中标记 |
最佳实践
- 仅当店铺实际销售订阅商品时该技能才有意义。如果不运行订阅,MRR 将为 $0——这是正确的。
- 每月第一天运行,使 MRR 快照与财务的月度结算节奏一致。
- 逐周跟踪 MRR,及早发现支付失败高峰——未恢复的 FAILED 合约会在 30 天内变成流失。
- 预付费年度订阅会抬高 ARR,但不会抬高任何给定月份的现金流——向关注现金流视角的投资者报告时,请将它们分开。
- 与 churn-risk-scorer(交易性流失)配合使用,以三角验证订阅流失与一次性购买流失——它们值得不同的留存策略。
- 多币种店铺:按币种报告 MRR;通过即期汇率换算会产生随汇率而非业务表现波动的误导性数字。