Bỏ lỡ thông báo hoàn tiền có thể khiến bạn mất những khoản hoàn tiền duy nhất bạn được quyền phản đối, và cả hai cửa hàng đều cho phép bạn lấy lại nếu kiểm tra kịp thời
Khi máy chủ của bạn bỏ lỡ một thông báo hoàn tiền, hai quy trình hoàn tiền cần bằng chứng của bạn sẽ khép lại mà không có bạn. Bài viết này giải thích cách Apple và Google Play gửi lại, bạn có thể khôi phục thông báo hoàn tiền bị bỏ lỡ từ bao lâu trước đó, và những khoảng trống trong việc khôi phục nằm ở đâu.

Điểm chính
- Apple thử gửi lại một lần gửi App Store Server Notifications V2 thất bại năm lần, vào 1, 12, 24, 48 và 72 giờ sau lần thử trước, nên lần thử lại thứ hai đến khoảng 13 giờ sau lần gửi đầu tiên.
- Apple yêu cầu nhà phát triển trả lời CONSUMPTION_REQUEST trong vòng 12 giờ kể từ khi nhận, nên một máy chủ bỏ lỡ lần gửi đầu và lần thử lại sau một giờ có thể chỉ thấy yêu cầu khi thời hạn gần như chắc chắn đã qua.
- Endpoint Get Notification History của Apple trả về các thông báo V2 trong 180 ngày qua ở môi trường production, 20 bản ghi mỗi trang, và cờ onlyFailures giới hạn kết quả ở những thông báo chưa từng đến máy chủ của bạn, cộng với những thông báo vẫn đang được thử lại.
- Google Play chỉ gửi yêu cầu xem xét chargeback qua PendingRefundReviewNotification, và pendingRefundToken cần để gọi orders.reviewrefund trong vòng 24 giờ nằm trong chính thông báo đó. Google không mô tả API riêng nào liệt kê các yêu cầu xem xét đang chờ.
- Google Cloud Pub/Sub giữ các tin nhắn chưa được xác nhận trong 7 ngày theo mặc định, tối đa 31 ngày, và xóa một subscription sau 31 ngày không có hoạt động của subscriber, trừ khi bạn thay đổi thời hạn hết hạn của nó.
- Voided Purchases API của Google Play khôi phục các khoản hoàn tiền, thu hồi và chargeback trong 30 ngày qua, với hạn mức 6.000 truy vấn mỗi ngày và 30 truy vấn trong mỗi khoảng 30 giây, nhưng không thể khôi phục một yêu cầu xem xét chargeback mà bạn chưa từng trả lời.
- Sandbox của Apple gửi mỗi thông báo một lần và không thử lại, nên một quy trình khôi phục chỉ từng chạy trên sandbox chưa bao giờ được kiểm thử với lịch thử lại thực tế của Apple.
Bỏ lỡ thông báo hoàn tiền là cách âm thầm khiến nhà phát triển mất đi hai quyết định hoàn tiền duy nhất mà họ có tiếng nói. CONSUMPTION_REQUEST của Apple và yêu cầu xem xét chargeback của Google Play đều bắt đầu bằng một thông báo, và cả hai đều khép lại sau một khoảng thời gian ngắn: 12 giờ với Apple, 24 giờ với Google. Nếu máy chủ của bạn ngừng hoạt động, chậm hoặc cấu hình sai khi tin nhắn đó đến, cửa hàng sẽ không chờ bạn. Cửa hàng quyết định dựa trên những gì họ đã có.
Tin tốt là không cửa hàng nào vứt bỏ tin nhắn ngay lần thất bại đầu tiên. Apple thử lại và lưu lịch sử 180 ngày mà bạn có thể truy vấn. Google phát hành qua Pub/Sub, nơi giữ các tin nhắn chưa được xác nhận trong nhiều ngày. Tin xấu là thời điểm thử lại không khớp với thời hạn phản hồi, và một trong hai quy trình hoàn toàn không có API khôi phục.
Cách mỗi cửa hàng gửi thông báo hoàn tiền
Apple gửi App Store Server Notifications thẳng đến một URL HTTPS mà bạn đặt trong App Store Connect. Google không gọi trực tiếp máy chủ của bạn. Google phát hành Real-time developer notifications lên một topic Google Cloud Pub/Sub, và subscription của bạn trên topic đó sẽ đẩy chúng đến endpoint của bạn hoặc chờ máy chủ của bạn kéo về.
| Câu hỏi | App Store | Google Play |
|---|---|---|
| Kênh gửi | HTTPS POST đến URL của bạn | Topic Cloud Pub/Sub, push hoặc pull |
| Thế nào là thành công | HTTP 200 đến 206 | Xác nhận tin nhắn Pub/Sub, hoặc mã thành công trên endpoint push |
| Thử lại | 5 lần với V2, vào 1, 12, 24, 48 và 72 giờ sau lần thử trước | Pub/Sub gửi lại cho đến khi được xác nhận hoặc hết thời gian lưu giữ |
| Tin nhắn bị bỏ lỡ tồn tại bao lâu | 180 ngày trong Get Notification History | 7 ngày theo mặc định trong subscription, tối đa 31 ngày |
| Hoàn tiền cần bằng chứng của bạn | CONSUMPTION_REQUEST, trả lời trong 12 giờ | PendingRefundReviewNotification, trả lời trong 24 giờ |
| Phương án dự phòng kiểu pull cho hoàn tiền đã chấp thuận | Get Notification History, Get Refund History | Voided Purchases API, 30 ngày qua |
| Hành vi trong sandbox hoặc khi thử nghiệm | Một lần gửi, không thử lại | Send Test Message từ Play Console |
Apple coi điều gì là thất bại
Tài liệu của Apple rất cụ thể. Trả về bất kỳ mã nào từ 200 đến 206 thì lần gửi hoàn tất. Trả về 40x hoặc 50x thì Apple thử lại. Apple cũng coi mọi mã khác là không thành công. Mỗi lần thử được ghi lại với một sendAttemptResult, và các giá trị đọc lên như một danh sách kiểm tra các sự cố thực tế: TIMED_OUT, TLS_ISSUE, CIRCULAR_REDIRECT, NO_RESPONSE, PREMATURE_CLOSE, UNSUCCESSFUL_HTTP_RESPONSE_CODE và một vài giá trị khác. Với TIMED_OUT, chính Apple khuyên bạn kiểm tra xem máy chủ có đang xử lý tin nhắn ngay trong lúc nhận hay không.
Google coi điều gì là thất bại
Với subscription kiểu push, mã phản hồi thành công từ endpoint của bạn chính là sự xác nhận. Với subscription kiểu pull, máy chủ của bạn phải xác nhận từng tin nhắn đã kéo về, nếu không Pub/Sub sẽ gửi lại. Thời hạn xác nhận mặc định là 10 giây và tối đa là 600 giây. Hướng dẫn RTDN của Google thêm một quy tắc đáng nhắc lại: thông báo chỉ cho biết có điều gì đó đã thay đổi, nên bạn vẫn phải gọi Google Play Developer API để lấy trạng thái đầy đủ của giao dịch mua.
Vì sao lịch thử lại của Apple không khớp với thời hạn 12 giờ
Khoảng thời gian thử lại của Apple được tính từ lần thử trước, không phải từ lần đầu tiên. Cộng dồn lại, bạn có dòng thời gian sau cho một thông báo V2 mà máy chủ của bạn liên tục không nhận được.
| Lần thử | Thời gian chờ sau lần thử trước | Số giờ kể từ lần thử đầu tiên |
|---|---|---|
| Lần gửi đầu tiên | Không có | 0 |
| Thử lại 1 | 1 giờ | 1 |
| Thử lại 2 | 12 giờ | 13 |
| Thử lại 3 | 24 giờ | 37 |
| Thử lại 4 | 48 giờ | 85 |
| Thử lại 5 | 72 giờ | 157 |
Apple yêu cầu bạn phản hồi trong vòng 12 giờ kể từ khi nhận CONSUMPTION_REQUEST. Nếu máy chủ của bạn ngừng hoạt động trong lần gửi đầu tiên và lần thử lại một giờ sau đó, lần thử tiếp theo sẽ đến 13 giờ sau lần đầu. Apple không nói rõ liệu một yêu cầu được nhận lần đầu qua lần thử lại có được thêm 12 giờ mới hay không. Cách hiểu thận trọng là coi lần thử đầu tiên là thời điểm bắt đầu tính giờ, nghĩa là chỉ dựa vào thử lại sẽ không cứu được một yêu cầu bạn đã bỏ lỡ quá một giờ.
Apple có thử lại sau HTTP 400 không?
Có, theo tài liệu. Apple liệt kê 40x và 50x là các mã kích hoạt việc thử lại. Vào tháng 3 năm 2026, một nhà phát triển báo cáo trên diễn đàn của Apple rằng việc thử lại sau phản hồi 400 dường như đã dừng, sau đó cho biết việc gửi đã tiếp tục một hai ngày sau, và Apple đề nghị gửi báo cáo qua Feedback Assistant. Hãy coi hành vi được ghi trong tài liệu là quy tắc, và việc giám sát của chính bạn là bằng chứng.
Khôi phục thông báo App Store bị bỏ lỡ bằng Get Notification History
Get Notification History trả về các thông báo phiên bản 2 mà Apple đã cố gửi đến máy chủ của bạn trong khoảng thời gian bạn chọn. Mỗi bản ghi chứa toàn bộ payload đã ký, nên bạn có thể đưa nó vào cùng handler như một thông báo trực tiếp. Mỗi bản ghi cũng có một mảng sendAttempts gồm tối đa sáu mục, một cho lần thử đầu tiên và một cho mỗi lần trong năm lần thử lại.
- startDate và endDate là bắt buộc, và startDate phải nằm trong 180 ngày qua ở production hoặc 30 ngày qua ở sandbox.
- Đặt onlyFailures thành true để chỉ nhận những thông báo chưa đến được máy chủ của bạn, cộng với những thông báo Apple vẫn đang thử lại.
- Lọc theo một notificationType, chẳng hạn CONSUMPTION_REQUEST hoặc REFUND, hoặc theo transactionId cho một khách hàng, nhưng không dùng cả hai trong cùng một yêu cầu.
- Mỗi lần gọi trả về tối đa 20 bản ghi. Tiếp tục gọi với paginationToken khi hasMore còn là true, và gửi cùng một request body mỗi lần.
Có một lưu ý quan trọng với hoàn tiền. Apple cho biết bản ghi lịch sử phản ánh trạng thái giao dịch mua tại thời điểm thông báo được gửi lần đầu, không phải hiện tại. Vì vậy một REFUND được khôi phục là một dữ kiện về quá khứ. Trước khi thu hồi quyền truy cập, hãy kiểm tra trạng thái hiện tại bằng các endpoint trạng thái giao dịch hoặc gói đăng ký.
Không thể khôi phục thông báo V1 theo cách này
Get Notification History chỉ áp dụng cho phiên bản 2. Apple thử lại thông báo V1 ba lần, vào 6, 24 và 48 giờ sau lần thử trước, và nếu tất cả đều thất bại thì không có lịch sử nào để phát lại. Đó là thêm một lý do để chuyển mọi ứng dụng còn dùng V1 sang V2.
Khôi phục thông báo hoàn tiền Google Play bị bỏ lỡ
Lưới an toàn của Google chính là Pub/Sub. Miễn là subscription của bạn còn tồn tại, một tin nhắn chưa ai xác nhận sẽ nằm đó trong suốt thời gian lưu giữ, 7 ngày theo mặc định và tối đa 31 ngày nếu bạn tăng lên. Khi endpoint của bạn hoạt động trở lại, việc gửi sẽ tiếp tục. Có hai thiết lập có thể âm thầm làm hỏng điều đó.
- Một dead-letter topic sẽ chuyển tin nhắn ra khỏi subscription của bạn sau một số lần gửi thất bại nhất định. Mặc định là 5, và với chính sách thử lại mặc định là gửi lại ngay lập tức, năm lần thử có thể trôi qua rất nhanh. Nếu bạn dùng nó, hãy theo dõi dead-letter topic như một hộp thư thứ hai.
- Một subscription không có hoạt động của subscriber, chẳng hạn kết nối đang mở, lượt pull đang chạy hoặc lượt push thành công, sẽ hết hạn sau 31 ngày theo mặc định. Một endpoint hỏng suốt một tháng có thể mất luôn subscription, cùng mọi thứ đang chờ bên trong.
Hoàn tiền đã hủy có phương án dự phòng 30 ngày
Với những khoản hoàn tiền đã xảy ra, Voided Purchases API là phương án dự phòng kiểu pull. API này liệt kê các giao dịch mua bị hủy trong 30 ngày qua, tối đa 1.000 mục mỗi trang, với hạn mức 6.000 truy vấn mỗi ngày và 30 truy vấn trong mỗi khoảng 30 giây cho mỗi ứng dụng. Truyền type 1 để bao gồm cả gói đăng ký bên cạnh sản phẩm mua một lần. Chạy API này hằng ngày sẽ bắt được mọi khoản hoàn tiền mà hệ thống thông báo của bạn bỏ sót, giúp quyền truy cập và số liệu doanh thu luôn chính xác.
Yêu cầu xem xét chargeback thì không có
PendingRefundReviewNotification thì khác. Nó mang pendingRefundToken mà bạn phải truyền vào orders.reviewrefund, và bạn có 24 giờ kể từ khi nhận để gửi lựa chọn hoàn tiền và bằng chứng sử dụng. Google ghi nhận lần gọi đầu tiên của bạn và bỏ qua những lần sau. Tài liệu của Google không mô tả endpoint nào liệt kê các yêu cầu xem xét đang chờ, nên nếu tin nhắn Pub/Sub đó bị mất, bằng chứng của bạn cho chargeback đó cũng mất theo.
Một thông báo hoàn tiền bị bỏ lỡ gây thiệt hại bao nhiêu tiền
Bỏ lỡ thông báo cho một khoản hoàn tiền đã có kết quả cuối cùng chỉ gây phiền toái về sổ sách. Bạn tìm thấy nó sau đó trong Voided Purchases API hoặc Get Notification History, thu hồi quyền truy cập nếu chính sách của bạn yêu cầu, và báo cáo của bạn sẽ được cập nhật. Phiền, nhưng không tốn kém.
Bỏ lỡ thông báo trong một trong hai quy trình có thể phản đối thì gây thiệt hại tiền thật, vì cửa hàng quyết định mà không có bằng chứng của bạn. Với Apple, điều đó có nghĩa là quyết định hoàn tiền được đưa ra mà không có dữ liệu sử dụng của bạn. Với Google Play, đối với các đơn hàng đặt sau ngày 3 tháng 8 năm 2026, một chargeback bị thua khiến bạn mất giá mua trừ phí dịch vụ của Play, cộng thêm phí chargeback mà ngân hàng của người mua tính. Google chỉ chịu phần phí dịch vụ của chính mình.
Và số tiền bạn đã chi để cung cấp giao dịch mua đó đã mất trước khi tranh chấp bắt đầu.
- Điện toán: thời gian GPU và máy chủ đằng sau mỗi lần tạo nội dung, render hoặc phản hồi mô hình mà người mua đã dùng.
- Lệnh gọi API: các yêu cầu đến bên thứ ba bị tính phí ngay khi được gửi, thường theo từng lệnh gọi.
- Lưu trữ: tệp và nội dung đa phương tiện người mua đã tạo, vẫn nằm trên hóa đơn hosting của bạn.
- Chi trả: phần chia doanh thu đã trả cho nhà sáng tạo, đối tác liên kết hoặc đối tác cho giao dịch đó.
Không khoản nào trong số đó quay lại khi hoàn tiền được chấp thuận. Bằng chứng bạn gửi trong 12 hoặc 24 giờ đó là đòn bẩy duy nhất bạn có, và một thông báo bị bỏ lỡ sẽ lấy mất nó.
Một quy trình khôi phục đáng tin cậy
- Xác nhận trước. Lưu payload gốc, trả về mã thành công, rồi xử lý trong hàng đợi.
- Thăm dò Get Notification History của Apple với onlyFailures vài phút một lần cho CONSUMPTION_REQUEST, để một sự cố chỉ làm bạn mất vài phút trong thời hạn 12 giờ.
- Chạy một lượt quét Get Notification History hằng ngày với onlyFailures cho vài ngày gần nhất ở mọi loại, và phát lại những gì bạn tìm thấy.
- Gọi Voided Purchases API hằng ngày với type 1 cho từng ứng dụng Google Play, và đối chiếu với các khoản hoàn tiền bạn đã ghi nhận.
- Trên Pub/Sub, giữ thời gian lưu tin nhắn từ 7 ngày trở lên, đặt cảnh báo cho dead-letter topic nếu có, và cảnh báo khi các tin nhắn chưa gửi được dồn lại.
- Kiểm thử toàn bộ luồng ở production nữa. Sandbox của Apple gửi mỗi thông báo một lần và không thử lại, còn Request a Test Notification cùng với Get Test Notification Status cho thấy chính xác máy chủ của bạn đã phản hồi ra sao.

