所有文章
Playbook阅读需 8 分钟

如果你的 App 仍在使用 App Store Server Notifications V1,Apple 永远不会就订阅退款征询你的意见

Apple 于 2023 年 6 月弃用了 App Store Server Notifications V1,而 V1 从未获得订阅的 CONSUMPTION_REQUEST、REFUND_DECLINED 或 REFUND_REVERSED。本文介绍 V1 服务器会错过什么、代价有多大,以及如何在不漏掉任何一笔退款的情况下迁移到 V2。

一个塞满未拆信件的旧邮箱,旁边是一台现代服务器机架,象征在 App Store Server Notifications V1 上丢失的退款信号

要点

  • Apple 于 2023 年 6 月 5 日弃用了 App Store Server Notifications V1 和 verifyReceipt 端点。两者目前仍可使用,但不再获得任何新功能,也没有公布停用日期。
  • Apple 的 V1 文档只针对消耗型 App 内购买列出 CONSUMPTION_REQUEST。针对自动续期订阅的消耗信息请求于 2024 年 4 月加入 App Store Server Notifications V2。
  • REFUND_DECLINED 和 REFUND_REVERSED 只存在于 App Store Server Notifications V2 中,因此 V1 服务器永远不会得知 Apple 拒绝了退款或撤回了已批准的退款。
  • 在 V1 上,Apple 对自动续期订阅的退款以 CANCEL 送达。在 V2 上则以 REFUND 送达,并在签名交易中附带 revocationDate 和 revocationReason。
  • V2 通知发送失败时,Apple 会在大约一周内重试五次,分别在 1、12、24、48 和 72 小时后。V1 通知失败只会重试三次,分别在 6、24 和 48 小时后,并且无法通过 Get Notification History 找回。
  • App 在 App Store Connect 中切换到 V2 后,新通知会立即以 V2 格式送达,而已在重试中的 V1 通知仍可能在约 78 小时内陆续到达。

App Store Server Notifications 的 Version 1 仍会推送退款,但它缺少了唯一一种能让你为订阅退款据理力争的通知。Apple 于 2023 年 6 月 5 日弃用了 V1,同时弃用的还有 verifyReceipt 端点,此后新增的每一项退款功能都只加入了 V2。如果你的 App Store Connect 设置仍显示 Version 1,Apple 就可以在从未向你的服务器发送 CONSUMPTION_REQUEST 的情况下对订阅退款作出决定。你并不是在这场争论中输了,而是从一开始就没有被邀请参与。

Apple 弃用 App Store Server Notifications V1 意味着什么

弃用并不等于关闭。一位 Apple 工程师于 2023 年 6 月在开发者论坛上写道,verifyReceipt 和 V1 通知会持续可用,直到公布停用日期为止,该日期尚未确定,并且会提前通知开发者。三年多过去了,在设置服务器 URL 时,App Store Connect 仍然提供 "Version 1 (deprecated)" 这一选项。

弃用真正意味着的是冻结。自 2023 年 6 月以来,Apple 通知更新日志中的每一项变更都是 V2 的变更:签名交易中的新字段、新的通知类型,以及 2026 年 4 月加入的 12 个月承诺数据。V1 服务器一样都看不到。

V1 服务器永远收不到哪些退款信号

根据 Apple 针对各版本的文档,同样的退款事件分别以下列方式送达 V1 服务器和 V2 服务器。

退款事件Version 1Version 2
顾客向 Apple 申请消耗型项目退款CONSUMPTION_REQUESTCONSUMPTION_REQUEST
顾客向 Apple 申请自动续期订阅退款V1 文档中未列出CONSUMPTION_REQUEST,自 2024 年 4 月起
Apple 为自动续期订阅退款CANCELREFUND
Apple 为消耗型项目、非消耗型项目或非续期订阅退款REFUNDREFUND
Apple 拒绝顾客在你的 App 内发起的退款不可用REFUND_DECLINED
Apple 撤回已批准的退款不可用REFUND_REVERSED
找回服务中断期间错过的通知不可用Get Notification History

V1 还能收到 CONSUMPTION_REQUEST 吗?

能,但仅限消耗型项目。Apple 的 V1 参考文档将 CONSUMPTION_REQUEST 描述为顾客针对消耗型 App 内购买发起退款申请时发送的通知。一位 Apple 工程师于 2023 年在论坛上确认,V1 的消耗信息请求会在符合条件的退款中触发。缺口在于订阅。Apple 的更新日志显示,订阅的消耗信息请求于 2024 年 4 月 11 日在 V2 中推出,而 Send Consumption Information 文档也说明,Apple 会通过你的 V2 端点发送该请求。

为什么 V1 上的 CANCEL 容易被误读

在 V1 上,当 Apple 为订阅退款时,通知类型是 CANCEL,并且常常伴随 DID_CHANGE_RENEWAL_STATUS。很多服务器会把任何取消都当作顾客关闭了自动续期,于是访问权限会一直保留到当前周期结束。V2 消除了这种歧义。退款以 REFUND 送达,而顾客关闭续期则以 DID_CHANGE_RENEWAL_STATUS 加子类型 AUTO_RENEW_DISABLED 送达。

继续使用 V1 在金钱上的代价

每一笔 App Store 退款都由 Apple 决定。CONSUMPTION_REQUEST 是你的使用数据进入这一决策的唯一途径,Apple 要求你在 12 小时内作出回复。在 V1 上,订阅退款会跳过这一步。

下面用示例数字举例说明。假设你的 App 销售一项每月 $9.99 的订阅,其中包含 AI 图像生成。某位订阅者一个月内生成了 400 张图像,每一次都会产生实际的模型推理成本。随后,他向 Apple 申请退款。

