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

已作廢購買通知讓您的 Google Play 伺服器在退款發生的當下立即撤銷存取權限

Google Play 可以在購買被退款、發生退單或作廢的當下,將已作廢購買通知推送到您的伺服器。它攜帶 purchaseToken、orderId、productType 和 refundType,而它只代表一件事,撤銷存取權限。以下說明如何讀取它並完成串接。

黃昏時分的開發者工作區,手機上顯示一筆被撤回的付款,象徵一則 Google Play 已作廢購買通知抵達伺服器

重點摘要

  • 已作廢購買通知是一種 Real-time Developer Notification,Google Play 會在購買被退款、發生退單或以其他方式作廢的當下,將它推送到您的 Cloud Pub/Sub 主題。它是一個推送訊號,不需要您主動輪詢。
  • 這則通知恰好攜帶四個欄位:`purchaseToken`、`orderId`、`productType` 和 `refundType`。這足以在您的資料庫中找到確切的那筆購買,並撤銷與其綁定的權限。
  • `productType` 為 `1` 代表已作廢的訂閱,為 `2` 代表已作廢的一次性購買。`refundType` 為 `1` 代表全額退款,為 `2` 代表基於數量的部分退款,後者僅適用於多數量的一次性購買。
  • 已作廢購買通知代表客戶已經拿回了他們的錢。Google 自己的指引是撤銷對相關內容的存取權限,因為買家不應再持有該權限。
  • 已作廢購買通知在您開啟之前都是關閉的。在 Play Console 的 Monetization setup 中,您可以選擇訂閱加上所有已作廢購買,或是在此之上再加上一次性產品事件。這兩個選項都包含已作廢購買。
  • 已作廢購買通知並不屬於那兩種會向您索取證據的退款流程。它是一則事後通知。唯二會接受您輸入的流程,是 Apple 的 CONSUMPTION_REQUEST,有 12 小時的時限,以及 Google Play 透過 orders.reviewrefund 進行的退單審查,有 24 小時的時限。
  • 自 August 3, 2026 起,Google 會將退單的購買金額加上銀行手續費轉嫁給開發者。已作廢購買通知往往是您的伺服器最先得知退單作廢已經發生的途徑,因此完成串接,正是讓您能停止服務一位已不再向您付費的客戶的關鍵。

Google Play 上的退款不必是您日後在報表中才發現的事。無論買家是自助退款、由客服人員核准、由銀行強制發起退單,還是您自己在開啟撤銷旗標的情況下為訂單退款,Google Play 都能在購買被作廢的當下,將已作廢購買通知推送到您的伺服器。這則訊息極小,它指名確切的那筆購買,並且只帶著一條指令,收回權限,因為錢已經沒了。

已作廢購買通知究竟是什麼

已作廢購買通知是 Google Play 的 Real-time Developer Notifications(即 RTDN)其中一種類型。RTDN 是一個推送通道。Google 會將訊息發布到您擁有的 Cloud Pub/Sub 主題,而您的後端會在事件發生後片刻內收到它,而不是在下一次排定的輪詢時才得知。這正是已作廢購買通知相較於較舊的拉取路徑的全部重點:您在退款發生的當下就得知,而非數小時之後。

拉取路徑依然存在,也依然重要。Voided Purchases API 讓您的伺服器能依自己的排程,查詢某個時間範圍內被作廢的購買清單。兩者相輔相成。通知會在某筆購買狀態翻轉的當下告知您;API 則讓您能批次對帳,並補齊任何遺漏訊息可能留下的缺口。

它包裹在 Real-time Developer Notification 之中

已作廢購買通知從不單獨抵達。它位於一個 DeveloperNotification 外層封裝之中,而該封裝會以單一的 base64 編碼字串,放在 Pub/Sub 訊息的 data 欄位中送達。您的處理程式必須先將該字串解碼為 JSON,才能讀取任何內容。封裝一定會指名應用程式與事件時間,並且恰好包含 Google 所定義的五種通知物件中的一個。它們彼此互斥,因此攜帶 voidedPurchaseNotification 的訊息,不會同時攜帶訂閱或一次性事件。

