所有文章
實戰指南閱讀時間 9 分鐘

漏收退款通知,可能讓你失去唯一能申辯的退款機會,好在兩大商店都讓你及時找回

伺服器漏收退款通知時,兩個需要你提交證據的退款流程會在你缺席的情況下結案。本文說明 Apple 和 Google Play 如何重試、漏收的退款通知最多能追回多久以前的,以及復原機制的缺口在哪裡。

夜裡的伺服器機櫃,一排穩定的綠燈中亮著一盞琥珀色警示燈,前方推車上放著一台筆記型電腦,正是漏收退款通知背後那種無聲的故障

重點摘要

  • App Store Server Notifications V2 傳送失敗時,Apple 會重試五次,分別在上一次嘗試後的 1、12、24、48 和 72 小時,因此第二次重試大約在第一次傳送 13 小時後才抵達。
  • Apple 要求開發者在收到 CONSUMPTION_REQUEST 後 12 小時內回應。如果伺服器錯過了第一次傳送和 1 小時後的重試,等它看到這筆請求時,回應期限很可能已經過了。
  • Apple 的 Get Notification History 端點可傳回正式環境過去 180 天內的 V2 通知,每頁 20 筆。onlyFailures 參數可將結果限定為從未送達你伺服器的通知,以及仍在重試中的通知。
  • Google Play 只透過 PendingRefundReviewNotification 傳送退單審查,而在 24 小時內呼叫 orders.reviewrefund 所需的 pendingRefundToken 就包含在這則通知裡。Google 沒有提供任何可列出待審查項目的獨立 API。
  • Google Cloud Pub/Sub 預設保留未確認訊息 7 天,最長 31 天。訂閱若連續 31 天沒有訂閱端活動就會被刪除,除非你變更了它的到期時間。
  • Google Play Voided Purchases API 可以找回過去 30 天內的退款、撤銷和退單,配額為每天 6,000 次查詢、任意 30 秒內 30 次查詢,但它無法找回你從未回應的退單審查。
  • Apple 沙盒環境每則通知只傳送一次,不會重試。所以只在沙盒裡跑過的復原流程,從來沒有經過 Apple 真實重試時間表的考驗。

漏收退款通知,會讓開發者在不知不覺中失去僅有的兩次能夠參與的退款決定。Apple 的 CONSUMPTION_REQUEST 和 Google Play 的退單審查都從一則通知開始,期限也都很短:Apple 是 12 小時,Google 是 24 小時。如果這則訊息抵達時你的伺服器當機、回應太慢或設定有誤,商店不會等你,而是根據手上已有的資訊直接做出決定。

好消息是,兩家商店都不會在第一次失敗後就丟掉訊息。Apple 會重試,並保留可查詢的 180 天歷史紀錄。Google 透過 Pub/Sub 發布,未確認的訊息會保留好幾天。壞消息是,重試時間和回應期限對不上,而且兩個流程中有一個完全沒有復原用的 API。

兩大商店如何傳送退款通知

Apple 會把 App Store Server Notifications 直接傳送到你在 App Store Connect 中設定的 HTTPS 網址。Google 不會直接呼叫你的伺服器,而是把即時開發人員通知發布到一個 Google Cloud Pub/Sub 主題,你在該主題上的訂閱要麼把通知推送到你的端點,要麼等你的伺服器來提取。

問題App StoreGoogle Play
傳送管道對你的網址發出 HTTPS POSTCloud Pub/Sub 主題,推送或提取
怎樣算成功HTTP 200 至 206確認 Pub/Sub 訊息,或推送端點傳回成功狀態碼
重試V2 重試 5 次,分別在上一次嘗試後的 1、12、24、48 和 72 小時Pub/Sub 持續重新傳送,直到被確認或保留期結束
漏收的訊息能保留多久在 Get Notification History 中保留 180 天訂閱中預設 7 天,最長 31 天
需要你提交證據的退款CONSUMPTION_REQUEST,12 小時內回應PendingRefundReviewNotification,24 小時內回應
已核准退款的提取式備援Get Notification History、Get Refund HistoryVoided Purchases API,過去 30 天
沙盒或測試行為只嘗試一次,不重試在 Play Console 中使用 Send Test Message

Apple 如何判定失敗

Apple 的文件寫得很清楚。傳回 200 至 206 之間的任何狀態碼,傳送就算完成。傳回 40x 或 50x,Apple 會重試。其他任何狀態碼 Apple 也一律視為失敗。每次嘗試都會記錄一個 sendAttemptResult,它的值幾乎就是一份真實故障清單:TIMED_OUT、TLS_ISSUE、CIRCULAR_REDIRECT、NO_RESPONSE、PREMATURE_CLOSE、UNSUCCESSFUL_HTTP_RESPONSE_CODE 等等。針對 TIMED_OUT,Apple 自己的建議是檢查伺服器是否在請求當下同步處理訊息。