RefundHalt nhận thông báo từ cả hai cửa hàng thay bạn, tự động trả lời CONSUMPTION_REQUEST và yêu cầu xem xét chargeback trong thời hạn, nên bạn không phải là người canh đồng hồ.
Câu hỏi thường gặp
- Apple tiếp tục thử gửi lại một thông báo máy chủ App Store thất bại trong bao lâu?
- Khoảng sáu ngày rưỡi với phiên bản 2. Apple thử lại năm lần, vào 1, 12, 24, 48 và 72 giờ sau lần thử trước, nên lần thử lại cuối cùng đến 157 giờ sau lần gửi đầu tiên. Thông báo phiên bản 1 được thử lại ba lần, vào 6, 24 và 48 giờ sau lần thử trước.
- Tôi có thể khôi phục thông báo máy chủ App Store bị bỏ lỡ từ bao lâu trước đó?
- 180 ngày ở production. Endpoint Get Notification History của Apple trả về thông báo phiên bản 2 trong 180 ngày qua, hoặc 30 ngày qua ở sandbox, 20 bản ghi mỗi lần gọi, và cờ onlyFailures giới hạn kết quả ở những thông báo chưa từng đến máy chủ của bạn.
- Apple có thử gửi lại thông báo nếu máy chủ của tôi trả về HTTP 400 không?
- Có, theo tài liệu của Apple. Apple thử lại khi máy chủ của bạn trả về mã 40x hoặc 50x, và coi 200 đến 206 là thành công. Mọi mã khác cũng được tính là không thành công.
- Tôi có thể khôi phục một yêu cầu xem xét chargeback Google Play bị bỏ lỡ không?
- Chỉ khi tin nhắn Pub/Sub vẫn còn tồn tại. pendingRefundToken bạn cần cho orders.reviewrefund đến trong PendingRefundReviewNotification, và Google không mô tả API nào liệt kê các yêu cầu xem xét đang chờ, nên các tin nhắn chưa được xác nhận trong subscription, được giữ 7 ngày theo mặc định, là bản sao duy nhất của bạn.
- Làm sao tìm các khoản hoàn tiền Google Play mà máy chủ của tôi đã bỏ lỡ?
- Gọi Voided Purchases API. API này trả về các giao dịch mua bị hủy trong 30 ngày qua, bao gồm hoàn tiền, thu hồi và chargeback, tối đa 1.000 kết quả mỗi trang với hạn mức 6.000 truy vấn mỗi ngày cho mỗi ứng dụng. Truyền type 1 để bao gồm cả gói đăng ký.
Nguồn và tài liệu đọc thêm
- Apple Developer: Responding to App Store Server Notifications
- Apple Developer: Get Notification History
- Apple Developer: NotificationHistoryRequest
- Apple Developer: Send Consumption Information
- Android Developers: Real-time developer notifications reference
- Android Developers: Help Google dispute chargebacks
- Google Play Developer API: Voided Purchases API
- Google Cloud: Pub/Sub subscription properties
- Play Console Help: Updates to refund protection and chargeback cost responsibility
RefundHalt
Chế độ tự động xử lý hoàn tiền cho App Store và Google Play
Đọc tiếp
Yêu cầu hoàn tiền quá mức có thể khiến bạn mất nhiều hơn chính khoản hoàn tiền, vì cả hai kho ứng dụng đều coi đó là tín hiệu chất lượng
Hướng dẫn 5.6.4 của Apple nêu rõ yêu cầu hoàn tiền quá mức là dấu hiệu ứng dụng không đạt chuẩn chất lượng, còn Thỏa thuận phân phối của Google cho phép gỡ ứng dụng của nhà phát triển mới dựa trên tỷ lệ hoàn tiền. Đây là những gì mỗi kho quy định, cái giá khi bị gỡ và cách tránh rủi ro.
Hãy xác minh thông báo máy chủ App Store trước khi xử lý hoàn tiền, vì bất kỳ ai cũng có thể gửi yêu cầu đến URL webhook của bạn
Một thông báo hoàn tiền chỉ là một yêu cầu HTTPS cho đến khi bạn kiểm tra chữ ký của nó. Bài viết này hướng dẫn cách xác minh thông báo máy chủ App Store và tin nhắn RTDN của Google Play, mỗi cửa hàng ký những gì, và một khoản hoàn tiền giả mạo hoặc bị từ chối nhầm khiến bạn tốn bao nhiêu.