App Store Refund Management

Apple CONSUMPTION_REQUEST 详解:面向 App 开发者的退款流程分步指南

了解 Apple 的 consumption_request 如何帮助 App 开发者管理退款请求、回应 Apple,并简化退款流程。

5 min read
Apple CONSUMPTION_REQUEST 详解:面向 App 开发者的退款流程分步指南

设想这样一个场景:一位客户购买了你的年度套餐,使用了一周后,就向 Apple 申请退款。你是在收到的打款金额变少时才发现这件事的。似乎没有人问过你任何问题。但事实并非如此。

实际上,Apple 常常会征询你的意见。它会向你的服务器发送一条名为 CONSUMPTION_REQUEST 的消息,想要了解客户到底是如何使用所购买内容的。如果你的服务器没有在监听,Apple 就会在没有你参与的情况下做出决定。本指南将逐步讲解面向开发者的 App Store 退款流程,并指出大家容易卡住的地方。如果想更全面地了解 iOS 上的退款应对策略, RefundSensor 的 App Store 退款应对页面也对此做了介绍。

快速解答

CONSUMPTION_REQUEST 通知是 Apple 在客户申请退款时,向你索取使用情况详情的一种方式。如果客户同意分享数据,你的服务器应在 12 小时内调用 Send Consumption Information API,并报告交付情况和使用情况。Apple 会权衡这些信息并做出最终决定。你无法批准退款,也无法保证最终结果。

什么是 Apple CONSUMPTION_REQUEST?

CONSUMPTION_REQUEST 是 App Store Server Notifications V2 中的一种通知类型。只要客户发起退款申请,Apple 就会发送该通知,它涵盖所有产品类型:消耗型项目、非消耗型项目、非自动续期订阅,以及自动续期订阅。

可以把它看作一个问题,而不是一道指令。Apple 并不是在告诉你要给谁退款,而是在询问你都知道些什么。最终决定仍由 Apple 做出,你的回答只是它参考的众多因素之一。

Apple 退款流程是如何运作的

这里发生了两件事,而人们常常把它们混为一谈。收到通知是自动发生的;而回传使用情况信息,则只有在你的服务器主动去做时才会发生。

  1. 客户向 Apple 申请退款。

  2. Apple 向你的 V2 通知 URL 发送一条 CONSUMPTION_REQUEST。

  3. 你的服务器核实该客户是否同意分享使用数据。

  4. 如果客户同意,你的服务器会在 12 小时内发送使用情况详情。

  5. Apple 做出决定。如果批准退款,随后会发送一条 REFUND 通知。

分步实施指南

下面是从头到尾的完整设置流程。

  1. 添加你的通知 URL。 在 App Store Connect 中,输入你服务器的 HTTPS URL,并选择 Version 2。

  2. 快速响应。 返回一个介于 200 到 206 之间的状态码。返回 40x 或 50x 会导致 Apple 重试。

  3. 校验签名。 V2 载荷是经过签名的。在读取其中任何内容之前,先进行校验。

  4. 找到对应客户。 将该笔交易与你自己数据库中的用户进行匹配。

  5. 核实同意情况。 没有同意,就不要回应。

  6. 调用 API。 通过 App Store Server API 请求发送数据,并使用 App Store Connect 中的 In-App Purchase 密钥进行身份验证。

  7. 记录日志。 保留你发送了什么内容、以及发送时间的记录。

作为开发者,如何回应 Apple 的退款请求

始终从核实同意情况开始。之后,如实告诉 Apple 实际发生了什么。这里的价值在于具体、诚实的数据,所以不要注水。

来看两个例子。

  • 一名玩家购买了一个金币礼包,并在一天内用掉了其中大部分。如实报告这种高使用量。要求 Apple 拒绝退款,是一个合理的偏好选择。

  • 一名订阅用户购买了一年的服务,但你的服务器出现了宕机,内容始终无法加载。如实报告这种未交付的情况。在这种情况下,批准退款可能才是诚实的答案。

你所提交的退款偏好只是一种建议,Apple 并没有义务遵从它。

Apple Send Consumption Information API 详解

Send Consumption Information 接口是一个与交易 ID 绑定的 PUT 请求(/inApps/v2/transactions/consumption/{transactionId})。你需要在收到 CONSUMPTION_REQUEST 之后调用它,而 Apple 希望在 12 小时内收到回应。

请求体是一个 ConsumptionRequest 对象,包含五个字段:

  • customerConsented:客户是否同意分享数据?该字段必须为 true,否则 Apple 会以 HTTP 400 错误拒绝此次调用。

  • deliveryStatus:你的 App 是否成功交付了可用的购买内容?

  • sampleContentProvided:你是否事先提供了免费样品或试用?

  • consumptionPercentage:使用了多少,以千分之一为单位表示。

  • refundPreference:你希望得到的处理结果。