封裝欄位它所存放的內容
version通知結構描述的版本,例如 1.0
packageName事件所屬的應用程式,例如 com.acme.app
eventTimeMillis事件發生的時間,以自 epoch 起算的毫秒表示
五種通知物件之一oneTimeProductNotificationsubscriptionNotificationvoidedPurchaseNotificationpendingRefundReviewNotificationtestNotification。每則訊息只會出現一個

它攜帶的四個欄位

剝去封裝後,已作廢購買通知本身就是四個欄位。這是刻意的精簡。Google 的立場是,如果您所需的只是找到正確的購買並調整權限,這四個欄位就足夠了,您無需回頭呼叫任何 API 就能採取行動。

欄位它是什麼您如何使用它
purchaseToken購買商品時交給裝置的權杖您的主鍵。將它與您在授權時儲存的購買紀錄比對
orderId顯示給買家的訂單編號,例如 GS.0000-0000-0000供支援與對帳使用、人類可讀的第二把鍵
productType被作廢的商品是訂閱還是一次性購買導向正確的撤銷路徑
refundType作廢是全額退款還是基於數量的部分退款決定是撤銷全部,還是僅撤銷已退款的數量

productType 告訴您什麼被作廢了

productType 是一個很小的整數,它決定要採用您的哪一條撤銷路徑。訂閱作廢必須解除持續進行的存取;一次性購買作廢則只是移除單一權限。

`productType` 值常數意義
1PRODUCT_TYPE_SUBSCRIPTION一筆訂閱購買被作廢
2PRODUCT_TYPE_ONE_TIME一筆一次性購買被作廢

refundType 告訴您退回了多少

refundType 將乾淨的全額撤回與部分撤回區分開來。部分退款的情況很狹窄。它只在一筆多數量的一次性購買,其數量被退了一部分但非全部時才出現。

`refundType` 值常數意義
1REFUND_TYPE_FULL_REFUND購買被全額作廢
2REFUND_TYPE_QUANTITY_BASED_PARTIAL_REFUND多數量購買中的一部分被作廢

先開啟它,否則它永遠不會抵達

已作廢購買通知預設不會流動。您只需在 Play Console 中啟用一次 RTDN,並將它指向由您掌控的 Pub/Sub 主題。這個開關位於 Monetize,接著是 Monetization setup,在頁面頂端的 Real-time developer notifications 區段中。勾選 Enable real-time notifications,然後以 projects/{project_id}/topics/{topic_name} 的格式貼上您完整的主題名稱,並在信任它之前使用 Send Test Message 來確認這條管道正常運作。

內容切換開關正是人們漏掉已作廢購買的地方。兩個選項都包含它們,因此您無法在保留訂閱的同時,不小心排除掉退款。

  • 接收訂閱與所有已作廢購買的通知。您會收到訂閱事件和每一筆已作廢購買,但不包含一次性產品的購買事件。
  • 接收訂閱與一次性產品的所有通知。您會收到上述內容,再加上一次性產品事件,例如 ONE_TIME_PRODUCT_PURCHASEDONE_TIME_PRODUCT_CANCELED
一張正面朝下的信用卡擺在一張紙本收據旁,象徵一筆已作廢的 Google Play 購買

它讓您付出什麼代價,以金錢計

作廢是一筆在通知抵達您這裡時就已經記入的損失。銷售金額沒了,您為服務那位客戶所花的一切也沒了。如果他們生成了圖片、對您的模型發出呼叫、佔用了儲存空間,或觸發了對第三方的支付,這些成本都是用真金白銀付出的,不會隨退款一起回來。通知無法挽回這些之中的任何一項。它能做的,是從此刻起止血,而這正是要迅速處理它的全部原因。

在訂閱上出血最嚴重,在退單上出血也最嚴重。一筆您未能撤銷的訂閱,會為一位不再付費的客戶,月復一月地持續耗費您的服務成本。而退單是最昂貴的一種作廢。自 August 3, 2026 起,Google 的文件說明退單會將購買金額加上銀行手續費轉嫁給開發者。已作廢購買通知往往是您自己的系統最先聽聞退單已完成的地方,因此一個當場撤銷的處理程式,正是防止一筆流失的銷售,演變成一筆流失的銷售外加數週免費服務的關鍵。

如何處理已作廢購買通知,逐步說明

