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

现在每一笔 Apple 退款请求都附带一个理由,而 consumptionRequestReason 就是你读取它的方式

自 WWDC24 起,每一个 Apple CONSUMPTION_REQUEST 都携带一个 consumptionRequestReason,也就是客户自己陈述的退款原因。它有五个取值,从 UNINTENDED_PURCHASE 到 LEGAL,每一个都应当改变你在 12 小时窗口内所回复的内容。下面讲清楚如何读懂每一个。

一部智能手机放在深色桌面上,显示订阅付款界面,旁边是一张空白纸质标签,展示现在随每一次消费请求一起到达的 Apple 退款请求理由

要点

  • 自 App Store Server Notifications 2.11 版本(在 WWDC24 上宣布)起,每一个 CONSUMPTION_REQUEST 通知都包含 consumptionRequestReason,这是一个字符串,说明客户为何请求退款。
  • 取值恰好有五个:UNINTENDED_PURCHASE、FULFILLMENT_ISSUE、UNSATISFIED_WITH_PURCHASE、LEGAL 和 OTHER。Apple 每次请求发送其中一个。
  • 理由并不决定退款结果。它是你用来选择 refundPreference 和消费数据的背景信息,需在 12 小时窗口关闭前完成。
  • 现在 CONSUMPTION_REQUEST 对自动续订订阅也会触发,而不仅是消耗型商品,因此 consumptionRequestReason 覆盖的退款范围远比 WWDC24 之前更广。
  • FULFILLMENT_ISSUE 这一理由是一个信号,说明可能是你自己的交付出了问题。对它提出异议会耗尽窗口,并可能在日后招致拒付。批准它通常是更省钱的答案。
  • 你在 12 小时内通过调用 Send Consumption Information 来回复,将 customerConsented 设为 true,并将 refundPreference 设为 GRANT_FULL、GRANT_PRORATED 或 DECLINE。Apple 把你的偏好视为一项输入,而非一道命令。
  • 退款仍会让你损失购买行为已经消耗掉的算力、API 调用、存储和分成。理由字段让你只在值得防守的案例上投入防守资源。

Apple 改变了退款请求到达你服务器的方式,而很多开发者从未察觉。自 WWDC24 上宣布的 App Store Server Notifications 2.11 更新起,每一个 CONSUMPTION_REQUEST 通知都携带一个名为 consumptionRequestReason 的字段。它是客户自己陈述的退款理由。一个纯文本字符串,五种可能取值,随附在你本就有十二小时时间去回复的同一份负载中。

Apple 退款请求理由本身并不决定任何事。它的作用是告诉你,你正身处五种截然不同的情形中的哪一种,从而让你不再对一笔应当批准的退款和一笔应当抗辩的退款发送同样通用的消费数据。下面讲清楚这个字段是什么、Apple 可以发送的确切取值、每一个取值意味着什么,以及它应当如何改变你所回复的偏好和证据。

consumptionRequestReason 究竟是什么

consumptionRequestReason 是 CONSUMPTION_REQUEST 通知 data 对象中的一个字符串字段。Apple 在 App Store Server Notifications 2.11 版本中加入了它,与 WWDC24 对退款流程的改动同步推出。在此之前,请求随附已签名的交易到达,却不带任何动机信息。你只能盲目回复。如今客户陈述的理由随请求一同抵达。

请仔细品味“陈述”这个词。这是客户在向 Apple 提交时所选择的理由,并非 Apple 核实过的事实。UNINTENDED_PURCHASE 并不能证明该购买未被使用,UNSATISFIED_WITH_PURCHASE 也不能证明产品有缺陷。这个取值是一副镜片,不是一份裁决。你仍需将它与自己的交付和使用记录相互印证。

它搭载在你已经处理的通知里

CONSUMPTION_REQUEST 是 Apple 唯一会向开发者索要证据的流程。它在 Google Play 中的对应物是通过 orders.reviewrefund 进行的拒付审查。当一个请求到达时,你有 12 小时时间通过调用 Send Consumption Information 来回复,那是对交易消费端点发起的一次 PUT。consumptionRequestReason 现在已是同一份通知的一部分,因此没有任何新东西需要订阅。如果你已经在解析 CONSUMPTION_REQUEST,这个理由只是一个你多半一直忽略的字段。