成本项V1 服务器V2 服务器
你在这笔付款中的分成若 Apple 批准则退还若 Apple 批准则退还
当月使用的算力、API 调用和存储已支付,无法收回已支付,无法收回
向 Apple 展示这 400 次生成的机会没有一次 CONSUMPTION_REQUEST,12 小时
得知 Apple 拒绝了退款永远不会REFUND_DECLINED
得知退款已被撤回永远不会REFUND_REVERSED

你损失的是自己的分成,而不是标价。在订阅者付费服务的第一年,Apple 向你支付订阅价格的 70%(扣除适用税费),此后或对于 App Store Small Business Program 的成员则为 85%。算力账单却不会随之减少。推理、第三方 API 调用和文件存储在顾客使用时就已经付过钱了。

缺失的两种结果通知同样会造成损失。没有 REFUND_REVERSED,因退款而撤销访问权限的服务器在 Apple 撤回退款后永远不会恢复权限,于是一位付费顾客被一直挡在门外,只能去联系客服。没有 REFUND_DECLINED,你就无法区分仍在处理中的退款和已被 Apple 拒绝的退款。

一位开发者的双手将网线从旧配线架端口移到新端口,旁边是一台打开的笔记本电脑

如何从 V1 迁移到 V2 而不漏掉任何一笔退款

迁移到 V2 只需修改服务器,再加上一项设置。Apple 在论坛上给出的官方指导来自一位 App Store Commerce 工程师,发布于 2025 年 12 月,解释了切换当天会发生什么。

在切换设置之前先搭建 V2 端点

  • 接受请求正文中携带 signedPayload 的 POST 请求。V2 负载是由 Apple 签名的 JWS,因此在信任其中任何内容之前,请先验证签名。Apple 的 App Store Server Library 可以替你完成这一步。
  • 将原有的 CANCEL 处理逻辑对应到 REFUND,并将 REFUND_DECLINED 和 REFUND_REVERSED 作为新情况处理。
  • 使用 Send Consumption Information 回复订阅的 CONSUMPTION_REQUEST,并且仅在顾客同意与 Apple 共享数据时回复。Apple 表示,未获同意时不应回复。
  • 成功时返回 HTTP 200 到 206。任何 40x 或 50x 都会让 Apple 重试。

在 App Store Connect 中切换设置

在 App Store Connect 中打开你的 App,在 "General" 下选择 "App Information",找到 App Store Server Notifications,将 "Production Server URL" 设置为你的 V2 端点,并选择 Version 2。如果想先测试,可以先对沙盒 URL 做同样的设置,然后用 Request a Test Notification 确认你的服务器能够正常响应。

让 V1 处理程序继续运行约三天

切换之后,新通知会立即以 V2 格式送达,无论新旧订阅皆是如此。已在重试中的 V1 通知会继续以 V1 格式到达,直到成功或重试次数用尽。Apple 表示最后一次可能的 V1 重试约在 78 小时后,即 6 加 24 加 48。请让旧处理程序运行超过这段时间,然后再将其移除。

顺便替换 verifyReceipt

verifyReceipt 也在同一天被弃用。它仍会响应,但 Apple 建议服务器改用 App Store Server API。Get Transaction Info 返回单笔签名交易,Get Transaction History 返回顾客的交易历史,Get Refund History 则列出某位顾客所有已退款的购买项目。配合 V2 通知,这些接口足以覆盖大多数服务器原本使用收据完成的工作,包括过去在收据中标记退款的 cancellation_date 字段。

RefundHalt 接入 App Store Server Notifications V2,并利用你的 App 已经记录的使用数据,在 12 小时时限内回复每一个 CONSUMPTION_REQUEST。如果你仍在使用 V1,切换版本正是让这一切成为可能的那一步。

常见问题解答

App Store Server Notifications V1 会被关停吗?
暂时不会。Apple 于 2023 年 6 月 5 日弃用了 V1 和 verifyReceipt,两者目前仍可使用。Apple 表示尚无停用日期,并会提前通知开发者。在此期间,V1 不会获得任何新功能。
在 V1 上能收到 CONSUMPTION_REQUEST 通知吗?
根据 Apple 的 V1 文档,仅限消耗型项目。针对自动续期订阅的消耗信息请求于 2024 年 4 月加入 V2,Apple 会通过你的 V2 端点发送。如果你销售订阅却仍使用 V1,就无法回复这些退款申请。
订阅退款在 V1 和 V2 上分别是什么样的?
在 V1 上,它以 CANCEL 送达,常常伴随 DID_CHANGE_RENEWAL_STATUS。在 V2 上,它以 REFUND 送达,并在签名交易中附带 revocationDate 和 revocationReason。当 Apple 拒绝在你的 App 内发起的退款时,V2 还会发送 REFUND_DECLINED;当 Apple 撤回已批准的退款时,会发送 REFUND_REVERSED。
从 V1 切换到 V2 时,通知会怎样?
切换后不久,所有订阅的新通知都会以 V2 格式送达。已在重试中的 V1 通知会继续以 V1 格式到达,直到成功或重试次数用尽,Apple 表示这大约持续到切换后 78 小时。在这段时间内,请让两个处理程序同时运行。
切换到 V2 之后还能回到 V1 吗?
可以,按照 Apple 技术说明 TN3180 的描述,通过 App Store Connect API 的 Modify an App 端点实现。Apple 称这属于特殊情况,并且仍将 V1 标记为已弃用,因此回退意味着放弃订阅的消耗信息请求以及较新的退款通知。

来源和延伸阅读

RefundHalt

App Store 和 Google Play 退款自动驾驶

继续阅读

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

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