要理解什么是 CONSUMPTION_REQUEST,一段话就够了。但要构建一个能可靠处理它的系统,所需的工作要多得多,而且真正让人栽跟头的地方往往出乎意料。
签名验证是其中之一。用户同意是另一个,因为它必须在通知到达之前就已存在。此外,重试计划与响应窗口之间的相互作用,也会让大多数团队在第一次仔细研究时感到意外。
本文将从请求到达你的端点那一刻开始,一直讲到最终完成权益更新的整个处理流程。
要点速览
• CONSUMPTION_REQUEST 是在退款审核期间向你索取信息。最终决定仍由 Apple 做出。
• 先验证签名负载,再据此采取行动。绝不要信任未经验证的通知。
• 用户同意必须已在你的应用中获取。请求到达后再收集就来不及了。
• Apple 要求在通知发出后 12 小时内做出响应。
• Apple 按固定计划重试失败的投递,而第二次重试会在响应窗口关闭之后才到达。
• 跟踪结果并在之后更新权益。响应并不是最后一步。
什么是 Apple CONSUMPTION_REQUEST 通知?
Apple CONSUMPTION_REQUEST 通知是一种 App Store Server Notification,用于告知你的服务器:某位用户已申请退款,Apple 邀请你提交该笔购买的消耗信息。它会发送到你配置的通知 URL,携带相关交易信息,并给你有限的时间进行回复。
它既不是退款,也不是决定。Apple 正处于审核过程中,正在收集背景信息。你的职责是提供关于该笔购买实际情况的准确信息;Apple 的职责是做出决定。
Apple 为什么会发送 CONSUMPTION_REQUEST?
因为 Apple 看不到你应用内部发生了什么。它知道交易、账户和购买历史,但不知道内容是否已交付、是否正常可用,以及用户使用了多少。
消耗信息正是用来填补这一空白的。它是 Apple 权衡的多个因素之一,而非决定性因素,消耗比例高也不等于自动拒绝退款。把它当作你提供的背景信息,而不是你在为某个立场辩护。
开发者收到 CONSUMPTION_REQUEST 后应该怎么做?
验证通知,识别交易和用户,确认已获得同意,整理准确的消耗数据,在 Apple 规定的窗口内发送,然后记录处理结果。
实际操作分为十步:
1. 在你配置的服务器端点接收通知,并立即持久化保存。
2. 先验证签名负载,再将任何字段视为可信。
3. 读取通知类型并进行路由。消耗请求不等于退款结果。
4. 从解码后的负载中识别相关交易。
5. 将该交易关联到你自己系统中的用户账户。
6. 检查该用户的同意授权是否允许你做出响应。
7. 从你的记录中收集交付和使用数据,而不是靠估算。
8. 准备响应内容,并对照字段验证规则进行检查。
9. 提交到 Apple 的消耗信息端点并记录返回结果。
10. 跟踪随后的退款结果,然后更新权益和记录。
开发者应如何验证 CONSUMPTION_REQUEST?
在信任内容之前先验证签名。通知以签名的 JWS 负载形式送达,相关说明见 Apple App Store Server Notifications 文档,你的处理程序应根据 Apple 的证书链进行校验,并确认 bundle ID 与你的应用一致。
原因很简单。你的通知 URL 是一个公开端点。如果实现方式是解析收到的任何内容并据此行动,那么任何找到该 URL 的人都可以操控它。
有三个处理细节与签名同样重要:
返回正确的状态码。 Apple 将 HTTP 200 到 206 视为成功。40x 或 50x 会告诉 App Store 进行重试。存储通知后就返回成功,而不是等处理完成后再返回——这是两个不同的时间点,把它们绑在一起意味着一个缓慢的下游任务可能触发不必要的重试。
处理重复通知。 重试意味着同一条通知可能多次到达,每条通知都带有一个 notification UUID,可用于去重。对重复通知应予以确认而不是报错;返回失败响应只会重新启动重试循环。
记住沙盒环境的行为不同。 重试机制适用于生产环境。在沙盒中,App Store 只尝试投递一次,因此在测试中看起来正常的处理程序,在生产环境中仍可能丢失事件,反之亦然。
开发者在响应前应检查什么?
四件事,按以下顺序。
首先是用户同意,因为它可能让一切止步。Apple 要求在分享用户数据之前必须获得有效的用户同意,获取同意是你的责任而非 Apple 的责任,且通知本身不携带任何同意标志。Apple 还明确指出,App Tracking Transparency 提示并不是这里所指的机制。如果没有获得同意,指导原则是不要响应。
其次是交易身份。你需要知道这是哪笔购买、背后是哪个账户。这种映射正是 appAccountToken 与 Apple 退款防御一文所讨论的内容——如果没有从交易到账户的稳定关联,你就只能在截止时间的压力下靠推测。
第三是产品类型,因为它会影响你可用的选项。最后是你是否真正掌握可用的数据。如果你的系统无法说明内容是否已交付,最好在开始整理响应之前就了解这一点。
开发者可以向 Apple 发送哪些消耗信息?
Apple 当前的 Send Consumption Information 文档定义了五个字段。三个必填,两个可选。
字段 | 是否必填 | 通俗解释 |
customerConsented | 是 | 用户是否同意?必须为 true,否则请求会被拒绝。 |
deliveryStatus | 是 | 你的应用是否真正交付了可正常使用的购买内容?如果没有,原因是什么? |
sampleContentProvided | 是 | 用户在购买前能否试用? |
consumptionPercentage | 否 | 用户使用了多少?以千分之一为单位——一半是 50000,而不是 50。 |
refundPreference | 否 | 你的偏好:全额退款、拒绝退款或按比例退款。 |
有两条规则常让人出错。如果交付状态不是“已交付”,消耗百分比必须为零。而退款偏好只是偏好,不是指令;Apple 可以且确实会做出不同的决定。
值得确认一下你使用的是哪个端点。Apple 还提供了 Apple 的 ConsumptionRequestV1 文档,即早期版本,其请求体包含十二个字段,大多数第三方文章描述的仍是这个版本。Apple 在该页面的说明中将标准应用内购买指向当前端点,并将 V1 限定于 Advanced Commerce API 购买。如果你的集成早于这次变更,这是第一件要检查的事。
开发者响应 CONSUMPTION_REQUEST 的时限是多久?
Apple 当前文档要求在通知发出后 12 小时内做出响应。
这里有个值得注意的地方。Apple 会对投递失败的通知重试五次,分别在上一次尝试后的 1、12、24、48 和 72 小时进行。将其与 12 小时窗口对照一下,结果并不乐观:如果你的端点错过了第一次投递,第一次重试会在一小时后到达,这没问题。如果连这次也错过了,下一次尝试会在大约第十三个小时到达——此时窗口已经关闭。
因此,端点可靠性在这里不只是一般的运维卫生问题。具体到消耗请求,大约一小时的停机是可以挽回的,而半天的停机则不行。
Apple 并未声明错过窗口意味着退款会自动批准,这样说是不对的。它的含义很简单:Apple 会在缺少你本可提供的信息的情况下做出决定。
开发者响应之后会发生什么?
Apple 会将你的信息纳入审核,与其他所有因素一并权衡,然后做出决定。结果会以单独的通知送达:已批准、已拒绝,或者如果 Apple 之后撤销了已批准的退款,则为已撤销。
这里发生的是三件不同的事,把它们区分开会很有帮助。你的响应是信息。Apple 的决定是决定。你的系统更新是状态变更。只有中间那件属于 Apple,而第三件除非你自己构建,否则不会发生。
响应之后开发者如何处理 Apple 退款
结果一旦送达,工作就回到你这边。
将结果记录到对应的交易和用户上。更新订阅状态,因为退款的周期通常意味着订阅结束,而不是继续运行。退款获批时撤销权益,退款被撤销时恢复权益,并处理只撤销部分交易的按比例退款情形。
然后将金额对账到正确的报告周期,并将退款保存在可查询的历史记录中。这份历史记录日后能告诉你某个产品或价位是否产生了不成比例的退款份额,也是客服在用户询问其访问权限发生了什么时所需要的依据。
处理 CONSUMPTION_REQUEST 时有哪些常见错误?
反复出现的错误包括:
• 把通知当作退款,立即撤销访问权限。此时什么都还没决定。
• 因为负载在测试中看起来正常就跳过签名验证。
• 到了必须响应的时候才发现没有同意授权流程。
• 发送估算的消耗数据而不是真实数据。
• 发出请求后从不检查是否成功。事后看来,失败的提交与成功的提交完全一样。
• 混淆取消与退款。它们是不同的事件,对访问权限的影响也不同。
• 处理了批准和拒绝两种结果,却忘了撤销的情形,导致付费用户被锁在门外。
• 在 12 小时倒计时下,依赖有人手动注意到通知。
CONSUMPTION_REQUEST 的处理可以自动化吗?
可以,而且几乎全部都应该自动化,因为几乎每一步都是确定性的。
自动化涵盖通知监控与验证、交易查找、同意检查、消耗数据准备、提交、响应日志记录、结果跟踪、内部告警和报告。这些都不需要临场判断。
仍需人工处理的部分在上游:设计应用内的同意授权流程,以及决定你的退款偏好策略。此外,无论某些工具怎么暗示,自动化对 Apple 的决定没有任何影响。
RefundSensor 如何帮助开发者处理 Apple 退款流程
App Store 退款管理是这个品类,而 RefundSensor 覆盖的是其中开发者这一侧:监控 Apple 退款流程、处理消耗请求的官方支持响应路径、跟踪退款事件和结果,并把重复性工作从人手中接过来。
实际效果是,响应会在窗口内发出,无需任何人凌晨 3 点盯着 dashboard,而且随着量的增长,退款记录依然保持准确。它不能阻止退款,也无法影响 Apple 的决定。它消除的是人工监控和遗漏的步骤。
这些规则的官方出处
Send Consumption Information——当前端点。包含同意要求、12 小时窗口和五个请求字段。标准应用内购买请基于此构建。
Send Consumption Information V1——早期端点,请求体包含十二个字段。可用于确认你的集成调用的是哪个版本,也适用于 Advanced Commerce API 购买。
App Store Server Notifications——通知投递、签名负载格式、预期响应码和重试计划。
如果这些仍在手动处理
12 小时的窗口、可能超出窗口的重试计划,以及深夜到达的通知,都让手动监控难以胜任。 RefundSensor 负责这些流程中开发者一侧的工作——验证通知、在窗口内准备并提交响应,以及将结果一路跟踪到你的权益记录。
常见问题
这是一种 App Store Server Notification,用于告知你的服务器:某位用户已申请退款,Apple 邀请你提交该笔购买的消耗信息。它既不是退款通知,也不是决定。Apple 会另行决定,并将你的响应视为多个考量因素中的一项。
因为 Apple 看不到你应用内部发生了什么。它知道交易和账户历史,但不知道内容是否已交付、是否正常可用,以及用户使用了多少。这些背景信息存在于你的系统中,因此 Apple 会在审核期间向你索取。
验证签名通知,识别交易及其背后的用户,确认已获得同意,从你的记录中收集真实的交付和使用数据,然后在窗口内提交到 Apple 的消耗信息端点。记录返回结果,而不是假设调用已成功。
当前端点有五个字段。三个必填:用户同意、交付状态,以及是否提供了试用内容。两个可选:消耗百分比和你的退款偏好。早期的 V1 端点要求十二个字段,这就是为什么较旧的指南会列出更长的清单。
Apple 当前文档将该通知描述为与所有产品类型的退款请求相关联,范围比旧文档所述更广。Apple 并未对每种情况都做出保证,因此应构建一个在请求到达时进行响应的处理程序,而不是假设请求一定会到达的逻辑。
Apple 要求在通知发出后 12 小时内做出响应。值得注意的是,Apple 对投递失败的重试计划为 1、12、24、48 和 72 小时,因此如果端点在第一次重试之后仍处于宕机状态,可能要等到窗口关闭后才收到通知。
Apple 会将其与其他因素一并权衡,然后做出决定。结果会以单独的通知送达,表明退款已批准、已拒绝或之后被撤销。此后,你需要更新权益、订阅状态和收入记录,以匹配新的交易状态。
可以。验证、交易查找、同意检查、数据准备、提交、日志记录和结果跟踪都是确定性的。仍需人工处理的是设计同意授权流程和制定退款偏好策略。自动化对 Apple 的退款决定没有任何影响。






