你的消耗数据只是为 Apple 的退款决定提供参考,而非决定它
当客户向 Apple 申请退款时,你有 12 小时来发送消耗数据。Apple 自己的文档称它是众多因素之一,而不是最终裁决。以下是你的数据实际能撼动什么,为什么一个 DECLINE 最终仍可能退款,以及这次推动到底值多少钱。

要点
- 当客户申请退款时,Apple 会向你的服务器发送一条 CONSUMPTION_REQUEST 通知,并给你 12 小时通过 Send Consumption Information 端点回复消耗数据。错过这个窗口,Apple 就会在没有你参与的情况下作出决定。
- 用 Apple 自己的话说,App Store 会用众多因素来决定一笔退款,而你发送的消耗信息被用来为该决定提供参考。你的 refundPreference 只是其中一个因素,而不是最终裁决。
- 你可以发送一个 refundPreference,取值为倾向拒绝、倾向全额批准或倾向按比例批准。Apple 会权衡它。这就是为什么各团队会看到一笔他们标记为倾向拒绝的购买仍被退款,而这正是文档所描述的正常运作。
- 除非 customerConsented 为 true,否则 Apple 会拒收你的消耗数据。如果客户没有同意共享这些数据,Apple 的指引是完全不要回应该通知,而获取该同意的责任完全在你。
- 自 WWDC24 起,CONSUMPTION_REQUEST 也会为自动续期订阅触发,而不再仅限于消耗型商品,因此同样的 12 小时回复如今覆盖的退款范围比以往大得多。
- 对于自动续期订阅,Apple 会自行计算消耗量并禁止使用按比例的偏好,因此你在那里的筹码,要比在一件你能描述为已完全消耗的消耗型商品上薄得多。
- 你为交付这笔购买已经花掉的钱,包括算力、第三方 API 调用、存储,无论 Apple 是否批准退款都已一去不返。你的消耗回复能改变退款结果,却永远无法改变你为交付而已经付出的成本。
客户点了退款,一分钟内你的服务器就收到了来自 Apple 的 CONSUMPTION_REQUEST。你有 12 小时用消耗数据来作答,而人们很容易把这条回复当成一票否决:发送倾向拒绝,把钱留住。它不是一票否决。Apple 自己的文档写道,App Store 会用众多因素来决定一笔退款申请是获批还是被拒,而你提供的消耗信息被用来为它的退款决定提供参考。是提供参考,不是决定。这篇文章会梳理你的消耗数据实际能撼动什么,为什么一笔你标记为倾向拒绝的购买仍可能被退款,以及一旦把你已经花掉的钱计算在内,整件事到底值多少。
Apple 究竟拿你的消耗数据做什么
Send Consumption Information 端点的存在,是为了让你能在退款存疑的那一刻把背景信息交给 Apple。它并不把决定权交给你。以正确的顺序理解这个流程,是在合理设定预期,与针对一个文档已写明的行为提交 bug 之间的区别。
App Store 作决定,而你作推荐
Apple 对这种分工说得很明白。在 Send Consumption Information 参考文档里,Apple 写道 App Store 会用众多因素来决定一笔退款申请是获批还是被拒,并且它会用你提供的消耗信息为其退款决定提供参考。在 refundPreference 字段本身的说明里,Apple 表示你的退款偏好是 App Store 用来为其退款决定提供参考的众多因素之一。所以你能发出的最强信号,一个干脆的倾向拒绝,仍然只是你无法掌控的模型中的一个输入。客户的历史记录、他们给出的理由、商品类型,以及 Apple 自己的欺诈信号,全都和你的回复并列在同一个模型里。
CONSUMPTION_REQUEST 如今覆盖订阅,而不仅是消耗型商品
这曾经是一个只关于消耗型商品的故事。自 WWDC24 起,当客户为一件消耗型应用内购买或一项自动续期订阅申请退款时,CONSUMPTION_REQUEST 通知都会触发。这是覆盖面的一次大幅扩张。同样的 12 小时回复如今也适用于订阅退款,而你在那里的筹码有所不同,因为 Apple 会自行为自动续期商品计算消耗量,并且不会接受你给出的按比例偏好。在决定你的回复能推得多用力之前,先读一读每个请求上的商品类型。
你被允许发送的五个输入
Apple 接受的 V2 请求体很小,五个字段承担了全部工作,其中三个是必填的。每一个都是 Apple 会权衡的输入,而不是一个强制结果的开关。以下是你能放进回复里的内容,以及它告诉 Apple 什么。
| 字段 | 是否必填 | 它告诉 Apple 什么 |
|---|---|---|
| customerConsented | 是 | 客户是否同意共享这份退款数据。必须为 true,否则 Apple 会拒收该请求。 |
| consumptionStatus | 否 | 用了多少:未申报、未消耗、部分消耗,或已完全消耗。 |
| deliveryStatus | 否 | 你的应用是否交付了可正常使用的购买,或遇到了你想留档的问题。 |
| sampleContentProvided | 否 | 你是否在购买前提供了免费样品、试用,或对该功能的说明。 |
| refundPreference | 否 | 你推荐的结果:倾向拒绝、倾向全额批准,或倾向按比例批准。 |
12 小时的窗口,以及大多数团队会漏掉的同意关卡
有两个机制决定了你的回复是否算数。一个是时钟。另一个是一个同意标志,它会把许多出于好意的回复挡在门外。
在 12 小时内回应,否则时机就过去了
Apple 的指示很直白:在收到 CONSUMPTION_REQUEST 通知后的 12 小时内回应。这就是全部窗口。一笔退款申请不会等你下一个工作日,而一条迟到的消耗回复,是一条 Apple 从未权衡过的回复。如果你在手工作答,这个 12 小时时钟正是会最先悄悄失守的部分,在周末、在假日、在你所在时区的凌晨三点。回复必须自动化才可靠,因为这个窗口不在乎你的团队什么时候醒着。

