所有文章
深度解析阅读需 8 分钟

Advanced Commerce API 退款是 iOS 开发者发起退款的唯一途径,而最终决定权仍在 Apple

大多数 iOS 开发者无法给客户退款。接入 Apple Advanced Commerce API 的 App 可以申请退款、撤销订阅,或退还自定义金额。本文说明每个端点如何运作,Apple 仍可拒绝什么,以及钱在哪些环节容易出错。

一位女士坐在家庭办公桌前,用笔记本电脑旁的 iPad 浏览庞大的有声书和课程库。这类大型目录 App 可以向 Apple 发送 Advanced Commerce API 退款请求

要点

  • 一位 Apple 工程师在 2026 年 6 月表示,对于普通的 App Store 购买,开发者无法直接发起退款。开发者唯一能提供的,是在回复 CONSUMPTION_REQUEST 时发送的消费数据和 refundPreference。
  • 获准使用 Apple Advanced Commerce API 的 App 可以调用 Request Transaction Refund 端点,请求 App Store 为一次性扣款或订阅交易退款,另外还有 Revoke Subscription 和 Cancel a Subscription 端点。
  • 要调用 Advanced Commerce API 的退款、撤销和取消端点,开发者的 Account Holder 必须签署 Advanced Commerce API Addendum(补充协议)。Apple 表示,如果未接受最新版本,调用会返回错误。
  • Request Transaction Refund 端点的 refundType 可取 FULL、PRORATED 或 CUSTOM。以货币千分之一单位表示的 refundAmount 仅在 CUSTOM 下允许。Apple 表示,除加拿大和美国外,所有地区的金额都必须含税。
  • Apple 的 refundRiskingPreference 字段默认为 true,这让 App Store 可以就开发者自己的退款请求发送 CONSUMPTION_REQUEST。Apple 要求在 12 小时内回复。
  • Advanced Commerce API 的退款、撤销和取消端点在生产环境中限制为每个 App 每秒 5 个请求,沙盒环境只有其 10%。
  • Revoke Subscription 调用成功后,Apple 会发送 REFUND 通知,并要求开发者以其中的 revocationDate 为准终止服务,而不是在通知到达之前。

普通 iOS 开发者无法给客户退款。2026 年 6 月,一位 App Store Commerce Engineer 在开发者论坛上只用一句话回答了这个问题:目前,开发者无法直接发起退款。例外只有一个,就在 Advanced Commerce API 里。获得 Apple 批准的 App 可以发送 Advanced Commerce API 退款请求,撤销订阅并退款,或申请自定义金额。钱退不退,仍由 Apple 决定。

Advanced Commerce API 是什么,谁能用

Apple 于 2025 年 1 月 23 日发布 Advanced Commerce API。它用于处理超大型目录的 Apple App 内购买,包括自定义的一次性购买、订阅,以及带可选附加项的订阅。你不必在 App Store Connect 中逐个创建产品,而是在自己的服务器上定义 SKU,在购买时发送给 Apple。

权限按 App 逐个授予。你需要填写申请表。Apple 的资格页面列出了三种商业模式,必须是 App 的核心业务:

  • 超大型一次性购买目录,例如有声书、课堂、课程或小程序。
  • 超大型订阅内容目录,每位创作者的内容各自是一个独立订阅。
  • 带可选附加项的订阅,附加项与主订阅作为一笔购买一起续订,例如付费频道或体育内容。

如果其他计划需要用到该 API,Apple 也允许 App 申请。Mini Apps Partner Program 就要求使用它。该计划向成员支付托管小程序中合格 App 内购买销售额的 85%。

退款端点后来才加入,而且需要签署协议

2025 年 3 月 24 日发布的 1.1 版新增了 Request Transaction Refund 和 Revoke Subscription。Apple 的计划页面称,提供订阅内容的 App 也可能有资格使用 Cancel、Revoke 和 Refund API,用于处理取消、在购买后验证内容以及管理目录。每个端点页面都附加了同一个条件:你的 Account Holder 必须签署 Advanced Commerce API Addendum,如果未接受最新版本,调用会返回错误。列出各端点适用场景的是 Addendum,而不是文档。