有几条规则容易让人踩坑。如果 deliveryStatus 不是 DELIVERED,就要把 consumptionPercentage 设为 0,否则请求会失败。对于带有 GRANT_PRORATED 的自动续期订阅,不要填写 consumptionPercentage,因为 Apple 会自行计算。而同意情况的核实责任在于你自己。Apple 还明确表示,不应使用 App Tracking Transparency 弹窗来获取该同意。

App Store Server Notifications V2 集成

App Store Server Notifications V2 是 Apple 用来触达你服务器的方式。你需要准备一个支持 TLS 1.2 或更高版本的安全 HTTPS URL。

CONSUMPTION_REQUEST 只是众多通知类型之一。其他类型,比如 REFUND 和 REFUND_REVERSED,会告诉你一个案例最终是如何结束的。为每种类型分别编写处理逻辑,这样退款相关代码就不会和续订相关代码纠缠在一起。想看看 App Store Connect 这一侧具体是怎么操作的吗? Refund Sensor 的 Apple 设置指南介绍了密钥与通知 URL 的配置方法。

应避免的常见错误

  • 仅仅停留在收到通知这一步。 在你的服务器回传数据之前,CONSUMPTION_REQUEST 不会产生任何实际作用。

  • 忽视同意情况。 客户未同意,就不应回应。

  • 错过 12 小时的时限。 这些通知常常在深夜和周末到达。使用队列机制,并设置提醒。

  • 发送不合理的字段组合。 在一笔未交付的购买上填写使用百分比,会导致请求失败。

  • 跳过签名校验。 先校验,后信任。

  • 响应过慢。 应尽快返回成功状态码,把繁重的处理放到后台进行,否则 Apple 会不断重试。

  • 找不到对应用户的办法。 如果你无法把一笔交易关联到具体客户,那你就没有真正能上报的内容。

如何实现 App Store 退款流程的自动化

没有人愿意手动盯着这 12 小时的倒计时。如果你想实现 App Store 退款流程的自动化,可以把工作拆分成以下几个小步骤:

  1. 接收通知并立即返回成功状态码。

  2. 将该事件放入队列中。

  3. 由一个工作进程(worker)对其进行校验,找到对应用户,并核实同意情况。

  4. 该工作进程根据存储的使用数据构建请求,并调用 API。

  5. 记录结果,如果失败则通知相关人员。

这样你就能获得一致的回应、清晰的审计轨迹,也不必让人半夜三更还醒着处理。你可以自己搭建这一套流程,也可以把这条处理链交给像 RefundSensor 这样的服务。

给开发者的最佳实践

  • 存储真实的使用数据:会话次数、消耗的积分、打开过的内容。没有保存过的数字,你是无法上报的。

  • 在你的条款或新手引导流程中加入明确的同意环节,并记录同意发生的时间。

  • 把你的退款规则一次性写清楚并固化到代码中,而不是每次都逐案判断。

  • 在正式上线前,先用沙箱(sandbox)通知进行测试。

  • 为每笔购买绑定一个账户令牌(account token),以便日后识别买家身份。这篇 appAccountToken 指南介绍了具体做法。

  • 每个月回顾一次退款结果。异常的激增可能指向某个功能出了问题,或者某个付费墙让人感到困惑。

结语

Apple 的退款流程归结起来分为两部分:Apple 发送 CONSUMPTION_REQUEST,而你来决定是否回应。如果客户已同意,就在 12 小时内通过 Send Consumption Information API 发送真实数据。最终决定权仍在 Apple 手中。

一个不错的第一步:确认你的 V2 通知 URL 处于正常运行状态,并且你的服务器能够把一笔交易与某个用户对应起来。这两项检查能为你省去日后不少麻烦。

常见问题

这是当客户申请退款时,Apple 发送的一条 V2 消息。它会向你询问使用情况详情。

Apple 要求你在收到通知后的 12 小时内做出回应。

是的。没有客户同意,就不要回应。如果请求中的 customerConsented 被设置为 true 以外的任何值,该请求都会被拒绝。

不一定。Apple 会利用你提供的数据来辅助决策,但最终决定权在 Apple 手中。

消耗型项目、非消耗型项目、非自动续期订阅,以及自动续期订阅。

#Apple Consumption Request#Apple Refund Workflow#App Store Refund API#Apple In-App Purchases#Consumption Request API#App Developer Guide
Refund SensorRefund Sensor TeamRefund defense for App Store and Google Play developers