Google 如何判定失敗

在推送訂閱中,你的端點傳回成功狀態碼就等於確認。在提取訂閱中,你的伺服器必須確認提取到的每則訊息,否則 Pub/Sub 會再傳送一次。預設的確認期限是 10 秒,最長 600 秒。Google 的 RTDN 指南還有一條值得再提的規則:通知只告訴你有東西變了,你仍然要呼叫 Google Play Developer API 取得完整的購買狀態。

為什麼 Apple 的重試時間表配合不上 12 小時期限

Apple 的重試間隔是從上一次嘗試開始算,而不是從第一次嘗試開始。把它們加總起來,就會得到一則持續傳送失敗的 V2 通知的時間軸。

嘗試距上一次嘗試的等待時間距第一次嘗試的小時數
第一次傳送無0
第 1 次重試1 小時1
第 2 次重試12 小時13
第 3 次重試24 小時37
第 4 次重試48 小時85
第 5 次重試72 小時157

Apple 要求你在收到 CONSUMPTION_REQUEST 後 12 小時內回應。如果第一次傳送和 1 小時後的重試時你的伺服器都當機,下一次嘗試要到第一次傳送 13 小時後才會抵達。Apple 沒有說明在重試中才第一次收到的請求,是否會重新給 12 小時。保守的解讀是把第一次嘗試當成計時起點,也就是說,如果你錯過請求超過 1 小時,光靠重試是救不回來的。

傳回 HTTP 400 後 Apple 會重試嗎?

依照文件,會。Apple 列出會觸發重試的狀態碼是 40x 和 50x。2026 年 3 月,有開發者在 Apple 論壇上回報,傳回 400 後重試似乎停止了,之後又說一兩天後傳送恢復正常,Apple 則請對方提交 Feedback Assistant 報告。請把文件中的行為當作規則,把你自己的監控當作證據。

用 Get Notification History 找回漏收的 App Store 通知

Get Notification History 會傳回在你指定的時間範圍內,Apple 嘗試傳送到你伺服器的第 2 版通知。每筆紀錄都含有完整的簽署酬載,所以你可以把它交給處理即時通知的同一個處理程式。每筆紀錄也含有一個 sendAttempts 陣列,最多六個項目,分別對應第一次嘗試和五次重試。

  • startDate 和 endDate 為必填,startDate 在正式環境中必須落在過去 180 天內,在沙盒中必須落在過去 30 天內。
  • 將 onlyFailures 設為 true,只取得尚未送達你伺服器的通知,以及 Apple 仍在重試的通知。
  • 可以依單一 notificationType 篩選,例如 CONSUMPTION_REQUEST 或 REFUND,也可以依單一顧客的 transactionId 篩選,但同一個請求中不能兩者並用。
  • 每次呼叫最多傳回 20 筆紀錄。只要 hasMore 為 true,就帶著 paginationToken 繼續呼叫,而且每次都送出相同的請求內容。

對退款來說,有一點特別重要。Apple 表示,歷史紀錄反映的是通知第一次傳送時的購買狀態,而不是現在的狀態。所以找回來的 REFUND 是過去的事實。撤銷存取權限之前,請先透過交易或訂閱狀態端點確認目前狀態。

V1 通知無法用這種方式找回

Get Notification History 只涵蓋第 2 版。Apple 對 V1 通知重試三次,分別在上一次嘗試後的 6、24 和 48 小時,如果全部失敗,就沒有可以重播的歷史紀錄。這也是還在用 V1 的 App 應該改用 V2 的另一個理由。

找回漏收的 Google Play 退款通知

Google 的安全網就是 Pub/Sub 本身。只要你的訂閱還在,沒人確認的訊息就會在保留期內一直留在那裡,預設 7 天,調高後最長 31 天。你的端點恢復後,傳送也會恢復。不過有兩個設定可能會悄悄讓這層保護失效。

  • 無效信件主題會在傳送失敗達到設定次數後,把訊息移出你的訂閱。預設次數是 5,在預設的立即重新傳送政策下,五次嘗試可能很快就用完。如果你有使用,請把無效信件主題當成第二個收件匣來盯。
  • 沒有訂閱端活動的訂閱,例如沒有開啟的連線、沒有進行中的提取或成功的推送,預設會在 31 天後到期。一個壞了一個月的端點,可能連訂閱本身和其中等待的所有訊息都一起賠掉。

已作廢的退款有 30 天的備援

對於已經發生的退款,Voided Purchases API 就是提取式備援。它會列出過去 30 天內的作廢購買,每頁最多 1,000 筆,每個 App 的配額為每天 6,000 次查詢、任意 30 秒內 30 次查詢。傳入 type 1 就能在一次性產品之外一併納入訂閱。每天執行一次,就能補上通知流程漏掉的任何退款,讓權益和營收數字保持正確。

退單審查沒有備援