五个理由,以及每一个在告诉你什么

Apple 明确记录了恰好五个取值。每次请求到达一个。下面是完整清单,以及在实践中如何读懂每一个。

取值客户所陈述的内容它对你通常意味着什么
UNINTENDED_PURCHASE他们并非有意购买往往是误触或家庭成员误点。在决定前先核查交付和消费情况。
FULFILLMENT_ISSUE他们无法收到或使用矛头指回你自己的交付。在提出异议前先核实你的日志。
UNSATISFIED_WITH_PURCHASE他们对其不满意买家后悔。你的消费证据在此处分量最重。
LEGAL他们援引了法律理由按批准处理。为一项法律请求抗辩不值得耗费这个窗口。
OTHER上述之外的任何理由本身不带信号。回退到你的交付和使用数据。

UNINTENDED_PURCHASE 是误触这一类

这是家长在孩子买了 10,000 枚金币之后所选择的理由,或者是某个成年人手误点了确认。它与从未被打开或使用的购买相关联。这正是你自己的数据为何重要的原因。如果你的记录显示该消耗型商品已被完整交付并被大量消耗,那么“非有意购买”的主张与已被花光的余额并不吻合,而这道落差值得通过 consumptionPercentage 上报。

FULFILLMENT_ISSUE 把矛头指回你

FULFILLMENT_ISSUE 是唯一一个部分关乎你的应用、而非客户的理由。它意味着他们说自己无法收到或使用其付费所购之物。在你条件反射式地提出异议之前,先调出你的交付日志。如果你自己的服务器显示权益从未激活、或额度从未入账,那么客户是对的,而 DECLINE 就是错误的偏好。对一次真实的交付失败进行抗争,既浪费窗口,又可能把客户推向其银行,而在那里一次拒付的代价会比原本的退款更高。

UNSATISFIED_WITH_PURCHASE 是证据说了算的地方

这是普通的买家后悔,也是你的消费数据发挥最大作用的理由。产品是好用的。客户使用了其中一部分或全部,如今想要退款。一个高 consumptionPercentage、一个诚实的 DELIVERED 的 deliveryStatus,以及一个 DECLINE 或 GRANT_PRORATED 的 refundPreference,正是 Apple 要你陈述的案情。发送数字,而不是一番争辩。

LEGAL 和 OTHER

LEGAL 意味着客户援引了某项法律或监管权利。明理之人也会有分歧,但作为通则,这不是打官司的窗口。批准它,然后继续前行。OTHER 是 Apple 在所陈述理由无法归入上述四者中任何一个时所使用的兜底项。它本身不带任何信号,因此对待一个 OTHER 就应当完全等同于对待一个毫无理由的请求:以你的交付状态和使用证据为先。

五张空白的折叠卡片在深色桌面上呈扇形展开,旁边放着一部手机,代表客户可以发送的五个 consumptionRequestReason 取值

理由如何逐字段改变你的回复

你通过调用 Send Consumption Information 并附上一个 ConsumptionRequest 主体来回复 CONSUMPTION_REQUEST。理由应当塑造该主体中的三个字段。

customerConsented 必须为 true

只有当 customerConsented 为 true,即客户同意分享消费数据时,Apple 才接受该提交。如果你没有取得该同意,那么无论理由如何,你根本无法发送任何数据。没有同意,就没有证据,请求会在没有你的数字的情况下被裁决。

deliveryStatus 和 consumptionPercentage 承载事实

deliveryStatus 说明你是否交付了一个可用的购买。如果它是 DELIVERED 之外的任何值,Apple 要求 consumptionPercentage 为 0。当你确实交付了时,consumptionPercentage 是一个以 milliunits 表示、从 0 到 100,000 的整数,其中 100,000 表示客户使用了整笔购买。这一对是你事实层面的核心,也正是应当承载一个 FULFILLMENT_ISSUE 或一个 UNSATISFIED_WITH_PURCHASE 案情的东西,而非理由本身。

refundPreference 是你唯一的杠杆

