連環退款濫用讓你損失兩次,以下是應用商店給你的反擊方法
一次又一次申請退款的客戶並非偶然。退款濫用不僅讓你退回金額,還要搭上你已經花掉的算力,而兩大商店都會給你一個身分訊號,即 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,用於一個帳戶下擁有多個設定檔的應用。
| 欄位 | 商店 | 類型與上限 | 由誰設定 | 預設 | 商店如何使用它 |
|---|---|---|---|---|---|
| appAccountToken | Apple | UUID | 你,在購買時 | 未設定 | 把交易綁定到你的使用者,在交易和消耗資料中返回 |
| obfuscatedAccountId | Google 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 Play | voidedReason 取值 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 仍然自己裁定,而透過不可反駁流程到來的濫用不受影響。
資料來源與延伸閱讀
- Apple: appAccountToken (App Store Server API)
- Apple: ConsumptionRequest (App Store Server API)
- Android: BillingFlowParams.Builder.setObfuscatedAccountId
- Android: Fight fraud and abuse (Play Billing security)
- Google Play Developer API: Voided Purchases
- Google Play Billing: Provide refund and chargeback suggestions (Review Refund API)
- Android Developers Blog: Play Commerce prevented over $2 billion in fraudulent and abusive transactions in 2022
- Google Play Console Help: Updates to refund protection and chargeback cost responsibility
RefundHalt
App Store 與 Google Play 的退款自動駕駛
繼續閱讀
過多的退款申請,代價可能遠超退款本身,因為兩大 App 商店都把它視為品質訊號
Apple 審查準則 5.6.4 把過多的退款申請列為 App 未達品質標準的跡象,Google 的開發人員發布協議也允許它依退款率下架新開發人員的 App。本文整理兩家商店的原文、下架的實際成本,以及如何避開風險。
在處理退款之前先驗證 App Store 伺服器通知,因為任何人都能向你的 webhook URL 發送請求
在檢查簽章之前,一則退款通知只不過是一個 HTTPS 請求。本文說明如何驗證 App Store 伺服器通知和 Google Play RTDN 訊息、各商店簽署的內容,以及偽造的退款或遭錯誤拒絕的退款會讓你付出什麼代價。