所有文章
Playbook閱讀時間 8 分鐘

為每一筆 Google Play 購買打上混淆帳戶 id 標記,否則拒付到來時你將無從追溯

Google Play 允許你為每一筆購買蓋上一個穩定的雜湊 id,並在爭議發生時把它讀回給你。設定好它,一次拒付審查就能精確對應到你必須上報其使用情況的那個使用者。跳過它,你就只能在 24 小時的時限內拿著一個孤零零的訂單 id 去猜。

一位開發者的雙手正把一個小小的空白標籤繫到一張紙質購買收據上,旁邊放著一部 Android 手機,象徵為一筆購買蓋上 Google Play 混淆帳戶 id

重點摘要

  • 混淆帳戶 id 是你用 setObfuscatedAccountId 附加到 Google Play 購買上的一串字元。Google Play 會把它與訂單一起儲存,並在之後以 obfuscatedExternalAccountId 的形式回傳,因此一筆購買可以追溯回你系統中發起它的那個使用者。
  • 用 Google 自己的話說,這個欄位讓 Google Play 能夠偵測異常活動,例如短時間內同一帳戶上有許多裝置發起購買。設定它會在交易完成之前,在購買那一刻為 Google 自己的詐欺篩查提供資料。
  • 該識別碼限制為 64 個字元,且不得以明文攜帶個人資訊。Google 表示,在此欄位中儲存電子郵件等 PII 會導致購買被攔截,並建議改用單向雜湊或加密。
  • 當一次銀行拒付需要你審查時,Google Play 會傳送一條 PendingRefundReviewNotification,它指明的是一個訂單,而不是一個人。混淆帳戶 id 就是那把連接鍵,把該訂單對應回你必須上報其使用情況的使用者記錄。
  • 回應一次爭議意味著在 24 小時內呼叫 orders.reviewrefund,攜帶 refundPreference、一個 sampleContentProvided 旗標,以及像 consumptionPercentageMilliunits 和 consumptionUsageEvents 這樣的消耗證據。只有先知道訂單屬於哪個使用者,你才能建構這些證據。
  • 對於在 2026 年 8 月 3 日或之後下單的 Google Play 訂單,一次敗訴的拒付會向開發者收取購買價格減去 Google 服務費,再加上銀行的拒付手續費。一次因為無法識別訂單而無法回應的爭議,如今成了一項直接成本,而不僅僅是一筆流失的銷售。
  • 對每一筆購買都設定該 id,而不只是訂閱,並在伺服器端把它讀回。在用戶端它來自 Purchase.getAccountIdentifiers,在你的後端它是購買記錄上的 obfuscatedExternalAccountId 欄位。

一次 Google Play 拒付審查出現時只報出一個訂單和一個購買權杖。它不會告訴你客戶是誰。如果你從未把自己的識別碼蓋到那筆購買上,你現在就得在 24 小時的時限下,拿著一個孤零零的訂單 id 去和你的使用者表做比對,還得用你可能根本找不到的使用證據來回應。混淆帳戶 id 就是解藥。它是一串你在結帳時附加的短字元,Google Play 會把它與購買一起儲存,之後再交還給你,這樣每一筆訂單都能追溯到發起它的那個確切使用者。下面說清楚這個欄位是什麼、它為何決定了你到底能不能回應一次爭議,以及在一次敗訴拒付已經變成一張帳單的今天,跳過它的代價是什麼。

混淆帳戶 id 究竟是什麼

混淆帳戶 id 是當客戶購買東西時,你傳入 Google Play 計費流程的一個可選字串。你在 BillingFlowParams 建構器上用 setObfuscatedAccountId 設定它,Google 會把它與購買一起儲存。它不是客戶的姓名,不是他們的電子郵件,也不是他們的 Google 帳戶。它是你自己對你自己使用者的識別碼,以一種 Google 可以保存卻無從得知此人是誰的形式寫成。

它是你在結帳時設定的一串字元,而不是一個姓名

用 Google 的話說,setObfuscatedAccountId 指定一個可選的混淆字串,它與你應用中購買者的使用者帳戶唯一關聯。「混淆」這個詞是有實際作用的。Google 不想要你的原始使用者 id,也不想要任何能識別此人的東西。它想要的是一個穩定的權杖,與你這邊的一個使用者一一對應,僅此而已。該欄位限制為 64 個字元,足夠容納一個雜湊,裝不下太多別的東西。

Google 首先為它自己的詐欺篩查讀取它

在對你有用之前,這個欄位先為 Google 做一件事。計費文件說,Google Play 可以使用這個值來偵測異常活動,例如短時間內同一帳戶上有許多裝置發起購買,並且 Google 使用這些資料來偵測可疑行為,並在某些類型的詐欺交易完成之前將其攔截。所以設定它的第一份回報在上游,體現在更乾淨的購買上,以及更少那些日後變成作廢和爭議的詐欺購買上。Google 把混淆帳戶 id 和 Voided Purchases API 一併列為它兩大核心反濫用工具,是有原因的。

