所有文章
Deep dive閱讀時間 8 分鐘

三天內不確認 Google Play 購買,Google 就會退款,這會讓你付出什麼代價

只要你的伺服器在三天內沒有確認某筆購買,Google Play 就會自動退款並撤銷這筆購買。這是整合失誤,不是客戶的決定,而且完全可以避免。下面講清楚具體規則、它為什麼會觸發,以及每一筆流失的銷售真正的代價。

一個沙漏在智慧型手機旁流盡,說明在 Google Play 購買被自動退款之前,你只有三天時間去確認它

重點摘要

  • 如果你的應用程式在三天內沒有確認購買,Google Play 會自動向買家退款並撤銷這筆購買。這是整合失誤,不是客戶的決定,而且完全可以在伺服器端避免。
  • 三天倒數計時從購買狀態變為 PURCHASED 時開始,而不是從結帳開始時。停留在 PENDING 的購買還沒有啟動倒數計時,此時絕不能去確認它。
  • 兩種呼叫都能滿足要求。透過 purchases.products.consume 消耗一件消耗型商品,以及透過 purchases.products.acknowledge 或 purchases.subscriptions.acknowledge 確認一件非消耗型商品或訂閱,兩者都算作確認。
  • 只有首次訂閱購買需要確認。續訂不需要,Google 會自動將它們標記為 ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED。
  • 時長短於一週的預付費方案,必須在方案時長一半的時間內確認,這個期限比標準的三天更緊。
  • 退款追回的是銷售價格,但你在交付產品時已經花掉的運算、模型 API 呼叫、儲存和創作者分潤並不會退還給你。你損失的錢比帳面上那一項要多。
  • Apple 沒有對應機制。一筆未完成的 StoreKit 交易會被反覆重新投遞,直到你完成它,但 Apple 絕不會自動退款。這種故障模式只存在於 Google Play。

一位客戶購買了你的產品,扣款成功,三天後 Google Play 悄悄退了款,並收回了你已經交付的東西。沒有人要求這筆退款。客戶沒有申請,也沒有任何客服人員核准過。它之所以觸發,是因為你的伺服器從未告訴 Google 這筆購買已被處理。如果你沒有在三天內確認一筆 Google Play 購買,Google 每次都會向買家退款並撤銷購買。這是兩大商店裡為數不多、完全由你的整合來預防的退款之一,也是最悄無聲息的營收流失方式之一。

這不是詐騙問題,也不是政策爭議。它只是一個漏掉的回呼。修復很小,而跳過它的代價是真金白銀,所以值得把規則弄清楚:它到底是什麼,購買為什麼會在未確認的情況下溜走,以及每一筆流失的銷售實際上帶走了什麼。

三天規則到底說了什麼

Google 的 Play Billing 文件對此毫不含糊。在你的應用程式授予權益並告訴使用者購買成功之後,它必須通知 Google 這筆購買已被處理。用 Google 的原話說,這"必須在三天內完成,否則購買將被自動退款、權益被撤銷"。一次性商品頁面重複了同樣的說法,沒有任何緩和:"如果你沒有在三天內確認購買,使用者會自動收到退款,Google Play 會撤銷該購買。"訂閱對首次購買適用完全相同的規則。

確認是一個訊號,不是走過場。它告訴 Google 權益已經到達使用者手中。Google 把這個訊號的缺失視為一次從未發生過的交付,並代客戶撤銷這筆交易。從買家的角度看,這像是一筆他們從未申請過的免費退款。從你的角度看,這像是一筆憑空蒸發的銷售。

倒數計時從 PURCHASED 開始,不是從結帳開始

三天視窗不是從使用者點下購買時開始的。它從購買狀態轉變為 PURCHASED 時開始。購買可能會先停留在 PENDING,現金支付、緩慢的銀行轉帳,或家長核准孩子的請求都會出現這種情況。Google 說得很明確:"三天確認視窗只有在購買狀態從 PENDING 轉變為 PURCHASED 時才開始。"

這有兩個後果。只在狀態為 PURCHASED 時授予權益,絕不在 PENDING 時授予,否則你就是在為一筆可能永遠不會完成的付款發放產品。同樣,也不要去確認一筆 PENDING 的購買。你在建構 BillingClient 時呼叫 enablePendingPurchases(),等待狀態轉變,然後才在心裡開始計算確認倒數計時。

確認還是消耗,你該做哪一個

滿足要求有兩種方式,用哪一種取決於產品類型。兩者都能趕上三天期限。區別在於它們還會做什麼。

