Apple 的 Retention Messaging API 能把你的話放上取消畫面,但退款申請從不經過那裡
Apple 的 Retention Messaging API 讓你在訂閱者點選取消時顯示一則訊息、一個換方案建議或一項促銷優惠。本文說明它的運作方式、執行成本,以及為什麼退款申請送達 Apple 時完全不會經過那個畫面。

重點摘要
- Apple 的 Retention Messaging API 讓開發者選擇 iPhone 訂閱者點選 Cancel Subscription(取消訂閱)後看到的訊息,共有四種類型:文字、附圖片的文字、換方案建議、促銷優惠。
- Apple 的文件仍將 Retention Messaging API 描述為需要開發者申請加入的預先發布功能。1.0 版於 2025 年 7 月 16 日推出,1.5 版於 2026 年 4 月 27 日跟進。
- 在即時流程中,當有效訂閱者檢視帶有取消按鈕的訂閱詳細資料頁面時,Apple 會呼叫開發者的 Get Retention Message 端點。正式環境中該端點必須在 700 ms 內回應,否則 Apple 會改用預設訊息。
- 挽留訊息只影響未來的續訂。退款申請透過 reportaproblem.apple.com 或 App 內退款表單送交 Apple,而顯示挽留訊息的取消畫面不在這條路徑上。
- 當顧客在 App 內透過 StoreKit 的退款申請 API 申請退款時,Apple 會自行關閉自動續訂,並傳送子類型為 AUTO_RENEW_DISABLED 的 DID_CHANGE_RENEWAL_STATUS,與從「訂閱項目」設定頁面取消時的類型和子類型完全相同。
- 對於 Apple 的退款,開發者唯一能提出意見的管道是 CONSUMPTION_REQUEST:須在 12 小時內以 Send Consumption Information 回覆,且前提是顧客同意分享這些資料。
- Google Play 沒有文件記載的、由開發者選擇取消畫面訊息的同類功能。開發者事後會收到 SUBSCRIPTION_CANCELED 通知,userInitiatedCancellation 欄位會說明訂閱者離開的原因。
在 iPhone 上點選取消的訂閱者,現在可以在確認之前看到你選擇的訊息、一個更便宜的方案或一項折扣。這就是 Apple 的 Retention Messaging API,也是開發者第一次能在 Apple 自己的取消畫面上發聲。它仍是預先發布功能,必須申請才能加入。如果你在意退款,它還有一條硬性界線:它面對的是即將停止付費的人,而不是要求退錢的人。退款申請走的是另一條路。
Apple 的 Retention Messaging API 能做什麼
Retention Messaging API 是一項伺服器對伺服器的服務。你事先把訊息文字和圖片上傳給 Apple,Apple 審核後,你再決定訂閱者在即將取消自動續訂型訂閱時看到哪一則已核准的訊息。Apple 的文件列出四種訊息類型:
- 文字訊息,可以包含項目符號。
- 附圖片的文字訊息。
- 換方案訊息,建議同一訂閱群組中的另一項訂閱。
- 促銷優惠訊息,以相同或不同級別的折扣價提供優惠,使用你在 App Store Connect 中設定並在伺服器上簽署的促銷優惠。
訊息會在顧客於訂閱詳細資料頁面點選 Cancel Subscription(取消訂閱)之後出現。接著 Apple 會顯示 Confirm Cancellation(確認取消)頁面。顧客仍然可以取消、點選 Keep Subscription(保留訂閱),或接受你建議的優惠或方案。你無法隱藏退出的路徑,Apple 也要求開發者不要上傳誤導或不正確的內容。
預設訊息與即時流程
執行方式有兩種。簡單的一種是預設訊息:依產品和語言地區指定的文字,可附或不附圖片、項目符號。更豐富的一種是即時流程:Apple 呼叫你伺服器上的 Get Retention Message 端點,你以一個訊息 ID 回應。只有即時流程才能顯示換方案和促銷優惠訊息。
實務上預設訊息並非可有可無。每當即時呼叫失敗,Apple 都會以預設訊息作為備援;對於缺少預設訊息的語言地區,Apple 不會為該產品顯示任何挽留訊息。
| 項目 | Apple 文件的說明 |
|---|---|
| 狀態 | 預先發布,開發者表達意願後加入 |
| 產品 | 自動續訂型訂閱 |
| 訊息類型 | 文字、附圖片的文字、換方案、促銷優惠 |
| 即時回應時限 | 正式環境 700 ms |
| 正式環境權限 | 須先通過沙盒效能測試,約 700 ms |
| 標題與項目符號文字 | 各 66 個字元,最多五個項目符號 |
| 內文文字 | 144 個字元 |
| 圖片替代文字 | 150 個字元 |
| 每個 App 的訊息數 | 2,000 |
| 審核 | 新訊息起始為 PENDING,變成 APPROVED 後才會顯示 |
| 裝置 | iOS 15.1、iPadOS 15.1、visionOS 1、macOS 14 或更新版本 |
即時呼叫中 Apple 會告訴你的伺服器什麼
請求是一個由 App Store 簽署的 JWS。解碼後包含 originalTransactionId、appAppleId、productId、userLocale、一個 requestIdentifier UUID、環境以及 signedDate。Apple 要求你核對 appAppleId 是否與你的 App 相符,不相符就不要回應。真正有用的是 originalTransactionId,因為它讓你在決定要說什麼之前,先查出這位訂閱者在你的 App 裡實際做過什麼。
挽留訊息會出現在哪裡,又不會出現在哪裡
Apple 只在一個畫面上放置這則訊息,也就是顧客點選 Cancel Subscription 之後的 Confirm Cancellation 步驟,例如從 Apple Account > Subscriptions 或 App Store 上某項訂閱的頁面進入。這個畫面關乎下一次續訂是否發生,不涉及已經收取的錢。
退款申請是另一回事。Apple 的支援頁面會引導顧客前往 reportaproblem.apple.com,在那裡選擇 Request a refund(申請退款),挑選原因和項目,然後等待 24 到 48 小時取得進度。在你的 App 內,StoreKit 的 beginRefundRequest 會開啟 Apple 的退款表單,Apple 表示 App Store 最多需要 48 小時核准或拒絕。兩條路徑都不經過 Confirm Cancellation 畫面。
| 時刻 | 發生位置 | 牽涉什麼 | 由誰決定 | 你的輸入 |
|---|---|---|---|---|
| 取消 | 訂閱詳細資料頁面,接著是 Confirm Cancellation | 未來的續訂 | 顧客 | 你選擇的挽留訊息,須在 700 ms 內回應 |
| 退款申請 | reportaproblem.apple.com 或你的 App 內退款表單 | 已經支付的錢 | Apple | 12 小時內提交的 CONSUMPTION_REQUEST 資料,前提是顧客同意 |
挽留訊息能阻止退款申請嗎?
不能。退款申請根本不會抵達顯示訊息的那個畫面。Apple 的通知文件中有一個細節讓這點非常具體:當顧客在你的 App 內透過退款申請 API 申請退款時,Apple 會自行關閉自動續訂,並傳送子類型為 AUTO_RENEW_DISABLED 的 DID_CHANGE_RENEWAL_STATUS。從「訂閱項目」設定頁面取消的顧客產生的類型和子類型完全相同。你的伺服器為兩種截然不同的顧客收到同一種通知,而其中只有一位看過你的挽留訊息。
如果退款申請繼續進行,提交證據的管道是 CONSUMPTION_REQUEST。Apple 會針對任何產品類型的退款申請傳送它,你有 12 小時以 Send Consumption Information 回覆。只有在顧客同意的情況下你才可以回覆。之後,Apple 的決定會以 REFUND 通知送達;若 Apple 拒絕了顧客在你 App 內發起的退款,則以 REFUND_DECLINED 送達。
Google Play 有取消訊息 API 嗎?
Google 的訂閱生命週期文件中沒有。Google Play 訂閱者在 Play 訂閱中心取消,存取權會保留到目前帳單週期結束,在此之前可以點選 Resubscribe(重新訂閱)撤銷取消,Google 稱之為恢復。你會在事後透過 SUBSCRIPTION_CANCELED 通知得知,訂閱資源中的 userInitiatedCancellation 欄位會告訴你使用者離開的原因。暫停功能是 Google 用來降低主動流失的主要內建手段,Google 表示所有訂閱預設啟用此功能。
在退款方面,Google Play 有自己的證據管道。當退單需要開發者審查時,會收到 PendingRefundReviewNotification,你有 24 小時透過 orders.reviewrefund 回覆。對於 2026 年 8 月 3 日之後成立的訂單,退單一旦成立,Google 會把購買價格(扣除 Play 服務費)連同銀行的退單手續費一併轉嫁給開發者。
取消畫面在金錢上讓你付出什麼
挽留訊息看起來是免費的。其實不是,帳單落在三個地方。
每次頁面瀏覽都要消耗運算資源
Apple 會在有效訂閱者檢視帶有取消按鈕的訂閱詳細資料頁面時呼叫你的端點,而不只是在他們取消時。每一次造訪都是一個請求,你的伺服器必須在 700 ms 內完成驗證、查詢和回應,否則 Apple 會改用預設訊息。這就排除了偶爾需要兩秒冷啟動的函式。你要為始終保持暖機的容量付費,還要負擔決策邏輯在每個請求中產生的資料庫讀取和付費第三方 API 呼叫。