為什麼在一次拒付審查到來時它至關重要

一次你能預見的退款很好辦。難辦的是銀行拒付,因為它不是從你的客戶跟你交談開始的。它從銀行開始,Google Play 把它作為一次帶著倒數計時的審查轉交給你。

爭議指明的是一個訂單,而不是一個人

當一位客戶就一筆扣款向他們的銀行發起爭議,而 Google 需要你的意見時,Google Play 會傳送一條 PendingRefundReviewNotification。那條訊息標識的是訂單。它不攜帶你的使用者 id,因為 Google 從來就沒有你的使用者 id。它只有你蓋到購買上的那點東西。如果那是空的,你現在就得拿著一個孤零零的訂單 id 和購買權杖去反查你自己的記錄,寄望於你在購買時記錄了那個權杖,也寄望於比對沒有歧義。如果你設定了混淆帳戶 id,那筆購買就攜帶你自己的雜湊,你一次查詢就能找到使用者,然後轉去建構證據,而不是四處搜尋身份。

orders.reviewrefund 到底向你要什麼

回應爭議意味著在 24 小時內呼叫 orders.reviewrefund 方法。Google 記錄你的第一次呼叫並忽略其餘,所以第一個回答就是唯一的回答。以下是它想要的欄位,而每一個證據欄位都假定你已經知道訂單屬於哪個使用者。

欄位是否必填它攜帶什麼
pendingRefundToken來自你正在回應的那條 PendingRefundReviewNotification 的權杖
refundPreferenceAPPROVE、DECLINE 或 NEUTRAL,你對 Play 是否應退款的建議
sampleContentProvided你是否在購買前提供了免費樣品、試用或該功能的說明
consumptionPercentageMilliunits可選客戶消耗了購買內容的多少,0 到 100,000 milliunits
consumptionUsageEvents可選一系列事件,每一個都是使用者消耗或使用其所購內容的一次實例
一張小小的空白紙質標籤用繩子繫著,擱在一份列印出來的銀行對帳單上,旁邊一部智慧型手機顯示著一份失焦的交易清單,象徵為一筆 Google Play 購買打上標記,以便日後的爭議能被追溯到某個使用者

跳過它究竟要付出什麼代價

在 Google Play 歷史的大部分時間裡,一次你無法辯護的拒付不過是一筆流失的銷售,聳聳肩就過去了。這一點變了。對於在 2026 年 8 月 3 日或之後下單的訂單,一次敗訴的拒付會向開發者收取購買價格減去 Google 服務費,再加上銀行的拒付手續費。那次你無法回應的爭議如今是一個帳目項。

走一遍一筆訂單。一位客戶就一筆 $9.99 的購買向他們的銀行發起爭議。Google Play 發來審查,你有 24 小時。如果你為這筆購買打了標記,你就能找到使用者,看到他們已經消耗了所購內容的大部分,然後以 DECLINE 偏好加上消耗證據來回應 reviewrefund,給了 Google 一個真實的案情去抗辯一次不正當的爭議。如果你沒打標記,你要麼來不及識別訂單,要麼什麼都沒有地去回應,爭議在沒有你這一方聲音的情況下被裁決,而對一筆 8 月 3 日之後的訂單,你要退還 $9.99 減去 Google 的費用,外加一筆固定的銀行拒付手續費,它往往落在接近 $20 的水準。在一筆小額銷售上,僅這筆固定費用就可能大於你淨得的金額。

  • 流失的收益:你在這筆銷售中的淨份額,被反轉。
  • 銀行的拒付手續費:一筆由卡組織設定的固定成本,對在 2026 年 8 月 3 日之後下單的訂單額外收取,而一次普通退款從不攜帶它。
  • 白花的開銷:該帳戶已經用掉的運算、第三方 API 呼叫和儲存,無論你能否回應,都沒了。
  • 你看不見的模式:沒有一個穩定的帳戶 id,你也無法察覺是同一個使用者在一次又一次地發起爭議,於是慣犯式的濫用就讀作互不相關的一次性損失。

如何設定它才不會讓購買被攔截

兩條規則幾乎涵蓋了各團隊在這個欄位上會犯的所有錯誤。給 id 做雜湊,並且到處都設定它。

對你的使用者 id 做雜湊,絕不傳送 PII

不要在這個欄位裡放電子郵件、電話號碼或任何原始的個人細節。Google 明確表示,以明文儲存電子郵件等 PII 會導致購買被攔截,並建議用單向雜湊或加密來產生該值。乾淨的做法是對你的內部使用者 id 做單向雜湊,每次都以相同的方式計算,這樣同一個使用者始終產生相同的 64 個字元的字串。也不要用此人的 Google 帳戶 id 或你的開發者 id。這個值應當只對你的系統有意義。

對每一筆購買都設定它,並在你的伺服器上把它讀回

