所有文章
Playbook阅读需 8 分钟

连环退款滥用让你损失两次,下面是应用商店给你的反击方法

一次又一次申请退款的客户并非偶然。退款滥用不仅让你退回金额,还要搭上你已经花掉的算力,而两大商店都会给你一个身份信号,即 Apple 的 appAccountToken 和 Google 的混淆账户 ID,用来把这种模式串联起来。

昏暗的过闸大厅里,一道旋转闸门被同一个身影反复穿过,用来说明连环退款滥用

要点

  • 只有两种退款流程会允许开发者提交证据来对抗退款滥用,即 Apple 的 CONSUMPTION_REQUEST,窗口为 12 小时,以及 Google Play 通过 Review Refund API 进行的拒付审核,窗口为 24 小时。
  • Apple 的 appAccountToken 是你生成并附加到某次购买上的一个 UUID,StoreKit 会把它与生成的交易绑定,因此你的服务器可以把每一笔退款追溯到做出该购买的确切账户。
  • Google Play 的混淆账户 ID 是一个经过哈希处理的字符串,上限为 64 个字符,Google 自己会用它来检测异常活动,例如短时间内有大量设备在同一账户上购买。
  • 在 Google 的混淆账户 ID 中存放明文个人数据会导致你的购买被拦截,因此该字段必须是加密值或单向哈希,绝不能是原始电子邮箱。
  • Google Play 的 voidedReason 字段会把 friendly_fraud 和 fraud 标记为区别于普通反悔退款(remorse)的原因,这让你可以把重复滥用者引导到审核队列,而不是走自动退款并遗忘的路径。
  • Google 表示它在 2022 年拦截了超过 20 亿美元的欺诈和滥用交易,而支撑这套系统的身份字段只有在你为每一笔购买都填充它们时才会生效。
  • 每一笔仍保留访问权限的已退款购买,都是你在已经退回的钱上继续支付的算力、存储和 API 开销,而连环退款者会故意让这笔账单成倍增长。

单笔退款是做生意的成本。同一个账户在每次都用掉所购内容后第四次退款,那就是退款滥用,而这种模式你只有在每一笔购买都带有你所掌控的身份时才能看见。Apple 和 Google 都会给你这个身份,也都会在退款或拒付被裁定之前,给你一个很窄的窗口把身份摆在商店面前。错过窗口,或者从未附加身份,一个连环退款者看起来就和第一次不满意的客户一模一样。下面讲的就是如何区分他们,以及这种区别在金钱上值多少。

为什么退款滥用是身份问题,而不是退款问题

退款由商店裁定。你无法阻止客户提出申请,在大多数流程里你也无法阻止商店批准。你能做的,是判断某个账户以前是否做过同样的事,以及它所购买的内容是否真的已被交付和使用。这两点都是关于身份的问题:你的哪位用户是这笔交易背后的人,他们的历史又是怎样。如果你的购买没有携带一个能追溯到你自己用户记录的稳定标识符,你就无法回答这两个问题,每一笔退款都毫无上下文地到来。

这才是真正的缺口。退款机制由政策固定。而你带到它面前的证据完全由你自己构建,它始于购买的那一刻,而不是退款的那一刻。

证据能改变结果的两个窗口

只有两种流程里,你所发送的任何内容都能影响裁定。当客户对消耗型商品或自动续订订阅申请退款时,Apple 的 CONSUMPTION_REQUEST 会触发,你有 12 小时来作答。当用户向银行争议某笔扣款时,Google Play 的拒付审核会触发,你有 24 小时通过 Review Refund API 作出回应。其他每一种退款,包括 48 小时的 Play 自助退款、客服批准的退款、未确认购买的自动退款,都是在没有你参与的情况下裁定的。

当交易本身已经带有你的标识符时,这两个证据通道都会强得多。Apple 的消耗信息可以在账户历史和消费额之外包含 appAccountToken,而 Google 的审核可以依托它自购买以来一直在观察的混淆账户 ID。一个没有标识符的账户,就是一个没有历史可提交的账户。

两个身份字段,并排来看

Apple 和 Google 用几乎相同的方式解决了同一个问题,只是名称不同、规则不同。两者都让你给一笔购买盖上一个指向你自己用户记录的值。两者默认都不开启。如果你不在购买时设置,两者都毫无用处。

