Mọi khoản hoàn tiền trên App Store đều do Apple quyết định, nhưng Apple không muốn đưa ra quyết định đó mà thiếu thông tin. Một yêu cầu hoàn tiền sẽ tạm dừng quy trình, gửi một câu hỏi đến server của bạn, và mở ra một khoảng thời gian cố định để bạn phản hồi bằng các thông tin thực tế về giao dịch mua. Phản hồi một cách thực chất, và các yêu cầu vô lý sẽ bị từ chối. Im lặng, và lời kể của khách hàng sẽ là phiên bản duy nhất mà Apple nghe được.
Những điểm chính
Các yêu cầu hoàn tiền trên App Store khiến Apple gửi đến server của bạn một thông báo CONSUMPTION_REQUEST, sau đó chờ tối đa 12 giờ để nhận bằng chứng trước khi đưa ra quyết định.
Phản hồi nghĩa là gọi endpoint Send Consumption Information với một payload gọn nhẹ: sự đồng ý, trạng thái giao hàng, việc có bản mẫu thử hay không, mức độ đã sử dụng, và kết quả bạn mong muốn.
Không gửi gì cũng chính là một kiểu phản hồi. Apple sẽ tiếp tục xử lý chỉ dựa trên lời khai của khách hàng cùng với lịch sử tài khoản của họ.
Sự đồng ý đóng vai trò như một rào chắn bắt buộc. Tài liệu của Apple nói rõ rằng bạn không nên phản hồi nếu khách hàng chưa đồng ý cho chia sẻ dữ liệu consumption của họ.
Với các gói đăng ký tự động gia hạn, tỷ lệ consumption do Apple tự tính dựa trên thời gian đã trôi qua, và nếu bạn cung cấp số liệu riêng sẽ gây ra lỗi.
Không có quy trình thủ công nào kịp hoàn thành trong khoảng thời gian đó. Những nhà phát triển có lợi từ việc này là những người có phản hồi được soạn và gửi đi một cách tự động.
Mọi khoản hoàn tiền trên App Store đều bắt đầu giống nhau: ai đó truy cập reportaproblem.apple.com, chọn một giao dịch mua, và chọn một lý do.
Thông báo mà hầu hết không được phản hồi
Các ứng dụng được cấu hình App Store Server Notifications V2 sẽ nhận được một thông báo CONSUMPTION_REQUEST ngay khi khoản hoàn tiền được yêu cầu. Trong payload đó có giao dịch, sản phẩm, và từ năm 2024, cả lý do mà khách hàng đã chọn: UNINTENDED_PURCHASE, FULFILLMENT_ISSUE, UNSATISFIED_WITH_PURCHASE, LEGAL, hoặc OTHER.
Mười hai giờ bắt đầu tính từ đó, trong khoảng thời gian này bạn có thể gọi endpoint Send Consumption Information và ghi nhận phía của mình. Những gì endpoint này cần được thiết kế tối giản một cách có chủ đích, chỉ gồm năm trường mang theo không gì khác ngoài cờ (flag) và số liệu.
customerConsented cho Apple biết liệu khách hàng có đồng ý chia sẻ dữ liệu sử dụng của họ hay không. Giá trị điển hình là true.
deliveryStatus cho Apple biết liệu giao dịch mua đã được giao và hoạt động đúng hay không. Giá trị điển hình là DELIVERED.
sampleContentProvided cho Apple biết liệu trước đó có cung cấp bản mẫu thử hoặc dùng thử miễn phí hay không. Giá trị điển hình là true.
consumptionPercentage cho Apple biết tỷ lệ đã sử dụng, được biểu thị theo milliunit, trong đó 100000 nghĩa là 100 phần trăm. Giá trị điển hình là 67500.
refundPreference cho Apple biết kết quả bạn mong muốn, có thể là chấp thuận, từ chối, hoặc không có ưu tiên. Giá trị điển hình là DECLINE.
consumptionPercentage chỉ áp dụng trong phạm vi hạn chế: hàng tiêu hao (consumables), giao dịch mua một lần, và gói đăng ký không tự động gia hạn. Với gói đăng ký tự động gia hạn, Apple tự tính giá trị này dựa trên thời gian đã trôi qua trong kỳ thanh toán, và bất kỳ giá trị nào bạn cung cấp đều sẽ bị từ chối.
Apple làm gì với những gì bạn gửi
Apple sử dụng thông tin consumption một cách rõ ràng như một yếu tố đầu vào cho cách khoản hoàn tiền được giải quyết. Không gửi gì, quyết định sẽ chỉ dựa hoàn toàn vào lời khẳng định của khách hàng cùng lịch sử tài khoản của họ. Gửi bằng chứng, các khoản hoàn tiền bị tranh chấp thường bị từ chối với tần suất đáng kể.
Tự xây dựng quy trình phản hồi, từ đầu đến cuối
Không có gì trong quy trình này là bí mật. Nhưng tất cả đều cần hoạt động mà không cần ai giám sát vào ba giờ sáng.
1. Nhận được thông báo
Trong App Store Connect, mở trang App Information của ứng dụng và cấu hình một Production Server URL trong phần App Store Server Notifications, chọn Version 2. Các consumption request không được truyền qua V1. Sau đó, mọi thông báo, bao gồm cả hoàn tiền, sẽ đến URL đó qua phương thức POST dưới dạng một payload JWS đã được ký.
2. Tạo đúng loại khóa
Việc xác thực cho các phản hồi sử dụng một In-App Purchase key, được tạo trong mục Users and Access, phần Integrations. Đây là một loại khóa riêng, và App Store Connect API key nằm cạnh đó sẽ không xác thực được các lệnh gọi này. File .p8 chỉ tải xuống được đúng một lần, sau đó bạn tạo một JWT ES256 có thời hạn ngắn cho mỗi request.
3. Xác minh, đối chiếu, rồi quyết định
Các thông báo CONSUMPTION_REQUEST đến cần được xác thực chuỗi ký JWS đối chiếu với các chứng chỉ gốc của Apple trước khi bạn tin vào bất kỳ phần nội dung nào. Tiếp theo, hãy xác định giao dịch đó thuộc về người dùng nào, lý tưởng nhất là qua UUID appAccountToken mà bạn đã gắn vào lúc mua, và lấy ra mức sử dụng thực tế của họ. Sau đó, quyết định một ưu tiên: nhượng bộ trong các trường hợp thiện chí, tranh chấp trong các trường hợp sản phẩm rõ ràng đã được sử dụng.
4. Gửi đi trước khi hết thời hạn
Gửi PUT năm trường đó đến endpoint Send Consumption Information gắn với transaction id tương ứng, trong vòng 12 giờ. Hai lỗi khiến gần như ai cũng mắc phải. Milliunit quy định tỷ lệ phần trăm, vì vậy 100% nghĩa là 100000, không phải một triệu. Và sự đồng ý là điều kiện quyết định toàn bộ, vì tài liệu của Apple nói rõ bạn không nên phản hồi gì cả nếu thiếu sự đồng ý của khách hàng. Hãy đưa điều khoản đồng ý đó vào terms of service của bạn trước khi triển khai bất kỳ phần nào trong số này.
Vì sao nhiều nhà phát triển bỏ lỡ cơ hội này
Nửa ngày là một thời hạn khắc nghiệt đối với bất kỳ điều gì do con người vận hành. Thông báo có thể đến vào 3 giờ sáng ngày thứ Bảy. Điều cần có là một server có khả năng xác thực chuỗi ký JWS của Apple, xác định giao dịch thuộc về người dùng nào, tính toán tỷ lệ consumption theo milliunit, và gọi một API được xác thực bằng JWT. Cho từng yêu cầu một. Không ngừng nghỉ.
Trên thực tế, danh sách công việc cần làm là:
Thiết lập App Store Server Notifications V2, nếu không có nó, yêu cầu sẽ không bao giờ đến được với bạn.
Xác thực payload đã ký đối chiếu với chuỗi chứng chỉ của Apple trước khi tin tưởng vào nó.
Xác định giao dịch thuộc về người dùng nào trong hệ thống của bạn, thường qua appAccountToken được gắn vào lúc mua.
Tính tỷ lệ consumption từ dữ liệu sử dụng thực tế đã ghi nhận, thay vì ước tính.
Gọi Send Consumption Information bằng một In-App Purchase key trong khi thời hạn vẫn còn.
Refund Sensor tồn tại để gánh vác công việc đó, gửi đi một phản hồi đầy đủ, có bằng chứng, hoàn toàn trong thời hạn mà không cần ai phải thức dậy để xử lý.
Các quy tắc này được ghi ở đâu
Câu hỏi thường gặp
Khoản hoàn tiền vẫn sẽ được quyết định, chỉ là lúc này chỉ dựa trên lời khai của khách hàng và lịch sử tài khoản của họ. Bạn sẽ mất đi cơ hội duy nhất để chứng minh rằng giao dịch mua đã được giao thành công và sử dụng nhiều. Trên thực tế, các yêu cầu không được phản hồi thường được chấp thuận nhiều hơn đáng kể.
Có. customerConsented phải là true, và sự đồng ý đứng sau cờ đó phải là thật, thường được ghi nhận trong bất kỳ văn bản pháp lý nào của bạn liên quan đến việc chia sẻ dữ liệu. Hướng dẫn chính thức của Apple yêu cầu các nhà phát triển không phản hồi thông báo này nếu không có sự đồng ý đó.
Chỉ với loại không tự động gia hạn. Với các gói đăng ký tự động gia hạn, Apple tự tính consumption dựa trên thời gian đã trôi qua trong kỳ thanh toán hiện tại, và API sẽ từ chối bất kỳ tỷ lệ nào bạn cung cấp. Dù vậy, refundPreference của bạn vẫn có giá trị.
Một In-App Purchase key, được tạo trong App Store Connect, trong mục Users and Access, phần Integrations. Khóa này khác với App Store Connect API key, và file .p8 của nó chỉ có thể tải xuống một lần duy nhất, ngay tại thời điểm tạo.
Trong môi trường production, bạn có 12 giờ tính từ khi nhận thông báo. Trong sandbox, chỉ có 5 phút, điều này gần như là một tín hiệu khá rõ ràng về điều Apple mong đợi: tự động hóa, chứ không phải con người.