把這個 id 附加到每一個計費流程,一次性商品和訂閱都一樣,這樣沒有一筆購買是沒有標籤的。購買之後,在兩個地方把它讀回。在用戶端,Purchase.getAccountIdentifiers 回傳一個物件,其 getObfuscatedAccountId 給出你設定的那串字元。在你的後端,伺服器端的購買記錄以 obfuscatedExternalAccountId 欄位攜帶它,而應當信任的是伺服器這一份,因為爭議到達的是你的伺服器,而不是裝置。

當一個帳戶有多個設定檔時使用 setObfuscatedProfileId

如果你的應用允許一個帳戶擁有多個設定檔,比如一個串流家庭或一個有多個角色的遊戲,那麼也一併設定 setObfuscatedProfileId。它是同一類經過雜湊、64 個字元、無 PII 的字串,作用範圍限定到發起購買的那個設定檔。Google 指出,設定設定檔 id 時也要求傳入帳戶 id,所以兩個都傳。結果是一次爭議不僅對應到帳戶,還對應到花了這筆錢的那個確切設定檔。

iOS 上的對應做法,一句話說清

App Store 在另一個名字下有著同樣的思路。在 iOS 上你為一筆購買附加一個 appAccountToken,一個 UUID,它會在交易上回傳,也會在客戶申請退款時 Apple 傳送的 CONSUMPTION_REQUEST 上回傳。問題的形狀在兩個商店上是一模一樣的。爭議或退款流程引用的是一筆交易,而你自己的識別碼就是把它連回一個你能上報其使用情況的使用者的東西。

細節Google PlayApp Store
你設定的欄位透過 setObfuscatedAccountId 設定的混淆帳戶 idappAccountToken
格式雜湊字串,64 個字元,無 PIIUUID
它在哪裡回傳購買上的 obfuscatedExternalAccountId交易上的 appAccountToken
它供給的時窗orders.reviewrefund,24 小時CONSUMPTION_REQUEST,12 小時
你上報什麼消耗百分比和使用事件Apple 的消耗欄位

這些都不難做。它很容易被跳過,因為你寫結帳程式碼的那天不是拒付到來的那天,而跳過它的代價在那之前一直是隱形的。RefundHalt 在兩個商店上設定並追蹤帳戶識別碼,保持購買到使用者的鏈路,讓一次爭議總能落到一個真實的客戶身上,並在各自的時窗內用銷售時記錄下來的消耗證據去回應 Google Play 的 orders.reviewrefund 和 Apple 的 CONSUMPTION_REQUEST。那 24 小時的倒數計時,不是你才發現自己說不出是誰買了這個東西的時刻。

常見問題解答

Google Play 計費中的混淆帳戶 id 是什麼?
它是你用 setObfuscatedAccountId 附加到一筆購買上的一個可選字串,與你應用中購買者的使用者帳戶唯一關聯。Google Play 把它與訂單一起儲存,用它來偵測異常活動,比如許多裝置在同一帳戶上購買,並在之後以 obfuscatedExternalAccountId 的形式回傳給你,這樣你就能把一筆購買連回某個特定使用者。
我可以把使用者的電子郵件或 id 放進混淆帳戶 id 欄位嗎?
不可以。Google 表示,在此欄位中以明文儲存電子郵件等個人身份資訊會導致購買被攔截。請用單向雜湊或加密來產生該值,保持在 64 個字元以內,也不要使用此人的 Google 帳戶 id 或你的開發者 id。
混淆帳戶 id 對 Google Play 拒付有什麼幫助?
一次拒付審查,也就是 PendingRefundReviewNotification,指明的是訂單,而不是你的使用者。混淆帳戶 id 就是那把連接鍵,把該訂單對應到正確的使用者記錄,這樣你就能在 24 小時內用真實的消耗證據回應 orders.reviewrefund,而不必去猜訂單屬於哪個客戶。
我應該在訂閱上設定混淆帳戶 id,還是只在一次性購買上設定?
對每一筆購買都設定它,一次性商品和訂閱都要。任何沒有標籤的購買,都是當一次爭議或作廢到來時你無法追溯到某個使用者的購買,而爭議可以落在任何訂單類型上。
混淆帳戶 id 和混淆設定檔 id 有什麼區別?
帳戶 id 把一筆購買對應到你應用中的一個使用者帳戶。設定檔 id 把它對應到該帳戶內的一個特定設定檔,用於一個帳戶擁有多個設定檔或角色的應用。兩者都是經過雜湊、64 個字元、無 PII 的字串,而且 Google 指出,設定設定檔 id 時也要求傳入帳戶 id。

資料來源與延伸閱讀

RefundHalt

App Store 與 Google Play 的退款自動駕駛

繼續閱讀

下一筆退款申請已經在路上。

讀完另一封關於未能抗辯退款的客服郵件所需的時間,就足夠您設定好 RefundHalt。