refundPreference 是你陈述所求的地方。Apple 记录了三个取值:GRANT_FULL、GRANT_PRORATED 和 DECLINE。读懂理由,将它与你的数据权衡,然后做出选择。日志中显示交付失败的 FULFILLMENT_ISSUE 倾向于 GRANT_FULL。产品已被完整消耗的 UNSATISFIED_WITH_PURCHASE 倾向于 DECLINE 或 GRANT_PRORATED。LEGAL 倾向于 GRANT_FULL。

一笔退款究竟让你付出多少

理由字段之所以重要,是因为一笔退款很少仅仅是那笔销售从你的账本上抹去。对于一个已经跑过的消耗型商品,你为兑现它付出了成本。一个调用了付费推理 API 的额度包、一批烧掉了 GPU 时间的生成图像、一份占着你存储账单的已存导出文件、一笔你已经付出的创作者分成:当购买被撤销时,这些成本仍是花掉的。商店退还客户的钱。它不退还你的算力。

这正是为什么理由值得一读。假设一位客户购买了 5,000 个各自触发一次付费 API 调用的额度,花掉了其中 4,000 个,然后以 UNSATISFIED_WITH_PURCHASE 提交。你的 deliveryStatus 是 DELIVERED,你的 consumptionPercentage 是 80,000 milliunits,而一个 DECLINE 或 GRANT_PRORATED 偏好,就是自己吞下这笔 API 账单与追回其中大部分之间的差别。现在把理由翻转为 FULFILLMENT_ISSUE,并附上显示额度从未入账的日志,那么诚实且更省钱的做法就是在客户升级到其银行之前选择 GRANT_FULL。

读懂理由而不反应过度

陷阱在于把理由当作证据。UNINTENDED_PURCHASE 不是对产品未被使用的招供,LEGAL 也并不总是一项真正的法律主张。理由缩小了情形的范围。是你的交付日志和消费记录做出定论。当它们与客户一致时,尽早且低成本地批准。当它们与客户相矛盾时,那份矛盾,以 deliveryStatus 和 consumptionPercentage 表达出来,就是你能发送的最有力的东西。RefundHalt 会在每一个 CONSUMPTION_REQUEST 上读取 consumptionRequestReason,并自动将它与你真实的使用数据相配对,从而让每一个理由在 12 小时窗口内都得到它应得的回应。

这个改动很小、很容易被忽略,但它把退款这场对话推向了对你有利的一方。Apple 现在会在你回复之前告诉你原因。用好它。

常见问题解答

consumptionRequestReason 是什么?
consumptionRequestReason 是 Apple 在每一个 CONSUMPTION_REQUEST 通知中都包含的一个字符串字段,于 WWDC24 在 App Store Server Notifications 2.11 版本中加入。它陈述客户自己请求退款的理由,在你于 12 小时窗口内用消费数据回复之前给你提供背景。
consumptionRequestReason 有哪些可能取值?
共有五个:UNINTENDED_PURCHASE、FULFILLMENT_ISSUE、UNSATISFIED_WITH_PURCHASE、LEGAL 和 OTHER。Apple 每次退款请求恰好发送一个。每一个都指向一种不同的情形,从误触到陈述的法律理由,且每一个都应当塑造你所回复的 refundPreference 和消费数据。
退款理由决定我是否能留住这笔钱吗?
不。consumptionRequestReason 是背景,不是裁决。退款仍由 Apple 决定,它会权衡你的 refundPreference、你的 deliveryStatus 和 consumptionPercentage 以及客户的历史。理由告诉你该陈述哪种案情。是你的交付和使用数据把它陈述出来。
我有多长时间回复一个 CONSUMPTION_REQUEST?
从收到 CONSUMPTION_REQUEST 通知起,你有 12 小时时间去调用 Send Consumption Information。该调用必须把 customerConsented 设为 true,否则 Apple 会拒绝它。错过窗口,退款就会在没有你任何数据的情况下被裁决。
consumptionRequestReason 会出现在订阅退款上吗?
会。那次加入 consumptionRequestReason 的同一次 WWDC24 更新,也开始对自动续订订阅发送 CONSUMPTION_REQUEST,而不仅是消耗型商品。对大多数应用来说,这意味着理由字段如今覆盖了财务上最重要的那些退款。

来源和延伸阅读

RefundHalt

App Store 和 Google Play 退款自动驾驶

继续阅读

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

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