三个端点对比

Cancel a SubscriptionRevoke SubscriptionRequest Transaction Refund
路径advancedCommerce/v1/subscription/cancel/{transactionId}advancedCommerce/v1/subscription/revoke/{transactionId}advancedCommerce/v1/transaction/requestRefund/{transactionId}
适用范围自动续期订阅一个订阅及其所有项目一次性扣款和订阅交易
退款无FULL 或 PRORATEDFULL、PRORATED 或 CUSTOM,按 SKU
访问权限持续到当前周期结束在 revocationDate 终止通过 revoke 标志逐项设置
生产环境速率限制每秒 5 个每秒 5 个每秒 5 个

Cancel a Subscription 停止下一次扣款

Cancel 会关闭自动续期。Apple 表示,客户在当前周期结束前仍可使用。不退任何款项。如果客户想退出,而且已经用完了付费的时间,这就是正确的选择。

Revoke Subscription 立即终止一切

Revoke 将自动续期设为 false,并以全额或按比例退款的方式撤销订阅。其请求体包含 refundReason、refundRiskingPreference、refundType 和 requestInfo。随后 Apple 会向你的 App Store Server Notifications V2 端点发送 REFUND 通知。Apple 的指示很明确:以该通知中的 revocationDate 为准关闭服务,不要在通知到达之前关闭。

Request Transaction Refund 逐项处理

这是最精确的工具。你提交一个项目列表,每个项目指定 SKU、refundReason、refundType 和 revoke 标志。使用 CUSTOM 时,还要以货币的千分之一单位发送 refundAmount,所以 4990 表示 4.99。如果在 FULL 或 PRORATED 下发送金额,Apple 会以错误 4000155 拒绝。响应包含已签名的交易信息,订阅还会附带已签名的续期信息。

Apple 接受以下 refundReason 值:UNINTENDED_PURCHASE、FULFILLMENT_ISSUE、UNSATISFIED_WITH_PURCHASE、LEGAL、OTHER 和 MODIFY_ITEMS_REFUND。第七个值 SIMULATE_REFUND_DECLINE 仅用于沙盒和 TestFlight 测试。它之所以存在,是因为 App Store 可以拒绝。

Apple 仍可拒绝你自己的退款请求

这个端点的名字很诚实。它只是一个请求。有两个字段说明了决定权真正在哪里。

refundRiskingPreference 会引来消费核查

Apple 对 refundRiskingPreference 的描述是:App Store 是否向你索取消费数据,作为退款决定的依据。它默认为 true。为 true 时,你会就自己的退款请求收到 CONSUMPTION_REQUEST,并通过 Send Consumption Information 回复。Apple 要求开发者在收到 CONSUMPTION_REQUEST 后 12 小时内回复。设为 false,就不会收到这条通知。

告诉你“不行”的错误

错误代码Apple 的说明
AlreadyRefundedError4030021该交易已退款
PendingRefundError4000181该交易有待处理的退款
TransactionNotRefundableError4030024该交易不可退款
TransactionCannotBeRefundedContactSupportError4030025客户可以联系 Apple 支持
RefundAmountWithoutCustomError4000155未使用 CUSTOM 却发送了金额

最需要提前准备的是 PendingRefundError。一个常见原因是:在你的客服团队处理之前,客户已经通过 Report a Problem 向 Apple 提出了申请。Apple 的资格规则本来就要求这类 App 在 App 内提供退款途径,可以是 Report a Problem 链接,也可以是 beginRefundRequest API,所以两扇门会同时敞开。

一位开发者手持 iPhone,对照打印出来的交易明细,核对一笔 Advanced Commerce API 退款应覆盖哪个项目

Advanced Commerce API 退款让你付出的真金白银