對於消耗型商品,你要消耗它。在安全的後端上這是 purchases.products.consume,或在 Play Billing Library 裡客戶端的 consumeAsync()。消耗既確認了購買,又讓產品重新可購買,這正是你想要的效果,適用於金幣、點數或一次性生成。對於非消耗型商品或訂閱,你要確認它:後端上用 purchases.products.acknowledge 或 purchases.subscriptions.acknowledge,或客戶端的 acknowledgePurchase()。確認趕上期限,但不會讓產品重新可供再次購買。

購買類型滿足期限的呼叫它還會做什麼期限
消耗型商品purchases.products.consume 或 consumeAsync()同時讓產品可再次購買從 PURCHASED 起 3 天
非消耗型商品purchases.products.acknowledge 或 acknowledgePurchase()標記權益已授予,不可再次購買從 PURCHASED 起 3 天
訂閱,首次購買purchases.subscriptions.acknowledge 或 acknowledgePurchase()確認新訂閱從 PURCHASED 起 3 天
訂閱續訂無需任何操作由 Google 自動標記為已確認不適用
時長不足一週的預付費方案按上述方式確認確認權益方案時長的一半

續訂已經處理好了,首次購買沒有

你只需對訂閱的首次購買負責確認。Google 明確表示"你不需要確認訂閱續訂",並且它會自行把續訂標記為 ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED。一筆新購買以 ACKNOWLEDGEMENT_STATE_PENDING 到達,在你處理掉它之前一直是你的責任。在確認之前,先在後端檢查 acknowledgementState,或在客戶端檢查 isAcknowledged(),以免重複確認。

預付費方案的引信更短

預付費訂閱方案收緊了視窗。Google 的規則是:時長一週或更長的預付費方案必須在三天內確認,但"時長短於一週的預付費方案必須在方案時長一半的時間內確認"。一個三天的預付費方案只給你一天半,而不是三天。如果你銷售短時的預付費儲值,你的確認路徑必須快速且由伺服器驅動,不能依賴使用者重新打開應用程式。

購買一開始為什麼會沒被確認

沒有人是故意跳過確認的。它之所以溜走,是因為負責確認的程式碼放錯了地方。常見的反模式是:客戶端只在購買流程回到前台時才確認。這對一個完成購買、並繼續使用應用程式的使用者是有效的。但對其他所有人都失效。

開發者不斷遇到這個問題。Google 自己的開發者社群裡的貼文每次讀起來都一個樣,都是"某個使用者在我的應用程式裡購買後三天被自動退款了"和"為什麼付款在三天後被自動退款"這類說法的變體。答案幾乎總是一樣:確認呼叫從未觸發,因為應用程式從來沒有處於能觸發它的狀態。

免費試用和那個再也不回來的使用者

最糟糕的情形是免費試用,或者使用者在徹底關閉應用程式之前的一筆購買。如果你的確認依賴於下一次打開應用程式,而根本沒有下一次打開,這筆購買就會過期作廢。到了第三天 Google 就退款並撤銷它。對於一個本會轉為付費訂閱的試用,你損失的是那筆你從未收到的首期帳單,外加一份悄悄消失的客戶權益。這兩件事都不會以工單的形式出現。它們表現為一筆你得主動去翻找才能發現的作廢購買。

一筆未確認退款實際的代價

退款那一行低估了損失。當 Google 撤銷這筆銷售時,你退回了價格,那是看得見的數字。它並不是全部帳單。

想想一件在購買瞬間就觸發真實工作的消耗型商品。一批圖像生成、一連串對模型提供商 API 的呼叫、一次影片匯出、一筆給創作者的分潤。你在使用時就已經為那些運算、那些 API 呼叫、那些儲存和那些分潤付了錢。退款把銷售價格退給了客戶。它不會把供應商的帳單退給你。你交付了一筆真實的成本,卻什麼也沒換回來。

對於訂閱和試用,損失是那筆你從未收到的首期帳單,以及一段還沒開始就結束了的客戶關係。而且從 2026 年 8 月 3 日起,Google Play 會把在該日期之後下單的訂單的退單購買價格和銀行手續費轉嫁給開發者,這讓任何可避免的營收流失都值得現在就堵上,而不是拖到以後。未確認退款不是退單,但它是同一個教訓:你已經花掉的錢,不會自動變成你留住的錢。

一張摺疊的收據和一些硬幣被拉回到一張深色桌子的另一端,說明當一筆未確認的 Google Play 購買被退款並撤銷時,你已經花掉的錢

如何在伺服器端確認一筆 Google Play 購買

