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

退款處理常常悄無聲息地出錯,所以要先在 sandbox 中測試應用程式內購買退款,別等真實客戶先碰上

你的退款處理只有在客戶已經離開之後才會執行,所以其中的缺陷會一直隱藏,直到它真的讓你損失金錢。兩大商店都允許你先在測試環境中觸發一次退款。這裡說明如何在退款成真之前,先在 App Store 和 Google Play 上測試應用程式內購買退款。

深色桌面上放大鏡下的一台 iPhone 和一台 Android 手機,象徵在退款成真之前先測試應用程式內購買退款

重點摘要

  • Xcode 的 StoreKit 測試允許你在本機退款,只需在 Transaction Manager 中點擊退款箭頭,這會觸發你應用程式的 Transaction.updates 監聽器,但它從不聯繫 Apple,所以不會傳送任何 App Store Server Notification。
  • 要在 Apple 上測試伺服器端,請把一個 sandbox 的 App Store Server Notifications V2 URL 指向你的後端:這樣一次 sandbox 退款會向你的伺服器投遞一條真實的 REFUND,一次退款請求則會投遞一條 CONSUMPTION_REQUEST。
  • Apple 的 Request a Test Notification 端點會向你設定的 URL 傳送一條類型為 TEST 的通知,並回傳一個 testNotificationToken,讓你在任何真實事件觸發之前就能確認你的 webhook 可達。
  • Apple 的 sandbox 從不重試失敗的通知,所以當 sandbox 觸發時若 webhook 處於當機狀態,事件就會被丟棄,不會有第二次嘗試,這正是日後讓你損失一個真實退款視窗的同一類失誤。
  • Google Play 為授權測試者提供一種名為 Test card, approves then charges back 的付款方式,它會在購買後片刻觸發一條 PendingRefundReviewNotification,讓你可以預演 24 hours 的 orders.reviewrefund 回應。
  • 對於 Google Play 上的授權測試者,一筆未確認的購買會在 3 minutes 後自動退款,而不是正式環境等待的 3 days,所以有問題的確認流程會在測試中又快又明顯地暴露出來。
  • 一個你從未測試過的退款處理器,正是那個讓已退款客戶繼續保有付費存取的處理器,而從 2026 年 8 月 3 日起,一個未測試的 Google Play 拒付回應可能讓你損失購買價格減去 Play 的服務費再加上銀行的費用。

你的退款處理是唯一一條只有在客戶已經離開之後才會執行的程式碼路徑。你日常的 QA 完全觸及不到它,因為要走到它那一步,你得真的被退款。於是它在未經測試的情況下上線,沉默數月,然後在一次真實退款上失敗,而這次失敗付出的是金錢,而不是一次紅色的測試。解決辦法是不再把退款當成發生在你身上的事,而是有意去觸發一次。Apple 和 Google 都允許你在測試環境中觸發退款並觀察你的伺服器如何反應。這裡說明如何在一個付費客戶證明你的處理器早已損壞之前,先在 App Store 和 Google Play 上測試應用程式內購買退款。

退款可能在三種環境中觸發,而只有一種是正式環境

在你建置期間,Apple 或 Google 的退款有三個各自獨立的觸發場所,而它們並不能互換。其中兩個由你按需觸發。第三個是正式環境,你絕不想在那裡第一次遇到退款缺陷。陷阱在於以為那個簡單的選項,也就是在 Xcode 中做本機測試,就能證明你的整條管線。它只證明你的應用程式。它對你的伺服器什麼也沒說。

Xcode StoreKit 測試是本機的,所以它只鍛鍊你的應用程式而已

Xcode 內建的 StoreKit 測試針對你 Mac 上的一個設定檔執行,不會往返 Apple。從除錯列打開 StoreKit Transaction Manager,選取一筆已購買的交易,點擊那個彎曲的退款箭頭。該交易會翻轉為已退款,你應用程式的 Transaction.updates 監聽器就會觸發,完全和在真實環境中一樣。你也可以呼叫 beginRefundRequest 來呈現真實的退款面板,而在 Xcode 環境中,你選擇的問題會一對一對應到某個 RevocationReason,退款立即生效。這是證明你的用戶端在 revocationDate 變為非 nil 的那一刻就切斷存取的最快辦法。這也是本機測試所能告訴你的全部,因為這裡沒有任何東西會到達 Apple 的伺服器,所以不會傳送任何 App Store Server Notification。你的後端什麼也學不到。

sandbox 是你的伺服器終於聽說退款的地方

