PAYATHON 2026

通过 Google Developer API 取消订阅会退款吗?

支付老李

结论

可以。通过 Google Play Developer API 执行”停止续订”不会自动退款,也不会立即终止用户已经付费获得的订阅权益。用户仍可使用订阅服务,直到当前订阅的 expiryTime。到期后,Google Play 不再自动扣款。

如果订阅已经下架,并准备逐步停止支持,建议调用 purchases.subscriptionsv2.cancel,并使用:

DEVELOPER_REQUESTED_STOP_PAYMENTS

这样可以阻止后续付款,同时禁止用户在 Google Play 中恢复该订阅。不要调用退款或撤销接口。

为什么会出现不同说法

“取消订阅”、“退款”和”撤销权益”是三个不同的操作:

操作停止续订退款立即终止访问
Cancel subscription是否否
Refund order通常否是通常否
Revoke subscription是是或按接口规则处理是

Google Play Console 不同历史版本的按钮、文案和操作入口可能不同,社区讨论中也常把取消交易、退款订单和取消订阅混在一起。不能只根据 Console 中的”Cancel”字样判断操作是否会退款,应以具体操作的确认页面和 API 语义为准。

仅将订阅商品从商店下架,也不一定会取消现有用户的自动续订。要让所有存量订阅停止续费,需要逐个处理仍处于有效状态的购买 token。

推荐操作步骤

1. 获取所有有效订阅

从自己的订阅数据库中找出仍然有效或可能继续续订的记录。至少需要以下信息:

  • 应用包名 packageName
  • 订阅购买 token purchaseToken
  • 当前到期时间
  • 用户与购买 token 的关联关系

不要用订单号代替 purchaseToken。

2. 查询订阅当前状态

调用:

GET https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptionsv2/tokens/{purchaseToken}

根据返回的 subscriptionState、lineItems[].expiryTime 等字段,确认订阅是否仍然有效,以及是否已经停止续订。

3. 停止后续付款

调用:

POST https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptionsv2/tokens/{purchaseToken}:cancel
Content-Type: application/json
Authorization: Bearer ACCESS_TOKEN

请求体:

{
  "cancellationContext": {
    "cancellationType": "DEVELOPER_REQUESTED_STOP_PAYMENTS"
  }
}

curl 示例:

curl -X POST \
  "https://androidpublisher.googleapis.com/androidpublisher/v3/applications/com.example.app/purchases/subscriptionsv2/tokens/PURCHASE_TOKEN:cancel" \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cancellationContext": {
      "cancellationType": "DEVELOPER_REQUESTED_STOP_PAYMENTS"
    }
  }'

这个调用只用于停止后续扣款,不会退款。现有权益应保留到 Google Play 返回的到期时间。

4. 按实际到期时间控制访问权限

服务端不应在 cancel 请求成功后立即关闭权限,而应继续根据订阅状态和 expiryTime 判断:

function hasAccess(subscription, now) {
  const expiryTimes = subscription.lineItems
    .map(item => Date.parse(item.expiryTime))
    .filter(Number.isFinite);

  const finalExpiryTime = Math.max(...expiryTimes);
  return now.getTime() < finalExpiryTime;
}

如果订阅包含多条 lineItems,不要默认第一条就是最终到期的项目。

5. 到期后再停止支持

继续处理 Google Play Real-time Developer Notifications,并定期调用 purchases.subscriptionsv2.get 校验最终状态。只有用户的最终 expiryTime 已经过期,并且不存在宽限期、账号保留期或其他有效权益时,才能关闭访问权限。

旧版 API

旧系统中常用的接口是:

POST /androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}:cancel

它同样用于停止自动续订,不会退款。不过,新实现应优先使用 purchases.subscriptionsv2。如果现有代码仍在使用旧接口,需要对照当前 Google Play Developer API 文档,检查接口的可用状态和迁移要求。

注意事项

  • 不要调用 revoke。撤销通常会立即终止订阅权益,不符合”允许用户使用到已付费周期结束”的要求。
  • 不要调用订单退款接口,除非确实需要退钱。退款和停止续订是两个独立的业务决定。
  • 对已经移除的订阅,优先选择 DEVELOPER_REQUESTED_STOP_PAYMENTS。如果使用 USER_REQUESTED_STOP_RENEWALS,用户在某些情况下仍可能从 Google Play 恢复订阅。
  • API 返回成功,只代表取消请求已经被接受。访问权限仍应根据重新查询到的订阅状态和到期时间判断。
  • 暂停、宽限期、账号保留期、延期和替换订阅都可能改变最终到期时间,因此不能只依赖本地最初保存的日期。
  • 批量处理时,应保存每个 token 的请求结果,并保证操作具有幂等性。失败记录需要重试,不要因为单个请求失败而中断整个批次。
  • Google Play Console 的界面和操作文案可能随时间变化。人工操作前,应仔细检查确认页面是否同时包含退款或撤销权益。

备注:内容仅供参考。