可靠的做法是把應用程式從關鍵路徑上移除。在你的後端上完成它,由通知驅動,而不是由使用者重新打開介面驅動。

  • 監聽 Real-time developer notifications。一個 ONE_TIME_PRODUCT 購買或一個 SUBSCRIPTION_PURCHASED 事件,會在 Google 一知道的瞬間就告訴你的伺服器有一筆購買存在,無論應用程式是否打開。
  • 用 Play Developer API 校驗購買權杖,並確認狀態是 PURCHASED,不是 PENDING。
  • 在你自己的記錄裡授予權益,以使用者為鍵。
  • 立即確認或消耗。消耗型商品用消耗,非消耗型商品和首次訂閱用確認。先檢查 acknowledgementState,這樣你就絕不會確認兩次。
  • 在客戶端也做補漏。在 onResume() 裡呼叫 queryPurchasesAsync(),讓任何在應用程式關閉期間完成的購買仍然得到處理。這是一張安全網,不是主路徑。

關鍵在於,確認是由 Google 發給你的事件觸發的,而不是由你無法指望的使用者操作觸發的。一個購買後再也不回來的使用者被完全涵蓋了,因為你的伺服器在購買落地的那一刻就採取了行動。

給漏網之魚準備的對帳網

即便是乾淨的管道也能從一次核對中獲益。Voided Purchases API 會列出被退款、撤銷或退單的購買,並點名那種原因是購買"從未被開發者確認,因此可能不存在於開發者記錄中"的情形。輪詢它,你就能撤銷你為任何 Google 已經撤銷的東西所授予的權益。注意限制:該 API 只回傳過去 30 天內的作廢購買,所以對帳必須按計畫定期執行,不能一季才跑一次。

Apple 沒有對應機制,這很重要

這是一個專屬於 Google Play 的問題。Apple 的 StoreKit 也有一個收尾步驟,即完成一筆交易,但它在失敗時做的是相反的事。如果你從不完成一筆 StoreKit 交易,Apple 會把它保留在佇列裡,並在每次你的應用程式啟動或觀察者附加時重新投遞它,這樣你就又有一次機會去授予權益。Apple 不會為一筆未完成的交易退款。App Store 上沒有三天自動退款。

所以心智模型必須保持平台特定。在 Google Play 上,一筆未處理的購買是一場隨時會發生的退款,是一個你正在追趕的期限。在 App Store 上,一筆未處理的購買是一次隨時會發生的重新投遞,根本沒有倒數計時。把 Apple 的假設照搬到 Android,正是團隊最終堆起一牆無法解釋的未確認退款的原因。

這正是為什麼 RefundHalt 會在商店通知一到達的那一刻就自動確認 Google Play 購買,並對照 Voided Purchases API 進行對帳,好讓為一筆 Google 後來撤銷的購買所授予的權益不會繼續生效。三天規則不再是一場你可能會輸的比賽,而變成一個早已完成的步驟。

常見問題解答

為什麼我的 Google Play 購買在三天後被自動退款了?
因為你的應用程式沒有及時確認它。Google Play 會自動向買家退款並撤銷任何在到達 PURCHASED 狀態後三天內未被確認的購買。這不是客戶的申請,也不是 Google 的處罰,而是缺失了一個確認呼叫,從商店通知在伺服器端進行確認就能消除它。
確認購買和消耗購買有什麼區別?
兩者都能滿足三天要求。你透過 purchases.products.consume 或 consumeAsync() 消耗一件消耗型商品,這同時也讓產品可再次購買。你透過 purchases.products.acknowledge、purchases.subscriptions.acknowledge 或 acknowledgePurchase() 確認一件非消耗型商品或訂閱,這確認了權益,但不會讓產品可供再次購買。
我需要確認 Google Play 訂閱續訂嗎?
不需要。只有首次訂閱購買需要確認。Google 不要求確認續訂,並會自動將它們標記為 ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED。一筆新購買以 ACKNOWLEDGEMENT_STATE_PENDING 到達,在你處理掉它之前一直是你的責任。
我可以在購買還處於 PENDING 時就確認它嗎?
不可以。你應該只在購買狀態為 PURCHASED 時才確認。一筆 PENDING 的購買,比如現金支付或家長核准請求,還沒有啟動三天倒數計時。只在狀態從 PENDING 轉變為 PURCHASED 之後再授予權益和確認。
對於我沒有完成的購買,Apple 會退款嗎?
不會。Apple 的 StoreKit 會在每次你的應用程式啟動時重新投遞一筆未完成的交易,直到你完成它,但它絕不會自動退款。針對未確認購買的三天自動退款是 Google Play 獨有的,所以這兩個平台需要不同的處理方式。
如果一筆購買已經因為未確認而被退款,我該如何補救?
你無法撤銷這筆退款,但你可以對帳。輪詢 Voided Purchases API,它會列出過去 30 天內被退款和撤銷的購買,並標出那些因為從未被確認而作廢的購買,然後撤銷你已授予的權益。往後,從商店通知進行確認,這樣下一筆就不會溜走。

資料來源與延伸閱讀

RefundHalt

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

繼續閱讀

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

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