要測試你整合中決定金錢的那一半,也就是你的伺服器,你需要 Apple 的 sandbox。在 App Store Connect 中設定一個 sandbox 的 App Store Server Notifications V2 URL,在裝置上登入一個 sandbox 測試者並購買。現在,sandbox 中的一次退款會向你的後端投遞一條真實的 REFUND 通知,而針對消耗型或自動續訂產品的退款請求會投遞一條 CONSUMPTION_REQUEST,這與你正式伺服器將收到的簽章負載相同。在觸發任何東西之前,先呼叫 Request a Test Notification 端點。它會告訴 App Store 伺服器向你設定的 URL 傳送一條類型為 TEST 的通知,並交給你一個 testNotificationToken,你把它傳給 Get Test Notification Status 以確認送達。如果這次往返不成功,任何真實通知也都不會成功。

環境它能觸發什麼它能證明什麼它做不到什麼
Xcode StoreKit 測試透過 Transaction Manager 或 beginRefundRequest 面板發起的退款你的應用程式在本機幾秒內對退款做出反應從不聯繫 Apple,所以不會傳送任何伺服器通知
Sandbox向你伺服器傳送真實的 REFUND 和 CONSUMPTION_REQUEST,外加按需的一條 TEST 通知你的後端接收、驗證並處理簽章負載不會重試你端點未能接收的通知
正式環境每一筆退款,都是真金白銀這裡沒有任何你想先弄明白的東西你無法撤銷一個缺陷造成的成本

如何在 App Store 上測試應用程式內購買退款

按這個順序執行,從便宜的用戶端檢查到完整的伺服器往返。每一步鍛鍊不同的部件,而靠後的那些正是正式環境真正會向你收費的部分。

  • 在 App Store Connect 的 Users and Access, Integrations, In-App Purchase 下建立一個 In-App Purchase key,並用它來簽署你的 App Store Server API 呼叫。
  • 把你 sandbox 的 App Store Server Notifications V2 URL 指向你的後端,然後呼叫 Request a Test Notification,確認 TEST 負載到達並能對照 Apple 的憑證鏈通過驗證。
  • 在 Xcode 的 Transaction Manager 中,退款一筆購買,確認在設定 revocationDate 的那一刻你的應用程式就撤銷了權益。
  • 登入一個 sandbox 測試者,購買一個消耗型產品,請求退款,確認你的伺服器收到 CONSUMPTION_REQUEST,並能在 12 hours 視窗內從容地組裝並傳送一條 Send Consumption Information 回覆。
  • 退款一筆 sandbox 購買,確認 REFUND 通知到達你的伺服器,確認你撤銷了存取或扣減了消耗型餘額,並確認同一條通知的重複投遞不會被重複處理。
一部智慧型手機夾在工作檯燈下的小台鉗裡,旁邊放著鑷子,一台受測裝置象徵在退款成真之前先預演一次退款

如何在 Google Play 上預演一次退款和一次拒付

Google Play 沒有像 Xcode 那樣的本機模式。一切都針對 Google 的伺服器執行,但授權測試者讓它保持免費又安全。在 Play Console 中把你的測試 Google 帳戶加入為授權測試者,他們就會得到一套從不產生真實費用的測試付款方式。Google 會在購買對話框中間橫跨標註每一筆測試購買,且不計算稅費。對退款測試而言,關鍵在於你選擇哪個測試工具,因為每一個都會帶來不同的結果。

測試付款方式它模擬什麼你為何會用它
Test instrument, always approves一筆乾淨的成功購買建立一筆你之後可以退款或撤銷的訂單
Test instrument, always declines一筆失敗的付款確認在被拒付時你什麼也不授予
Slow test card, approves after a few minutes一筆稍後成功的待處理購買在授予存取之前鍛鍊你的 PENDING 處理
Slow test card, declines after a few minutes一筆稍後失敗的待處理購買確認待處理的拒付絕不會洩漏權益
Test card, approves then charges back一次使用者發起的拒付觸發一條 PendingRefundReviewNotification 並預演你 24 hours 的回應

觸發一次退款、一次拒付和確認自動退款

  • 用先核准後拒付的測試卡購買,片刻之後一條 PendingRefundReviewNotification 就會落到你的 Real-time Developer Notifications 主題上。用單次 orders.reviewrefund 呼叫來回應它,因為 Google 只保留你的第一次回應。
  • 在 Play Console 的 Orders 標籤頁退款並撤銷一筆測試訂單,以觸發一條 VoidedPurchaseNotification,確認你的伺服器收回了權益。
  • 故意讓一個授權測試者的購買保持未確認。Google 會在 3 minutes 後自動退款,而不是正式環境允許的 3 days,並把取消郵件寄給你,所以有問題的確認流程會在幾分鐘內暴露,而不是等到正式環境的第四天。

一條未經測試的退款路徑實際上要花多少錢

退款處理器不是裝飾。它是那段讓你停止為一個不再付錢給你的人買單的程式碼。當它悄無聲息地失敗時,退款仍然照常完成,但其背後的存取、餘額和支出並沒有停止。