PendingRefundReviewNotification 就不一樣了。它帶有你呼叫 orders.reviewrefund 時必須傳入的 pendingRefundToken,從收到通知起,你有 24 小時可以提交退款偏好和使用證據。Google 只記錄你的第一次呼叫,之後的都會忽略。Google 的文件中沒有任何列出待審查項目的端點,所以一旦這則 Pub/Sub 訊息遺失,你為這筆退單準備的證據也跟著消失。

漏收一則退款通知的金錢代價

如果漏收的是已經確定的退款通知,代價只是記帳工作。你之後會在 Voided Purchases API 或 Get Notification History 中發現它,依你的政策需要撤銷存取權限,報表也會跟著補齊。麻煩,但成本不高。

如果漏收的是兩個可申辯流程中的通知,就會造成實實在在的金錢損失,因為商店會在沒有你證據的情況下做出決定。在 Apple,這代表退款決定是在沒有你的使用量資料下做出的。在 Google Play,對於 2026 年 8 月 3 日之後成立的訂單,輸掉一筆退單要承擔購買價格扣除 Play 服務費後的金額,再加上買家銀行收取的退單手續費。Google 只承擔它自己的服務費。

而你為了交付這筆購買所花的錢,在爭議開始之前就已經花掉了。

  • 運算:買家已經用掉的每一次生成、算圖或模型回應背後的 GPU 和伺服器時間。
  • API 呼叫:第三方請求在送出的那一刻就已計費,通常按次收費。
  • 儲存空間:買家建立的檔案和媒體,仍然算在你的主機帳單裡。
  • 分潤:這筆銷售中已經支付給創作者、推廣夥伴或合作夥伴的營收分成。

退款一旦成立,這些都拿不回來。你在那 12 或 24 小時內提交的證據,是你唯一能用的籌碼,而漏收一則通知就會讓你失去它。

一套經得起考驗的復原流程

  • 先確認。儲存原始酬載,傳回成功狀態碼,再放進佇列處理。
  • 每隔幾分鐘用 onlyFailures 輪詢 Apple 的 Get Notification History,查找 CONSUMPTION_REQUEST,這樣一次故障只會損失 12 小時期限中的幾分鐘。
  • 每天用 onlyFailures 針對過去幾天的所有類型做一次 Get Notification History 全面檢查,並重播找到的通知。
  • 每天為每個 Google Play App 以 type 1 呼叫一次 Voided Purchases API,並和你已記錄的退款進行核對。
  • 在 Pub/Sub 上,把訊息保留期設為 7 天以上,如果有無效信件主題就針對它設定警示,並在未傳送的訊息累積時發出警示。
  • 也要在正式環境測試整條路徑。Apple 沙盒每則通知只傳送一次,不會重試,而 Request a Test Notification 搭配 Get Test Notification Status 可以清楚顯示你的伺服器是怎麼回應的。
清晨的光線下,一支智慧型手機正面朝上放在桌上,旁邊是咖啡杯和筆記本,以平靜的方式開始每天檢查漏收的退款通知

RefundHalt 替你接收兩大商店的通知,在期限內自動回應 CONSUMPTION_REQUEST 和退單審查,你不必再親自盯著時間。

常見問題解答

App Store 伺服器通知傳送失敗後,Apple 會持續重試多久?
第 2 版大約六天半。Apple 會重試五次,分別在上一次嘗試後的 1、12、24、48 和 72 小時,所以最後一次重試出現在第一次傳送 157 小時後。第 1 版通知重試三次,分別在上一次嘗試後的 6、24 和 48 小時。
漏收的 App Store 伺服器通知最多能追回多久以前的?
正式環境為 180 天。Apple 的 Get Notification History 端點會傳回過去 180 天內的第 2 版通知,沙盒則為過去 30 天,每次呼叫傳回 20 筆紀錄,onlyFailures 參數可將結果限定為從未送達你伺服器的通知。
如果我的伺服器傳回 HTTP 400,Apple 會重試通知嗎?
依照 Apple 的文件,會。伺服器傳回 40x 或 50x 狀態碼時 Apple 會重試,200 至 206 視為成功。其他任何狀態碼也都算失敗。
漏收的 Google Play 退單審查還能找回嗎?
只有在 Pub/Sub 訊息還存在時才可以。呼叫 orders.reviewrefund 所需的 pendingRefundToken 會隨 PendingRefundReviewNotification 一起送達,而 Google 沒有提供列出待審查項目的 API,所以訂閱中預設保留 7 天的未確認訊息就是你唯一的副本。
要怎麼找出伺服器漏掉的 Google Play 退款?
呼叫 Voided Purchases API。它會傳回過去 30 天內的作廢購買,包括退款、撤銷和退單,每頁最多 1,000 筆結果,每個 App 每天的配額為 6,000 次查詢。傳入 type 1 即可納入訂閱。

資料來源與延伸閱讀

RefundHalt

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

繼續閱讀

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

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