除非客户同意,否则你无法发送数据
这就是让各团队栽跟头的关卡。对于一个 customerConsented 值不为 true 的 Send Consumption Information 请求,Apple 会拒收。用 Apple 的话说,如果客户提供了同意,就通过调用 API 并发送消耗数据来回应;如果没有,就不要回应 CONSUMPTION_REQUEST 通知。Apple 还把责任明明白白地压在你身上:在共享客户个人数据之前,你必须取得客户的有效同意,而作为开发者的你,对取得它负全部责任。所以每个请求上的第一个问题不是他们用了多少,而是这位客户是否同意让我们告诉 Apple。没有同意,就没有回复,而这笔退款会在除你那一方陈述以外的一切之上被决定。
究竟是什么在撼动 Apple 的退款决定
如果这条回复是一份推荐,那么诚实的问题是它推荐得有多重。答案是,你的数据恰恰在人会犹豫的地方最要紧,而在结果本就毫无悬念的地方最不要紧。
为什么你发送了倾向拒绝,仍会看到退款
有开发者反映,他们在一笔客户已完全消耗的购买上发送了倾向拒绝,却眼看 Apple 照样退了款。这不是 API 坏了。Apple 告诉过你它会权衡众多因素,而在任何一个具体请求上,其中某些因素都可能压过一件已完全消耗的消耗型商品:一位历史记录干净的客户、一个被 Apple 视为有力的陈述理由、一笔小额金额、一次首次申请。你的回复在向退款反向施力。其他输入施力更狠。教训不是停止回复,而是不要再指望一件干净的消耗型商品总能挺过去。在信号确实混杂的地方,一个部分消耗状态、一份有记录的交付问题,以及一个诚实的偏好,才是能把一个临界情形扳向你这一边的输入。
一份推荐值多少钱
一笔退款不等于这笔销售的价格。它等于销售价格加上你为交付它已经花掉的一切,而消耗回复触及的永远只有前一部分。
请求到来时,钱早已花掉
等到 Apple 问是否要退款时,客户早已用掉了那件东西。在一件消耗型商品上,这意味着算力已经跑过、第三方 API 调用已经计费、图像或 token 或生成结果已经产出、存储已经写入。这些在你这一方都是已付成本,如果 Apple 拒绝退款它们不会回来,如果 Apple 批准退款它们就赔了两次。你的消耗回复能在一个临界情形上赢回销售价格。它赢不回你已经交出去的货物成本。这才是一件已完全消耗的购买是退起来最贵的那一笔的真正原因,而这与它是多久以前买的毫无关系。
- 销售价格:在 Apple 抽成后你的净收入,若退款获批则被冲回。这是你的回复唯一能影响的部分。
- 交付成本:算力、API 调用、存储,以及你已针对这笔购买作出的任何支付。无论决定如何都已不再。
- 人力时间:每一笔手工作答的退款都是某人一天里的几分钟,而 12 小时窗口意味着这些分钟落在不方便的时段。
- 你漏掉的模式:一位一次又一次退款的客户是一项成本,而你只有在跨请求追踪消耗与历史、而不是把每一笔都当成一次性事件时,才看得见它。
Google Play 如何处理同样的问题
Apple 并不是唯一一家先请你发表意见、再自行决定的商店。Google Play 为银行拒付运行着一套平行的流程,而其形态是一样的:你发送证据,商店作决定。差异在于那个时钟,以及你被允许发送什么。
| 问题 | App Store | Google Play |
|---|---|---|
| 触发条件 | CONSUMPTION_REQUEST 通知 | 针对拒付的 PendingRefundReviewNotification |
| 你的窗口 | 12 小时 | 24 小时 |
| 你如何作答 | Send Consumption Information | orders.reviewrefund |
| 你的推荐 | refundPreference:倾向拒绝、倾向全额批准、倾向按比例批准 | refundPreference:APPROVE、DECLINE 或 NEUTRAL |
| 谁作决定 | App Store | Google Play,或拒付情形下的银行 |
两家商店给出的要点是一模一样的。你的工作是在窗口内用准确的消耗证据和一个诚实的偏好来作答。商店的工作是作决定。把两者搞混,就是一个团队最终要么因为回复只是一份推荐而忽视窗口,要么把回复当成一票否决、在退款照样落地时被打个措手不及的原因。两者都不对。每次都作答,作答要准确,并把结果当成一个你为之提供了参考的决定,而不是一个由你作出的决定。
RefundHalt 会在 Apple 发出 CONSUMPTION_REQUEST 的那一刻就将它接住,核对同意,组装消耗状态、交付状态和一份基于证据的退款偏好,并在 12 小时窗口内作答,无需你团队里的任何人盯着时钟。它为 Google Play 的拒付审核在其 24 小时窗口内做的是同样的事。你无法让 Apple 按你的意思来决定。但你可以确保 Apple 永远不会在没有你那一方陈述的情况下作出决定,在每一笔退款上,且都赶得及。
常见问题解答
- 向 Apple 发送消耗数据能阻止一笔退款吗?
- 单靠它不能。Apple 的文档说 App Store 会用众多因素来决定一笔退款,而你的消耗数据被用来为该决定提供参考。你的回复,包括一个取值为倾向拒绝的 refundPreference,只是 Apple 会权衡的一个输入,所以它能撼动一个临界情形,却不会保证被拒,尤其是在一笔客户已完全消耗的购买上。
- 我有多长时间来回应一条 CONSUMPTION_REQUEST?
- 12 小时。Apple 说要在收到 CONSUMPTION_REQUEST 通知后的 12 小时内,通过 Send Consumption Information 端点回应。一条在窗口之后到达的回复,是一条 Apple 从未权衡过的回复,这也是为什么这个回应必须自动化,而不是交给一个可能正在睡觉的人来处理。
- 为什么我发送了倾向拒绝之后,Apple 还是退了一笔购买的款?
- 因为倾向拒绝是一份推荐,不是一道命令。Apple 表示你的退款偏好是它用来为其决定提供参考的众多因素之一。在一个具体请求上,客户的历史记录、他们给出的理由、金额大小,以及 Apple 自己的欺诈信号,都可能压过你的偏好,所以在一个倾向拒绝之后发生的退款,正是文档所描述的流程在正常运作。
- 我需要客户同意才能发送消耗数据吗?
- 需要。除非 customerConsented 为 true,否则 Apple 会拒收一个 Send Consumption Information 请求,而它的指引是,如果客户没有同意,你就完全不该回应 CONSUMPTION_REQUEST。Apple 还表示,作为开发者的你,对在共享客户数据之前取得有效同意负全部责任。
- 消耗流程对订阅有效,还是只对消耗型商品有效?
- 两者都有效,自 WWDC24 起。CONSUMPTION_REQUEST 现在会为一件消耗型应用内购买或一项自动续期订阅触发。对于自动续期订阅,Apple 会自行计算消耗量并且不接受按比例的偏好,所以你的筹码要比在一件你能直接描述其用量的消耗型商品上更窄。
来源和延伸阅读
- Apple Developer: Send Consumption Information (12-hour window, informs refund decisions)
- Apple Developer: ConsumptionRequest (the request body fields)
- Apple Developer: refundPreference (one of a variety of factors)
- Apple Developer: customerConsented (consent is required)
- Apple Developer: notificationType (CONSUMPTION_REQUEST covers subscriptions)
- Google Play Developer API: Method orders.reviewrefund (24-hour chargeback review)
RefundHalt
App Store 和 Google Play 退款自动驾驶
继续阅读
为每一笔 Google Play 购买打上混淆账户 id 标记,否则拒付到来时你将无从追溯
Google Play 允许你为每一笔购买盖上一个稳定的哈希 id,并在争议发生时把它读回给你。设置好它,一次拒付审查就能精确对应到你必须上报其使用情况的那个用户。跳过它,你就只能在 24 小时的时限内拿着一个孤零零的订单 id 去猜。
银行账单上一笔无法识别的费用会变成拒付,而拒付给你带来的损失比退款更大
当客户无法辨别你的应用向他们收取了什么费用时,他们会打电话给银行而不是联系你,于是这场纠纷就变成了拒付。Apple 把所有费用都显示为 apple.com/bill,并且不让你更改任何内容。Google Play 允许你设置账单显示名称。以下是各自的代价以及你能掌控的部分。