順著錢走。當 Apple 或 Google 退還一筆購買時,你退回銷售價格,商店退回它的佣金,到這裡帳目是持平的。回不來的是你為交付產品已經花掉的一切:一次生成結果背後的算力、模型 API 呼叫、使用者儲存內容的儲存空間、你已經付給創作者的分潤。一個從不撤銷存取的退款處理器會讓一個已退款使用者繼續用你的預算去花這些,而系統裡再沒有任何東西能切斷他們。

兩個舉證視窗讓這一點更加尖銳。一個你在 sandbox 裡從未鍛鍊過的 CONSUMPTION_REQUEST,就是一個你發得格式錯誤或過遲的回覆,而當你的回答沒有落在 12 hours 之內時,Apple 往往會預設核准退款。一個你從未用測試卡觸發過的 Google Play 拒付回應,就是一個你在真實環境中會搞砸的 24 hours 視窗,而從 2026 年 8 月 3 日起,一次失敗的 Play 拒付會讓你損失購買價格減去 Play 的服務費再加上銀行的拒付費用。這些失敗裡的每一個都可以先在測試環境中免費重現。而它們沒有一個在正式環境裡是便宜的。

未測試的路徑它在正式環境中如何失敗它讓你付出什麼代價
REFUND 處理器已退款使用者保有存取你繼續為他們花掉的算力、API 呼叫、儲存空間和分潤
CONSUMPTION_REQUEST 回覆格式錯誤,或在 12 hours 之後才傳送Apple 預設核准退款,所以你既失去銷售又失去支出
orders.reviewrefund 回應在 24 hours 內遺漏或出錯從 2026 年 8 月 3 日起,購買價格減去 Play 的服務費,再加上銀行的拒付費用

上線退款處理前的一份簡短清單

你不需要一個實驗室。你需要的是親眼看著每個事件都擊中你的程式碼一次。

  • 在一筆 StoreKit 交易顯示出 revocationDate 的那一刻,你的應用程式就切斷了存取,已在 Xcode 的 Transaction Manager 中確認。
  • 你的 sandbox 伺服器 URL 收到一條 TEST 通知,並對照 Apple 的憑證完成驗證。
  • 一條 sandbox REFUND 撤銷存取或扣減餘額,而重複投遞不會被重複計數。
  • 一條 sandbox CONSUMPTION_REQUEST 在 12 hours 之內從容地產生一條有效的 Send Consumption Information 回覆。
  • 一條來自拒付測試卡的 Google PendingRefundReviewNotification 恰好產生一次 orders.reviewrefund 呼叫。
  • 一筆未確認的 Google Play 測試購買在 3 minutes 內自動退款,而你的對帳流程注意到了它。

把那份清單跑一遍,退款處理就不再是你希望它能用的程式碼。它變成了你已經親眼看著它運作過的程式碼。

常見問題解答

我能在沒有真實購買的情況下測試 App Store 退款嗎?
可以。Xcode 的 StoreKit 測試允許你透過 Transaction Manager 在本機退款一筆購買,不涉及真實金錢,也不需要 App Store 帳戶,這會觸發你應用程式的 Transaction.updates 監聽器。它不會傳送伺服器通知,所以它只測試你的應用程式,而不是你的後端。
本機 StoreKit 測試會傳送 App Store Server Notifications 嗎?
不會。Xcode 的 StoreKit 測試完全在你的 Mac 上針對一個本機設定執行,從不聯繫 Apple 的伺服器,所以不會傳送任何 App Store Server Notification,包括 REFUND 或 CONSUMPTION_REQUEST。請使用 sandbox 來測試你的伺服器。
我該如何測試 Google Play 拒付回應?
使用名為 Test card, approves then charges back 的授權測試者付款方式。它會在購買後片刻觸發一條 PendingRefundReviewNotification,與真實銀行拒付傳送的通知相同,所以你可以預演你 24 hours 的 orders.reviewrefund 回覆。
為什麼我的 Google Play 測試購買幾分鐘後就被退款了?
對於授權測試者,如果你的應用程式沒有確認購買,Google 會在 3 minutes 後自動退款,並把取消郵件寄給你。正式環境等待 3 days,但測試者拿到的是加速版本,好讓有問題的確認流程盡快浮現。
Apple 的 sandbox 會重試一條失敗的退款通知嗎?
不會。sandbox 不會重試 App Store Server Notifications,所以如果在 sandbox 退款觸發時你的端點處於當機狀態,通知就會被丟棄,不會有第二次嘗試。請先用 Request a Test Notification 確認你的 URL 可達。

資料來源與延伸閱讀

RefundHalt

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

繼續閱讀

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

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