Apple:appAccountToken

appAccountToken 是你在购买开始时生成并传入的一个 UUID。StoreKit 会把它与生成的交易关联起来,它会出现在你的服务器验证的交易数据里,也会出现在你在 CONSUMPTION_REQUEST 期间回传的消耗信息里。因为它是你自己的值,所以它把一笔商店交易直接映射到你数据库里的账户,不涉及任何电子邮箱或姓名。它必须是一个真正的 UUID,其他任何东西都会被拒绝。Apple 后来还新增了一个 Set App Account Token 端点,可以在过去的交易上附加或更新该令牌,包括在你应用之外发生的购买,例如优惠代码兑换。

Google Play:混淆账户 ID

Google 的对应物是 setObfuscatedAccountId,一个与购买账户绑定的可选字符串。Google 自己的文档对它的用途说得很直白:Google Play 用它来检测异常活动,例如短时间内有大量设备在同一账户上进行购买,并在一些欺诈交易完成之前将其拦截。它限制在 64 个字符以内,并且不能携带明文个人数据。在那里存放原始电子邮箱,Google 会直接拦截这笔购买,因为该字段期望的是加密值或单向哈希。还有一个同类字段 setObfuscatedProfileId,用于一个账户下拥有多个档案的应用。

字段商店类型与上限由谁设置默认商店如何使用它
appAccountTokenAppleUUID你,在购买时未设置把交易绑定到你的用户,在交易和消耗数据中返回
obfuscatedAccountIdGoogle Play哈希字符串,最多 64 字符你,在购买时未设置检测异常活动,并在完成前拦截部分欺诈

一次来自连环滥用者的退款究竟要付出什么代价

退款本身是这笔账单里最小的一部分。当商店批准一笔退款时,你退回了收入,这部分在账本上是看得见的。而退款那一行看不到的,是你为交付如今变得免费的产品所花的一切。

设想一个会触发真实工作的消耗型商品:一次图像生成、一批发往模型提供方的 API 调用、一次视频导出、一笔付给创作者的款项。客户使用的那一刻,你就已经为那份算力付了钱。退款把价格追回,但它追不回提供方的账单。一个连环退款者,就是那个已经学会内容能在退款后依然留存的人,于是他们再跑一遍这个循环:购买、消耗、退款、重复。每一轮,你都要第二次吃下交付成本。

然后还有商店自身的成本转移。从 2026 年 8 月 3 日起,对于此日期之后下的订单,Google Play 会把购买价格和银行的拒付手续费转移到开发者身上。一笔过去主要是 Google 的问题的拒付,如今变成你的收入加上一笔手续费,而一个反复扣款的人每一次都会抬高这个数字。身份字段正是让你能够在 24 小时窗口内,向 Review Refund API 提供证据以反驳非法争议的东西。

Google 把规模说得很直白:它表示自己在 2022 年拦截了超过 20 亿美元的欺诈和滥用交易。那个数字之所以存在,是因为那些信号,其中就包括混淆账户 ID,都被填充了。一个带着空身份字段发货购买的应用,等于主动放弃了那份保护。

在一块发光的玻璃传感器上读取指纹,用来说明商店身份字段如何把一笔购买追溯回退款滥用背后的账户

如何在商店裁定之前抓住重复退款者

用你自己掌控的身份给每一笔购买打标签

在每一笔 StoreKit 购买上设置 appAccountToken,在每一笔 Play Billing 购买上设置 setObfuscatedAccountId,两者都从你自己的用户记录生成。在 Apple 上,使用一个映射到该账户的真正 UUID。在 Google 上,对账户键做哈希,这样就没有个人数据以明文形式传输。要在购买时就这么做,因为在 Google 上这是你事后无法补救的一步。

保存一份以该身份为键的账本

把每一次购买、交付、消耗事件和退款都对着这个标识符记录下来。当一个 CONSUMPTION_REQUEST 或一次拒付审核到来时,该账户的完整历史,包括此前的退款,只需一次查询就能拿到。Apple 的消耗信息里有专门为此设置的字段:consumptionStatus、deliveryStatus、playTime、accountTenure、lifetimeDollarsPurchased,以及你的 refundPreference。