折扣是你選擇放棄的營收
留住訂閱者的促銷優惠是實實在在保住的錢。給了一個本來就會留下的人,就純粹是讓利。以下是示意,不是基準數據。一個 $9.99 的月訂方案以半價提供三個月,每接受一次優惠就少收 $14.99。如果接受優惠的人中有三分之一本來就會以全價留下,那麼一千次接受就代表約 $5,000 的折扣給了根本不需要的人。帳本的另一邊,是那些真的要離開的訂閱者。
糟糕的退出體驗招來的退款
Apple 會把 Cancel Subscription 按鈕留在頁面上,所以你困不住任何人,但你仍然可能惹人厭煩。感到被逼迫的顧客還有另一個選擇,就是向 Apple 要回最近一筆扣款。退款一旦發生,錢會退回去,而與該訂閱者相關的運算、儲存、API 呼叫和聯盟分潤都已經花掉了。這些成本是任何挽留訊息都收不回來的。
如何使用挽留訊息而不推高退款率
把取消畫面當作講求準確的地方,而不是耍小聰明的地方。以下幾條規則能讓它留在退款界線的安全一側:
- 依訂閱者個別決定。用 Apple 請求中的 originalTransactionId 查詢近期使用情況。給真正在使用產品的人提供折扣或更便宜的方案。給好幾週沒開啟過的人一則簡短、誠實的訊息。
- 保持快速回應。在使用資料變動時預先算好決策,讓請求本身只需一次查詢,輕鬆控制在 700 ms 以內。
- 為每個產品和語言地區都寫一則預設訊息。沒有預設訊息,呼叫失敗就代表什麼都不顯示。
- 密切留意 AUTO_RENEW_DISABLED。如果同一個 originalTransactionId 隨後出現 CONSUMPTION_REQUEST,你面對的就是退款申請而不是取消,12 小時的倒數已經開始。
- 回覆每一個你被允許回覆的 CONSUMPTION_REQUEST。RefundHalt 會在 12 小時期限內向 Apple 傳送準確的消費資料,並在 24 小時內回覆 Google Play 的退單審查,因為這是兩家商店僅有的兩個徵詢你方說法的時刻。
值得向 Apple 申請權限嗎?
如果你銷售自動續訂型訂閱,而且已經在處理 App Store Server Notifications V2,那麼大概值得。取消畫面是訂閱者離開前你能接觸到他們的最後一個地方,而換方案的代價比徹底失去他們要小。只是要為一個在每次訂閱頁面瀏覽時都要回應的端點編好預算,並把退款防線放在退款真正發生的地方。
常見問題解答
- 什麼是 Apple 的 Retention Messaging API?
- 它是一個伺服器對伺服器的 API,讓開發者選擇訂閱者在自動續訂型訂閱上點選 Cancel Subscription 後看到的訊息。Apple 支援四種類型:文字、附圖片的文字、換方案建議和促銷優惠。Apple 的文件仍將其描述為需要開發者申請加入的預先發布功能。
- 我的 Get Retention Message 端點需要多快回應?
- 正式環境中須在 700 ms 內回應。如果你的伺服器太慢或出錯,Apple 會顯示為該產品和語言地區設定的預設訊息;如果沒有預設訊息,則什麼都不顯示。在 Apple 允許你設定正式環境 URL 之前,你還必須通過一項約 700 ms 的沙盒效能測試。
- 顧客申請退款時會出現挽留訊息嗎?
- 不會。Apple 只在顧客點選 Cancel Subscription 後的 Confirm Cancellation 畫面上顯示挽留訊息。退款申請透過 reportaproblem.apple.com 或由 beginRefundRequest 開啟的 App 內退款表單送出,開發者在那裡唯一的輸入是 CONSUMPTION_REQUEST,須在 12 小時內回覆,且前提是顧客同意。
- 如何在 App Store Server Notifications 中區分退款申請和取消?
- 單憑續訂通知無法區分。從「訂閱項目」設定頁面取消,和透過你的 App 發起的退款申請,都會產生子類型為 AUTO_RENEW_DISABLED 的 DID_CHANGE_RENEWAL_STATUS。同一筆交易隨後出現的 CONSUMPTION_REQUEST,以及之後的 REFUND 或 REFUND_DECLINED 通知,才代表有退款申請正在進行。
- Google Play 允許開發者在使用者取消時顯示訊息嗎?
- Google 的訂閱生命週期文件沒有描述這類功能。開發者會在事後收到 SUBSCRIPTION_CANCELED 通知,並可以讀取 userInitiatedCancellation 欄位了解使用者取消的原因。暫停功能預設對所有訂閱啟用,是 Google Play 對抗主動流失的主要內建工具。
資料來源與延伸閱讀
- Apple Developer Documentation: Retention Messaging API
- Apple Developer Documentation: Setting up your Get Retention Message endpoint
- Apple Developer Documentation: Upload Message
- Apple Developer Documentation: Retention Messaging API changelog
- Apple Developer Documentation: notificationType
- Apple Developer Documentation: Send Consumption Information
- Apple Support: Request a refund for apps or content that you bought from Apple
- Google Play Billing: Subscription lifecycle
- Google Play Billing: Real-time developer notifications reference
- Google Play Console Help: Updates to refund protection and chargeback cost responsibility
RefundHalt
App Store 與 Google Play 的退款自動駕駛
繼續閱讀
你的 App ROAS 仍在計入 Apple 和 Google 已退款的購買,請改用淨 ROAS 出價
退款很少回傳到廣告平台,因此 ROAS 仍在計入 Apple 和 Google 早已退款的購買。本文說明 Firebase、Google Ads 和 AdAttributionKit 在哪些環節遺漏退款、這會造成多少損失,以及如何為 App 建立淨 ROAS。
客戶收據上的 App Store 訂單 ID 能告訴你他們買了什麼,以及 Apple 是否已經退款
Apple 的 Look Up Order ID 端點能把客戶 App Store 收據上的訂單 ID 轉換成已簽署的交易,其中包含退款日期與原因。本文說明如何用它處理退款郵件、它做不到什麼,以及 Google Play 的訂單 ID 有何不同。