驗證訊息並去除重複

  • 確認該 Pub/Sub 訊息來自 Google 並指向您所設定的主題,接著解碼 base64 的 data 欄位,以取得 DeveloperNotification 的 JSON。
  • 使用 Pub/Sub 的 messageId 來丟棄重複項目。Google 警告同一則通知可能被傳遞不止一次,因此請將重送視為正常情況,並讓您的處理程式具備冪等性。
  • 只在您已安全記錄訊息之後才確認它,如此一來處理程式中途當機也不會遺失該事件。

查找該筆購買

  • purchaseToken 與您首次授予權限時儲存的購買比對。以 orderId 作為支援查詢與人工對帳的備援。
  • 讀取 productType 以選擇訂閱或一次性的撤銷路徑,並讀取 refundType 以在全額撤銷與部分撤銷之間做出決定。

撤銷並記錄

  • 移除權限。對於全額退款,切斷對該商品的存取。對於基於數量的部分退款,將已授予的數量按退款的數量減少,其餘部分保持不變。
  • purchaseTokenorderId 為鍵,寫下您做了什麼以及在何時做的。這份紀錄能讓您日後回覆支援工單,也能讓 Voided Purchases API 與您自己的狀態乾淨地對帳。

它在其他退款訊號中的定位

已作廢購買通知是一則告知,而非一場協商。它告訴您一個已經定案的結果。值得把它與那些容易和它混淆的訊號放在一起看,因為只有其中一部分會徵詢您這一方的說法。

訊號方向它是否接受您的輸入
已作廢購買通知 (RTDN)Google 推送到您的伺服器否。它回報一件已經發生的作廢
Voided Purchases API您的伺服器向 Google 拉取否。它是一份唯讀的過往作廢清單
pendingRefundReviewNotification (RTDN)Google 推送到您的伺服器是,間接地。它標記一筆退單,您接著在 24 小時內透過 orders.reviewrefund 提出異議
Apple CONSUMPTION_REQUESTApple 向您的伺服器詢問是。您在 12 小時內以 Send Consumption Information 回覆

要牢記的原則很簡單。橫跨這兩家商店,開發者能發表意見的退款流程恰好只有兩種,Apple 的 CONSUMPTION_REQUEST 與 Google Play 的退單審查。已作廢購買通知兩者都不是。當它抵達您這裡時,決定早已成為過去,唯一還在您手中的,就是您撤銷的速度有多快。

常見問題解答

在 Google Play 上,已作廢購買通知代表什麼?
它代表一筆購買被退款、發生退單或以其他方式作廢,而客戶已拿回他們的錢。Google 的指引是撤銷對相關內容的存取權限,因為買家不應再持有該權限。通知會透過其 `purchaseToken` 和 `orderId` 指名確切的那筆購買。
一則 Google Play 已作廢購買通知包含哪些欄位?
四個:`purchaseToken`、`orderId`、`productType` 和 `refundType`。`productType` 為 `1` 代表訂閱,為 `2` 代表一次性購買。`refundType` 為 `1` 代表全額退款,為 `2` 代表多數量購買上基於數量的部分退款。
我要如何啟用已作廢購買通知?
在 Play Console 中,開啟 Monetize 接著 Monetization setup,並在 Real-time developer notifications 區段勾選 Enable real-time notifications,然後輸入您的 Cloud Pub/Sub 主題名稱。兩種內容選項,訂閱加上所有已作廢購買,以及在此之上再加一次性產品事件,都包含已作廢購買。
已作廢購買通知與 Voided Purchases API 有什麼差別?
通知是一個推送訊號,在購買被作廢的當下透過 Cloud Pub/Sub 即時送達。Voided Purchases API 則是一條拉取路徑,由您的伺服器依自己的排程查詢,以列出某個時間範圍內的作廢。用通知來即時反應,用 API 來對帳與補齊缺口。
已作廢購買通知能讓我對退款提出異議嗎?
不能。它是一則對已經做成的決定的事後通知。唯一會接受您輸入的 Google Play 流程,是透過 `orders.reviewrefund` 進行的退單審查,您有 24 小時可以回覆,而在 Apple 上則是有 12 小時時限的 CONSUMPTION_REQUEST。

資料來源與延伸閱讀

RefundHalt

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

繼續閱讀

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

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