读取 voidedReason,并对滥用者做不同的路由

当一笔 Google 购买被作废时,voidedReason 字段会告诉你原因,而 friendly_fraud 和 fraud 是区别于普通反悔退款(remorse)的独立取值。把这些引导到审核队列和更严格的政策上,而不是走和首次退款相同的自动路径。Google 自己的指引是一种多次犯规模型:对初犯者发出警告,对重复者采取更坚决的行动,并对屡教不改的账户禁用购买。

每一次都在窗口内作答

证据只有在这两个窗口内才算数。把 CONSUMPTION_REQUEST 的回应自动化,让它在 12 小时内充分提前触发,把拒付审核自动化,让它在 24 小时内触发。一份你提交迟了的完美历史,就是一份商店永远不会读到的历史。

你想抓住的信号它在哪里让它浮现的字段或流程
同一账户、大量设备、短时间窗口Google Play混淆账户 ID 的异常活动检测
这个账户以前退过款你的账本以 appAccountToken 或混淆账户 ID 为键的历史
内容已交付并被消耗Apple消耗信息中的 deliveryStatus 和 consumptionStatus
一次争议其实是第一方欺诈Google PlayvoidedReason 取值 friendly_fraud

商店会为你做什么、不会为你做什么

值得把这种分工说清楚,因为人们很容易以为商店会处理滥用,而在它们不处理时,它们大多也不会告诉你。Google 会主动使用混淆账户 ID,在一笔购买完成之前拦截部分欺诈,它的系统在平台层面拦下了很大一部分。Apple 会自己裁定每一笔退款,并把你的消耗信息当作一个输入,而绝非一张选票。两家商店都不会替你维护滥用者名单,不会从你的余额里扣掉一个已退款的消耗型商品,也不会替你对一个重复退款者说不。身份在边缘处由商店去处理,在其他所有地方则由你去处理。

这也正是 RefundHalt 把一切都以购买身份为键的原因:同一个账户的一次退款、一次拒付审核和一次消耗请求都会归结到同一份历史上,于是一个连环退款者在他们第一次重复时就会作为一个模式浮现出来,而不是等到你已经付掉第四张账单之后。

常见问题解答

应用中的退款滥用是什么?
退款滥用是指客户在收到并使用所购内容后反复申请退款,从而既留住内容或权益,又把钱拿回去。在应用商店上,它通常表现为同一个账户一次又一次地对消耗型商品或订阅退款,或者表现为第一方欺诈(friendly fraud),即向银行争议一笔合法的扣款。
我该如何把一笔应用内购买关联到特定用户?
在 Apple 上,生成一个 UUID,并在购买开始时把它作为 appAccountToken 传入,StoreKit 会把它绑定到交易,并在交易和消耗数据中返回它。在 Google Play 上,调用 setObfuscatedAccountId,传入一个与账户绑定的哈希值。两者都能在不暴露个人数据的情况下,把一笔商店交易映射到你自己的用户记录。
Apple 或 Google 会告诉我某个账户是重复退款者吗?
不会直接告诉你。Google 会用混淆账户 ID 来检测异常活动,并在购买前拦截部分欺诈,Apple 会让你在消耗请求期间提交账户历史,但两家商店都不会递给你一份重复退款者名单。那份名单要你自己用以身份字段为键的账本来构建。
为什么我设置了账户 ID,Google 却拦截了我的购买?
因为混淆账户 ID 不能包含明文个人数据。在其中存放诸如原始电子邮箱地址之类的东西,会导致 Google Play 拦截这笔购买。请使用加密值或单向哈希,并把它控制在 64 个字符的上限之内。
通过消耗请求反驳退款能阻止滥用吗?
它可以减少滥用。CONSUMPTION_REQUEST 是仅有的两种能让你的证据在商店裁定之前到达商店的流程之一,账户历史加上交付和消耗数据能帮助 Apple 识别退货滥用和第一方欺诈。不过它并不是一种拦截。Apple 仍然自己裁定,而通过不可反驳流程到来的滥用不受影响。

来源和延伸阅读

RefundHalt

App Store 和 Google Play 退款自动驾驶

继续阅读

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

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