Ai đó mở Report a Problem, chọn ứng dụng của bạn và yêu cầu Apple hoàn tiền. Apple không tự quyết định ngay. Nó ping server của bạn trước, hỏi bạn biết gì về giao dịch mua đó, rồi chờ khoảng 12 giờ để nhận câu trả lời.
Cú ping đó chính là Apple CONSUMPTION_REQUEST. Rất nhiều team có doanh thu IAP thực sự chưa từng nghe đến nó. Nhiều team khác thấy nó một lần trong log rồi bỏ đó. Nếu bạn cũng vậy, bài
giải thích về Apple CONSUMPTION_REQUEST của chúng tôi đã nói rõ nó là gì và tại sao. Bài này là phần trả lời. Gửi gì, không gửi gì, và chuyện gì đã xảy ra với những người từng thử.
Những điểm chính
Apple gửi CONSUMPTION_REQUEST khi khách hàng yêu cầu hoàn tiền. Bạn có khoảng 12 giờ. Sau đó Apple tự quyết mà không cần bạn.
Phản hồi gồm năm trường. Không phải năm mươi. Năm.
Refund preference của bạn đúng nghĩa chỉ là một mong muốn. Apple từng bác bỏ nó và sẽ còn làm vậy.
Khách hàng không đồng ý thì không phản hồi. Đó là lời của Apple, không phải của chúng tôi.
Một ứng dụng đã giảm tỷ lệ hoàn tiền từ 3% xuống 1.9% trong khoảng hai tuần chỉ bằng cách bắt đầu trả lời. Nó chưa bao giờ yêu cầu Apple từ chối bất cứ điều gì.
Không ai làm việc này thủ công được lâu. Thời hạn quá ngắn và các yêu cầu đến vào những giờ oái oăm.
Vậy chính xác Apple CONSUMPTION_REQUEST là gì?
Đó là một server notification, một trong nhiều thông báo Apple đẩy qua App Store Server Notifications V2. Thông báo này được kích hoạt khi ai đó yêu cầu hoàn tiền cho một giao dịch mua trong ứng dụng. Trước đây nó chỉ áp dụng cho consumable. Từ WWDC24, nó bao gồm cả auto-renewable subscription, nơi phần lớn doanh thu nằm ở đó.
Bên trong payload: transaction đã ký, product ID và lý do khách hàng chọn. Tài liệu
consumption Request Reason của Apple liệt kê năm lý do: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL, OTHER.
Thứ bạn sẽ không tìm thấy là tên hay Apple ID. Chỉ có một transaction identifier. Biến nó thành "đây là user 48213 và cô ấy đã mở ứng dụng 40 lần kể từ khi mua" là việc của bạn, và nó chỉ khả thi nếu bạn đã gắn App AccountToken lúc thanh toán. Chúng tôi đã viết
hẳn một bài về appAccountToken vì quá nhiều người bỏ qua bước này.
Apple hỏi, bạn trả lời, Apple quyết định. Đó là hình hài của các yêu cầu hoàn tiền Apple đối với nhà phát triển.
Cách phản hồi Apple CONSUMPTION_REQUEST
Bạn PUT một JSON body nhỏ tới endpoint Send Consumption Information của Apple, với transaction ID trong path. Body đó chính là Apple consumption information mà hệ thống hoàn tiền sẽ đọc.
Customer Consented đứng đầu. True hoặc false. Nếu là false, dừng lại. Đừng gửi gì cả. Tài liệu của Apple nói rằng nếu không có sự đồng ý, bạn hoàn toàn không nên phản hồi. Lạ, nhưng luật là vậy.
Tiếp theo là delivery status. DELIVERED nếu đã giao thành công. Nếu không, có các biến thể UNDELIVERED cho vấn đề chất lượng, sai mặt hàng, server ngừng hoạt động và lý do khác.
Sample Content Provided là câu trả lời có hoặc không cho việc khách hàng có được dùng thử trước khi mua hay không. Dùng thử miễn phí, có. Xem trước nội dung, có. Một paywall với ba gạch đầu dòng, có lẽ là không.
Consumption Percentage khiến nhiều người vấp. Nó tính bằng milliunit, nên 100000 nghĩa là đã dùng hết và 50000 là một nửa. Bỏ trống trường này với auto-renewable subscription. Apple tự tính từ chu kỳ thanh toán.
Và cuối cùng là refund Preference. DECLINE, GRANT_FULL hoặc GRANT_PRORATED. Không bắt buộc. Cũng là nơi duy nhất bạn được nói mình muốn gì.
Một phản hồi cho gói xu đã được tiêu hết:
Apple trả về 202 và không gì khác. Không có phán quyết. Một kỹ sư Apple trên diễn đàn nhà phát triển đã nói từ năm 2021: 202 nghĩa là dữ liệu của bạn "sẽ được xem xét". Đó là toàn bộ lời hứa.
Đừng gửi DECLINE cho mọi thứ
Tôi biết điều đó rất hấp dẫn. Hãy kiềm chế.
Đọc lý do trước. FULFILLMENT_ISSUE nghĩa là hãy kiểm tra log giao hàng. Nếu giao dịch thực sự không đến tay khách, gửi trạng thái UNDELIVERED tương ứng kèm GRANT_FULL rồi bỏ qua. Bạn sẽ không thắng ca đó, và cố gắng thắng chỉ khiến các DECLINE sau này của bạn trông yếu hơn.
UNINTENDED_PURCHASE là chuyện mức độ sử dụng. Mua lúc 9:02, yêu cầu hoàn tiền lúc 9:05, không có phiên nào ở giữa? Có lẽ là bấm nhầm. Cho qua. Dùng hàng ngày suốt một tuần? DECLINE, kèm con số tiêu thụ thực của bạn.
UNSATISFIED_WITH_PURCHASE là lúc Sample Content Provided phát huy giá trị. Đã có bản dùng thử và đã dùng 80%? Từ chối. Hầu như chưa mở? GRANT_PRORATED là phương án trung dung hợp lý.
Với LEGAL và OTHER, gửi dữ liệu chính xác và bỏ qua preference trừ khi hồ sơ của bạn khiến quyết định trở nên hiển nhiên.
Một DECLINE đi kèm 95% tiêu thụ và bản dùng thử miễn phí là một phản hồi mạnh. Một DECLINE cho thứ chỉ được dùng chín mươi giây trông như phản xạ vô điều kiện.
Chuyện thực sự đã xảy ra với những người làm điều này
Dipsea là một ứng dụng audio mà RevenueCat mua lại vào tháng 9 năm 2024 và dùng để thử nghiệm trình xử lý hoàn tiền của chính họ. Ngày 23 tháng 10, họ bắt đầu trả lời các consumption request với preference đặt ở "để Apple quyết định". Không DECLINE. Chỉ có dữ liệu. Trong khoảng 15 ngày, tỷ lệ hoàn tiền giảm từ mức 3% đều đặn xuống 1.9%.
Họ đã công bố biểu đồ.Với tôi, đó là điểm dữ liệu hữu ích nhất về chủ đề này. Chỉ riêng dữ liệu đã làm con số thay đổi.
Rồi đến mặt còn lại. Tháng 3 năm 2024, một studio game đăng trên Apple Developer Forums rằng họ đang gửi consumption info mà Apple vẫn chấp thuận "gần như toàn bộ" yêu cầu hoàn tiền cho số xu người chơi đã tiêu hết. Consumable là trường hợp khó. Một khi xu đã tiêu, Apple không thể thu hồi. Nếu bạn không tự thu hồi số dư sau thông báo REFUND, bạn mất cả tiền lẫn xu.
Và tháng 5 năm 2025, một thread trên r/iOSProgramming ngập tràn người dùng RevenueCat đã đặt "always prefer declining" rồi đột nhiên thấy mọi yêu cầu hoàn tiền đều được chấp thuận. RevenueCat nói đó là thay đổi chính sách từ phía Apple. Dù nguyên nhân là gì, nó đã khép lại một tranh cãi cũ. Refund Preference không phải là một công tắc. DECLINE hàng loạt là một pattern, và Apple có thể lọc bỏ nó.
Những cách để nhận về lỗi 400
Apple rất khắt khe với body. Đây là những lỗi chúng tôi thấy lặp đi lặp lại.
Chuyện milliunit. Ai đó đọc thấy "percentage", gửi 100, và thế là đã báo với Apple rằng khách hàng dùng một phần mười của một phần trăm. Khoảng giá trị là từ 0 đến 100000.
Phần trăm khác 0 cho mặt hàng chưa giao. Nếu delivery Status không phải DELIVERED, Consumption Percentage phải là 0, nếu không yêu cầu sẽ bị trả về.
Bất kỳ phần trăm nào cho auto-renewable subscription. Apple có hẳn một mã lỗi riêng cho việc này. Hãy bỏ trống.
Sai key. Lệnh gọi này cần In-App Purchase key, được tạo trong App Store Connect ở mục Users and Access, rồi Integrations. Không phải App Store Connect API key, dù trông chúng giống hệt nhau. Dùng sai key sẽ nhận lỗi 401 và mất một giờ nghi ngờ JWT của mình.
Bỏ qua sự đồng ý. Không phải lỗi HTTP, mà là lỗi tuân thủ. Hãy đưa điều khoản này vào terms của bạn trước khi đưa vào vận hành.
Hãy test trên sandbox trước. Một lưu ý: tài liệu testing của Apple chỉ cho bạn năm phút ở đó, không phải mười hai giờ. Nếu server của bạn mất sáu phút, bài test sẽ bỏ qua dữ liệu của bạn. Để ép một quyết định từ chối, chọn Other trên refund sheet và gõ DECLINE.
Nhà phát triển xử lý yêu cầu hoàn tiền App Store thế nào khi số lượng quá lớn
Nói thẳng thì phần lớn là không xử lý. Yêu cầu đến lúc 3 giờ sáng. Hoặc thứ Bảy. Hoặc ngày lễ khi người duy nhất hiểu pipeline đang offline. Mười hai giờ trôi qua. Apple phán quyết dựa trên lời của khách hàng.
Cách xử lý yêu cầu hoàn tiền Apple với tư cách nhà phát triển quy về một quyết định. Tự xây toàn bộ chuỗi (xác minh JWS, tra cứu user, lấy dữ liệu sử dụng, tính phần trăm, tạo JWT, gọi endpoint, ghi log, retry) và duy trì nó mãi mãi. Hoặc cắm vào một phần mềm quản lý hoàn tiền Apple đã làm sẵn những việc đó.
Refund Sensor là một lựa chọn trong nhóm thứ hai. Bạn dán notification URL của chúng tôi vào App Store Connect, kết nối key, và các phản hồi được gửi đi trong vài giây. Trên các ứng dụng đang dùng hiện nay, 77% yêu cầu đủ điều kiện đã được bảo vệ, với khoảng $33 được giữ lại mỗi ca. Không có gì cao siêu ở đây. Một phản hồi với dữ liệu thực được gửi đi mọi lần, trước thời hạn. Nếu bạn muốn tham khảo thêm, hướng dẫn công cụ quản lý hoàn tiền Apple
của chúng tôi liệt kê những câu cần hỏi.
Đó là lý do tự động hóa hoàn tiền Apple cho nhà phát triển liên tục được nhắc đến. Mười hai giờ, mọi yêu cầu, mỗi tuần, không phải việc dành cho con người. Dù chọn gì, hãy chọn một thứ. Im lặng nghĩa là Apple chỉ nghe một phía.
Câu hỏi thường gặp
Mười hai giờ trên production, năm phút trên sandbox. Cả hai đều có trong tài liệu của Apple.
Không. Apple gọi thông tin tiêu thụ của bạn là "một trong nhiều yếu tố". Nó cải thiện cơ hội của bạn, nhưng không quyết định điều gì cả.
Có, mọi yêu cầu mà khách hàng đã đồng ý. Kể cả những trường hợp bạn gửi GRANT_FULL vì server của bạn bị sập. Phản hồi trung thực ở các ca dễ chính là lý do Apple tin tưởng các DECLINE của bạn sau này
deliveryStatus và sampleContentProvided, một cách chính xác. Bỏ qua phần trăm. Rồi đi sửa hệ thống tracking của bạn.
Có. DECLINE và GRANTFULL hoạt động với mọi loại sản phẩm. GRANTPRORATED cũng vậy, chỉ là Apple tự tính toán phần chia tỷ lệ cho các gói tự động gia hạn.





