长期以来,对于"我该如何回应 Apple 退款请求"这个问题,老实说答案就是:你根本无法回应。Apple 收款、接受请求、做出决定,而开发者第一次得知此事,往往是发现收款金额变少了。自 2021 年以来,情况已不再如此,尽管许多人仍然这么以为。
如今,Apple 会在做出决定之前询问你的服务器对这笔购买了解多少,并会等待大约 12 小时以获取回复。我们之前已经详细写过CONSUMPTION_REQUEST 实际包含哪些内容,因此这里不再逐字段重复讲解 payload。本文要讲的是:这类通知到达之后该怎么做。
核心要点
每一笔 App Store 退款都是由 Apple 决定的。你提交的信息并不会改变这一点,但会改变 Apple 做决定时所掌握的信息。
该请求以 CONSUMPTION_REQUEST 通知的形式送达,仅适用于消耗型项目和自动续订订阅。
你有 12 小时的时间,通过 Send Consumption Information 端点进行回复,该端点目前需要五个字段的信息。
回复内容主要围绕三个事实:是否已交付、使用了多少、用户此前是否获得过免费体验。再加上你的处理意向。
根据我们的经验,开发者"输掉"的退款,大多是那些根本没人回应的请求。
什么是 Apple App Store 退款请求?
Apple App Store 退款请求是指客户向 Apple(而不是向你)申请退还某个应用或应用内购买项目的款项。他们会访问 reportaproblem.apple.com,或使用应用内退款表单,从简短的菜单中选择一个理由,选定购买项目后提交申请。Apple 的支持页面告知用户,应在 24 到 48 小时内得到答复。
如果该购买项目是消耗型项目或自动续订订阅,Apple 会向你的服务器发送请求,询问你所了解的信息,然后将你的回复与客户自身的购买及退款历史(Apple 对此远比你了解得多)结合起来,做出最终决定。你看不到客户的姓名,也没有否决权。你拥有的,只是一段很短的时间窗口,用来摆出事实。
Apple 退款流程对开发者而言是如何运作的
面向开发者的 Apple 退款流程分为四个阶段,而你只需参与其中一个。
客户向 Apple 申请退款,并选择一个理由。
Apple 向你在 App Store Connect 中注册的服务器 URL 发送一个 CONSUMPTION_REQUEST。这种情况仅适用于消耗型项目和自动续订订阅。
你有 12 小时的时间,调用 Send Consumption Information 端点提交你的数据。
Apple 做出决定,然后通过 REFUND 通知或 REFUND_DECLINED 通知告知你结果。
如果你从未为 App Store Server Notifications 设置服务器 URL,第二阶段就悄悄不会发生。Apple 会仅凭客户账户信息做出裁定,而你只能从销售报告中得知结果——前提是你会去看那份报告。
客户申请退款后会发生什么?
客户提交申请后不久,你的端点会收到一个经过签名的 JSON payload,其 notificationType 为 CONSUMPTION_REQUEST。其中包含:已签名的交易信息、产品 ID、原始交易 ID,以及一个 consumptionRequestReason。Apple 在 2024 年新增了这个理由字段,并在WWDC24 关于 App Store server API 的分享会中做了说明。该字段有五种可能的取值:UNINTENDED_PURCHASE、FULFILLMENT_ISSUE、UNSATISFIED_WITH_PURCHASE、LEGAL 和 OTHER。
缺失的是"人"这个信息。唯一能追溯到你记录中的线索,是交易 ID,以及你在购买时是否附加了 appAccountToken。如果你当时没有这样做,这正是你会后悔没做的时刻。
所以,审核其实就是一次查询:是谁买的,他们是否收到了,以及此后他们对它做了什么?
如何回应 Apple 退款请求
搜索"如何回应 Apple 退款请求通知"的人,大多只能找到 API 参考文档。以下是按顺序排列的具体步骤。
1. 验证 Payload
Apple 会对每个通知进行签名。在你相信其中任何内容之前,先验证签名。Apple 的 App Store Server Library 在 Java、Python、Node 和 Swift 中都提供了这项功能。
2. 找到对应的购买记录
使用交易 ID 或 appAccountToken,在你自己的系统中查找该笔购买记录。你需要找到的是用户信息、交付记录,以及此后记录的任何使用数据。
3. 查看理由,然后核实它
FULFILLMENT_ISSUE 表示客户称自己从未收到所购买的内容。先查看你的交付日志,因为如果客户说的是实情,你会希望这笔退款顺利通过。
UNINTENDED_PURCHASE 通常是孩子误操作或用户不小心点错导致的。
在 UNSATISFIED_WITH_PURCHASE 这类理由中,你的使用数据才真正起作用,因为"我不喜欢它"这句话,在使用率为 2% 和 100% 时所传达的含义是截然不同的。
4. 选择处理意向
Apple 接受 GRANT_FULL、GRANT_PRORATED 或 DECLINE 这三种取值。选择你的数据能够支撑的那一种。这只是一种"意向",而 Apple 其实批准过不少开发者要求拒绝的退款。
5. 发送回复
调用 Send Consumption Information 端点。目前的请求体包含五个字段:customerConsented、deliveryStatus、consumptionPercentage、sampleContentProvided 和 refundPreference。
消耗量使用的单位是千分之一(milliunits),这常常让人感到困惑:100000 表示已完全使用,45200 表示已使用 45.2%。
而且 customerConsented 必须为 true,因此,共享使用数据的许可应该在第一个请求到达之前,就早早写入你的用户协议中。
6. 根据结果采取行动
REFUND 意味着要撤销相应的内容或权限,最好在一小时内完成。REFUND_DECLINED 则意味着一切照常,无需改动。无论结果如何,都要将处理结果记录在对应的案例中。
举个例子:有人在晚上 11 点购买了一个 500 金币的礼包,一夜之间花掉了其中 470 个,第二天早上以 UNSATISFIED_WITH_PURCHASE 为理由提交了退款申请。结果是:已交付、消耗了 94%、没有试用、处理意向为 DECLINE。这就是一份完整的 Apple 退款请求回复。它不需要写成一篇长文。
开发者在回复之前应该核查哪些信息?
共有五项信息,其中大部分应该已经存在于你的数据库中。
购买记录
购买日期、产品、价格,以及该账户此前是否在你这里有过购买记录。如果你自己的记录不够完整,只要提供该客户的一个交易 ID,Apple 的 Get Transaction History 端点就会返回该客户在你的应用中购买的全部记录。
交付情况
你的服务器是否确实发放了金币、解锁了功能、开启了订阅?具体是在什么时候完成的?如果这一步调用失败了,那么你的 deliveryStatus 就应标注为其中一种 UNDELIVERED 值,这笔退款也确实应该予以批准。不要和自己的日志记录较劲。
此后的使用情况
使用会话次数、打开的章节数、花掉的金币数——无论"使用"对你的产品意味着什么。Apple 只需要一个百分比,但如果没有底层的事件数据支撑,你是无法得出一个经得起推敲的百分比的。
用户此前是否获得过免费体验
也就是免费试用、预览章节或免费版本。Apple 会直接询问这一点,如果答案是"是",就会削弱"我不知道自己买的是什么"这种说法的可信度。
你这边的账户信息
账户的注册时长、此前是否曾为该账户办理过退款、是否存在未结的支持工单。Apple 只能看到 App Store 那一半的历史记录,而你能看到的是你这边的记录。
这一切都取决于能否将 Apple 的交易 ID 与你系统中的用户关联起来,而这正是 appAccountToken 存在的意义。这是我们发现的最常见的缺口。如果你想了解具体设置方法,可以阅读我们那篇讲述appAccountToken 为何对退款防御至关重要的文章。
开发者在应对 Apple 退款请求时常犯的错误
通知从未送达
App Store Connect 中没有配置服务器 URL,或者配置了,但指向的是某个在三月份就已被下线的测试服务器。Apple 一直在发送通知,却根本没人接收。
回复太晚
12 小时听起来绰绰有余,直到某个请求在周日凌晨 2 点送达,而负责处理此事的人正在睡觉,之后在吃早午餐,再之后才隐约注意到一条 Slack 消息。一个围绕办公时间设计的流程,注定会漏掉一部分请求。
无话可说
通知到达时,却没有交付日志、没有使用事件、也没有 appAccountToken。Apple 只能凭客户的说法来做决定。而这个错误,其实是几个月前在结账环节就已经埋下的。
要求 Apple 一律拒绝
我们见过一些设置,对每个请求都统一发送 DECLINE,甚至包括开发者自己的日志已经显示交付失败的情况。Apple 能够看出这种模式,而这会在你真正有理有据的请求上损害你的可信度。
退款批准后忘记撤销权限
这是会让你双重损失的错误。钱已经退了,客户却仍然拥有相应的内容,而有些客户是会注意到这一点的。
在生产环境中测试
Apple 为你提供了测试通知端点和沙盒退款请求功能。在第一个真正的请求在不合时宜的时刻出现之前,把这两者都用起来。
Apple 退款管理:人工处理与自动化处理对比
Apple 退款管理涵盖了围绕那 12 小时窗口期的所有工作:接收请求、查找数据、选择处理意向、发送回复、记录结果,以及在需要时撤销权限。
人工处理
人工处理,意味着由一个人负责——拥有日志访问权限并接收提醒。在每月只有少量请求的情况下,这种方式运作良好,前提是这个人从不请一周的假。
一旦每周请求量达到二十左右,这种方式就开始捉襟见肘。到了每周一百个,这就成了一份专职工作,而且没人愿意主动揽下这份工作。
自动化处理
自动化处理下,查找和回复都依照你事先写好的规则运行。一个已被完全消耗的消耗型项目会得到 DECLINE,一个交付失败且理由为 FULFILLMENT_ISSUE 的请求会得到 GRANT_FULL,而任何异常情况都会被标记出来,交由人工处理。
回复会在几分钟内发出,无论是凌晨 2 点还是下午 2 点,都同样可靠。
但问题在于:自动化的效果取决于背后的数据质量。如果交付和使用记录本身零散不全,自动化只会更快地给出"未知"的结果。
开发者应该在什么时候考虑使用 Apple 退款管理软件?
说实话,一开始并不需要。每月两三个请求,靠一份检查清单和一个醒目的提醒就能搞定,而亲手处理几次也能让你学到不少东西。
当请求的到来速度超出一个人在时间窗口内能处理的能力,或者经常出现在没人清醒的时段时,使用这类软件就开始变得合理了。如果你同时运营多个应用,或者同时兼顾 Apple 和 Google Play,并希望用一个列表来代替三个,这类软件也会很有帮助。
一旦人工处理流程开始漏单,Apple 退款管理软件就物有所值了。你会知道这一刻何时到来:就是你连续错过三个请求,却只能从结算款中察觉异样的那一周。
Apple 退款防御软件:开发者应该关注哪些方面?
如果你在比较各家 Apple 退款防御软件,先从底层机制看起:它是否能自行接收 CONSUMPTION_REQUEST,并在无需人工介入的情况下回复常规案例?速度有多快,包括在深夜和周末的情况?以分钟计才是合格的答案,务必要求查看时间戳记录。
证据
它是否能够拉取或接收你的交付和使用数据,还是仅仅把通知原样回传、附上一个处理意向?后一种做法没有太大价值。
它还应该是基于 App Store Server API 和 Server Notifications V2 构建的,而不是靠解析邮件来实现。
可见性
在请求到达、回复发出、以及 Apple 做出决定时,都能收到通知。
每个请求对应一个案例,回复内容和处理结果集中展示在一处。
按应用和产品维度,提供退款率、成功率及退款原因方面的统计报表。
完整的审计记录,记录是谁(或什么系统)在何时发送了哪条回复。
由你自己掌控的规则,这样调整处理逻辑时无需重新部署。
定价
定价方式也各不相同:固定月费、按请求计费,以及按回收金额抽成的模式,分别适用于不同的请求量级。
但有一件事是这些软件都做不到的:阻止退款请求的发生,或是保证 Apple 的最终决定。任何声称能做到这一点的人,都是在推销噱头。
回应 Apple 退款请求的最佳实践
把这份清单贴在你的值班排班表旁边。
为 App Store Server Notifications V2 注册一个生产环境服务器 URL,并在它长时间无响应时设置提醒。
在每一笔购买上都设置 appAccountToken。一笔都不能漏。
记录交付情况时附上时间戳和结果,再加上那几个能够说明"用户确实用了它"的使用事件。
现在就把共享使用数据的同意条款写进你的用户协议中。
在 12 小时内回复每一个请求,包括那些回复内容就是"批准退款"的请求。
只有当数据能够支撑时,才选择 DECLINE。Apple 会留意其中的模式。
每收到一个 REFUND 通知,都在当天撤销相应的访问权限。
每月检查一次,你实际回复了多少比例的请求。这个数字对退款率的影响,比任何其他因素都大。
Apple 退款管理软件值得使用吗?
在请求量较低的情况下,可能并不值得。但一旦请求量超出一个人能够稳定应付的范围,或者开始频繁出现在工作时间之外,能够自动回复的软件通常就能物有所值。
如果要从这一切中提炼出一条习惯,那就是:在时间耗尽之前,用真实数据回复每一个请求。Dipsea 是一款订阅制音频应用,在开始回复请求之后,大约两周内,其退款率就从 3% 降到了 1.9%,而且从未要求 Apple 拒绝任何一笔退款。那些始终保持沉默的应用,永远不会知道自己本可以保住多少本该属于自己的收入。
常见问题
指客户通过 reportaproblem.apple.com(通常如此)向 Apple 申请退还某个应用或应用内购买项目的款项。Apple 会告知客户预计在 24 到 48 小时内得到答复。对于消耗型项目和订阅,Apple 会先向开发者询问相关信息。
验证通知内容,在你自己的记录中找到该笔购买,核查交付和使用情况,选择一个处理意向,并在 12 小时内调用 Apple 的 Send Consumption Information 端点。之后,再根据 Apple 的最终决定采取相应行动。
不能。你可以告知 Apple 你更希望该请求被拒绝,并提供相应数据作为支持。但最终决定权仍在 Apple 手中,而且 Apple 确实会在开发者要求拒绝的情况下,照样批准退款。
五项信息:客户是否同意共享数据、该购买项目是否已交付、已使用了多少、客户此前是否获得过免费样品或试用,以及你的退款处理意向。这就是目前完整的请求内容。
从收到 CONSUMPTION_REQUEST 起算的 12 个小时。Apple 表示,如果你希望自己的数据被纳入决策考量,就应在这个时间窗口内作出回复。