主动退款感觉比应对争议更省钱。但钱还是流出去了,而且这个 API 会让某些错误很容易被大规模重复。

自定义金额里的税

Apple 表示,请求的 refundAmount 必须含税,加拿大和美国除外。如果团队按税前 SKU 价格计算 CUSTOM 退款,就会在其他所有店面少退给客户,然后还要花客服时间逐一修正。

收不回来的成本

  • 分成支出:在创作者目录或小程序托管平台中,创作者的分成往往在销售时就已支付。给客户退款并不能把这笔钱收回。
  • 内容授权:有声书或课程按作品向版权方支付的费用,根据合同可能在访问时就已触发,退款不会撤销这些费用。
  • 计算资源:为这笔购买所做的流媒体传输、转码和任何服务器工作,费用已经计入你的账单。
  • API 调用:按请求计费的第三方服务,从语音到模型推理,退款之后照样计费。

本想退一个项目,却全额退了

Revoke Subscription 会退款并终止整个订阅,附加项也包括在内。如果客户只对一个附加项有异议,Request Transaction Refund 可以只退该 SKU,并只对该项目设置 revoke。因为一个项目的投诉就调用 Revoke Subscription,会连基础套餐的收入也一并退还。

启用之前的开发检查清单

  • 确认你的 Account Holder 已接受当前版本的 Advanced Commerce API Addendum,并在协议失效时针对返回的错误设置告警。
  • 每个请求都生成新的 requestReferenceId UUID,只有在重试超时的调用时才复用同一个。
  • 把退款调用放入队列。限制是每个 App 每秒 5 个,429 响应会带有以 UNIX 毫秒表示的 Retry-After 头。
  • 在沙盒中用 SIMULATE_REFUND_DECLINE 测试拒绝情形,并记住沙盒限制是生产环境的 10%。
  • 按具体情况决定 refundRiskingPreference。当它保持为 true 时,准备好消费数据响应程序,以应对 12 小时的回复窗口。
  • 只在 REFUND 通知到达时终止访问,并以其中的 revocationDate 为准。
  • 记录每个请求的原因、金额和 SKU,这样在 Apple 看到你的退款率之前,你自己先能看到。

常见问题解答

iOS 开发者能直接给客户退款吗?
普通的 App Store 购买不行。一位 Apple 工程师在 2026 年 6 月表示,开发者无法直接发起退款。获准使用 Advanced Commerce API 且已签署 Addendum 的 App,可以通过 Request Transaction Refund 端点申请退款,但仍由 Apple 决定。
Advanced Commerce API 中的 Cancel 和 Revoke 有什么区别?
Cancel 关闭自动续期,客户在周期结束前仍可使用,不退款。Revoke 立即终止订阅及其所有项目,并退还全额或按比例的金额。撤销之后,Apple 会发送 REFUND 通知。
能用 Advanced Commerce API 退还自定义金额吗?
可以。将 refundType 设为 CUSTOM,并以货币的千分之一单位传入 refundAmount。Apple 表示,除加拿大和美国外,所有地区的金额都必须含税。在 FULL 或 PRORATED 下发送金额会返回错误 4000155。
我自己申请的退款,也会收到 CONSUMPTION_REQUEST 吗?
有可能。refundRiskingPreference 默认为 true,App Store 因此可以通过 CONSUMPTION_REQUEST 向你索取消费数据,Apple 要求在 12 小时内回复。设为 false,Apple 表示就不会发送这条通知。
为什么我的 Advanced Commerce API 退款请求失败了?
先看错误代码。4030021 表示该交易已退款,4000181 表示已有待处理的退款,4030024 表示不可退款,4030025 表示客户应联系 Apple 支持。未签署或版本过旧的 Addendum 也会返回错误。

来源和延伸阅读

RefundHalt

App Store 和 Google Play 退款自动驾驶

继续阅读

下一项退款请求已经在路上。

读完又一封关于未能申辩退款的支持邮件所需的时间,足够您完成 RefundHalt 设置。