Dùng Google Play RTDN để xử lý sự kiện nhanh chóng. Dùng Voided Purchases API để kiểm tra các đơn hàng bị hủy và đối soát dữ liệu của bạn. Với hầu hết ứng dụng trả phí, lựa chọn an toàn hơn là dùng cả hai.
Nếu bạn đang lên kế hoạch chống hoàn tiền trên Google Play cho ứng dụng, hãy bắt đầu với cách phân chia này. Một hướng cho bạn biết có điều gì đó đã thay đổi. Hướng còn lại cho phép server của bạn lấy danh sách các giao dịch bị hủy và kiểm tra những gì đã bị bỏ lỡ.
Lựa chọn này không hẳn là giữa hai hệ thống thông báo. Google Play RTDN đẩy (push) tin nhắn qua Cloud Pub/Sub. Voided Purchases API là một API kéo (pull): backend của bạn gọi nó.
Bản thân cả hai đều không ngăn được việc ai đó yêu cầu hoàn tiền. Giá trị của chúng nằm ở việc phát hiện thay đổi, kiểm tra đơn hàng và đảm bảo quyền truy cập trả phí khớp với trạng thái mua hàng.
Những điểm chính
Dùng RTDN để phản ứng kịp thời với các sự kiện mua hàng và đăng ký.
Dùng danh sách voided-purchase như một hướng thứ hai để kiểm tra các đơn hàng bị ảnh hưởng.
Không xem việc hủy gói đăng ký là bằng chứng của việc hoàn tiền.
Đảm bảo cả hai hướng đều dùng chung một logic cập nhật quyền truy cập an toàn.
Tách riêng việc xem xét chargeback đang chờ xử lý (pending) với một lần hủy (void) đã hoàn tất.
Google Play RTDN là gì?
Google Play Real-Time Developer Notifications, thường gọi là RTDN, gửi các sự kiện liên quan đến mua hàng đến một topic Cloud Pub/Sub.
Backend của bạn nhận một tin nhắn và định tuyến nó đến worker phù hợp. Loại tin nhắn rất quan trọng. Một lần gia hạn, một lần hủy và một giao dịch bị hủy (voided) không phải là cùng một sự kiện.
Để theo dõi hoàn tiền, hãy đặc biệt chú ý đến voidedPurchaseNotification. Nó bao gồm:
purchaseToken: liên kết sự kiện với một giao dịch mua.
orderId: xác định đơn hàng bị ảnh hưởng.
productType: xác định đây là gói đăng ký hay giao dịch mua một lần.
refundType: phân biệt giữa hủy toàn phần và hoàn tiền một phần dựa trên số lượng.
Tài liệu tham khảo RTDN và định nghĩa sự kiện của Google giải thích các trường này và các loại thông báo khác.
RTDN hữu ích khi bạn muốn hành động ngay sau khi có thay đổi. Nhưng một tin nhắn không phải là toàn bộ cơ sở dữ liệu mua hàng của bạn. Hãy khớp nó với các bản ghi đã lưu và truy xuất trạng thái mua hàng liên quan khi cần trước khi thay đổi quyền truy cập.
Hủy gói đăng ký có đồng nghĩa với hoàn tiền không?
Không. Khách hàng có thể ngừng các lần gia hạn trong tương lai nhưng vẫn có quyền truy cập trả phí cho phần còn lại của kỳ hiện tại.
Không nên xây dựng một quy tắc xóa quyền truy cập ngay khi SUBSCRIPTION_CANCELED xuất hiện. Thay vào đó, hãy kiểm tra trạng thái và ngày hết hạn của gói đăng ký. Việc thu hồi (revocation) và hết hạn (expiry) cần được xử lý riêng.
Voided Purchases API là gì?
Google Play Voided Purchases API trả về danh sách các giao dịch mua đã bị hủy, hoàn tiền hoặc bị charge back trong phạm vi được hỗ trợ.
Nó áp dụng cho cả đơn hàng in-app mua một lần và gói đăng ký. Server của bạn có thể dùng kết quả này để kiểm tra giao dịch mua nào không còn nên được cấp quyền truy cập.
Danh sách này có thể bao gồm order ID, purchase token, thời điểm hủy (void time), nguồn hủy (void source) và lý do hủy (void reason). Đối với các trường hợp hoàn tiền một phần dựa trên số lượng được hỗ trợ, nó cũng có thể bao gồm số lượng đã hoàn.
Hướng dẫn Voided Purchases API của Google quy định khoảng thời gian tra cứu lại là 30 ngày. Đây không phải là bản lưu trữ hoàn tiền vĩnh viễn. Hãy lưu lại các bản ghi đã xử lý trong hệ thống riêng của bạn.
API này đặc biệt hữu ích sau một lần worker ngừng hoạt động, một lỗi định tuyến hoặc một khoảng trống trong bản ghi cục bộ của bạn. Nó cũng giúp bạn thực hiện kiểm tra định kỳ đối chiếu với các sự kiện bạn đã xử lý.
RTDN so với Voided Purchases API: sự khác biệt thực tế
Câu hỏi | Google Play RTDN | Voided Purchases API |
Cách hoạt động? | Google phát một sự kiện đến Pub/Sub. | Server của bạn yêu cầu một danh sách. |
Vai trò chính là gì? | Xử lý kịp thời các thay đổi trạng thái mua hàng. | Kiểm tra và đối soát các đơn hàng bị hủy. |
Có bao quát các sự kiện ngoài hoàn tiền không? | Có, bao gồm cả gia hạn và các sự kiện vòng đời khác. | Tập trung vào các giao dịch bị hủy. |
Có hỗ trợ khi có khoảng trống xử lý không? | Khả năng khôi phục của Pub/Sub phụ thuộc vào cấu hình và thời gian lưu giữ của bạn. | Có thể liệt kê các bản ghi có sẵn trong khoảng 30 ngày. |
Có cần cơ chế chống trùng lặp không? | Có. | Có, đặc biệt khi các lần quét chồng lấp hoặc chia sẻ sự kiện với RTDN. |
Câu hỏi quan trọng không phải là công cụ nào tốt hơn khi xét riêng lẻ. Đó là mỗi công cụ giúp bạn xử lý loại lỗi nào.
RTDN mang lại cho bạn một hướng xử lý nhanh. API mang lại cho bạn một hướng kiểm tra. Cơ sở dữ liệu riêng của bạn nên kết hợp cả hai lại.
Ứng dụng của bạn nên dùng cái nào?
Dùng RTDN khi tốc độ quan trọng
Một ứng dụng trả phí không nên phải chờ đến lần quét theo lịch trước khi nhận ra một thay đổi trạng thái mua hàng.
Dùng RTDN khi ứng dụng của bạn cần cập nhật kịp thời cho các gói đăng ký, giao dịch mua một lần và các đơn hàng bị hủy. Định tuyến từng sự kiện theo loại thay vì áp dụng một quy tắc hoàn tiền duy nhất cho mọi tin nhắn.
Dùng API khi tính đầy đủ quan trọng
Dùng các lần kiểm tra API theo lịch để tìm ra các đơn hàng bị hủy mà worker của bạn chưa áp dụng vào bản ghi.
Ví dụ, receiver của bạn có thể đã nhận một tin nhắn, nhưng một lỗi có thể đã khiến việc cập nhật quyền truy cập sau đó không thực hiện được. Chỉ sửa lỗi gửi tin sẽ không khắc phục được khoảng trống cục bộ đó.
Dùng cả hai cho một quy trình chống hoàn tiền trong môi trường production
Với hầu hết ứng dụng trả phí, hãy kết hợp cả hai. Cho cả hai hướng cùng đổ vào một bộ xử lý (handler) chung, có nhiệm vụ kiểm tra đơn hàng và áp dụng bất kỳ thay đổi nào một cách an toàn.
Điều này giảm nguy cơ một sự kiện bị bỏ lỡ khiến quyền truy cập vẫn còn hiệu lực. Nó cũng giảm nguy cơ ngược lại: xóa quyền truy cập hai lần cho cùng một lần hoàn tiền.
Cách phát hiện hoàn tiền trên Google Play theo từng bước
1. Duy trì một sổ cái giao dịch mua (purchase ledger)
Lưu trữ package của ứng dụng, purchase token, order ID, sản phẩm, liên kết người dùng (user mapping) và số lượng đã cấp. Sổ cái chỉ đơn giản là một bản ghi rõ ràng về những gì đã được mua và quyền truy cập mà nó đã cấp.
Đối với gói đăng ký, hãy lưu cả order ID của các lần gia hạn. Tài liệu tham khảo RTDN ghi rõ mỗi lần tự động gia hạn có một order ID mới. Chỉ riêng purchase token là không đủ để xác định mọi lần gia hạn bị ảnh hưởng.
2. Bảo mật và định tuyến tin nhắn RTDN
Cấu hình quyền truy cập Pub/Sub đúng cách. Đối với push delivery, hãy xác minh yêu cầu đã được xác thực. Đối với pull delivery, hãy giới hạn ai có thể đọc subscription.
Giải mã tin nhắn, kiểm tra tên package, và lưu lại trước khi thực hiện các công việc tốn thời gian. Gửi các sự kiện thử nghiệm qua toàn bộ đường dẫn (full path), không chỉ qua endpoint tiếp nhận.
3. Chạy quét theo lịch để tìm giao dịch bị hủy (voided-purchase scan)
Gọi phương thức list với thông tin xác thực phù hợp và quyền Play Console cần thiết. Lấy hết toàn bộ các trang kết quả.
Có hai thiết lập truy vấn dễ bị bỏ qua:
type=1 bao gồm cả giao dịch mua một lần và gói đăng ký. Giá trị mặc định, 0, chỉ bao gồm giao dịch mua một lần.
includeQuantityBasedPartialRefund=true bao gồm các trường hợp hoàn tiền một phần dựa trên số lượng được hỗ trợ. Giá trị mặc định của nó là false.
Tài liệu tham khảo phương thức voidedpurchases.list của Google trình bày các trường yêu cầu và phân trang.
Hãy dùng một độ chồng lấp vừa phải giữa các lần quét và loại bỏ trùng lặp trong kết quả. Chọn tần suất quét dựa trên lưu lượng, hạn mức (quota) của bạn và mức độ chậm trễ mà ứng dụng của bạn có thể chấp nhận. Không nên chờ đến khi khoảng thời gian tra cứu lại sắp kết thúc.
4. Chỉ áp dụng mỗi thay đổi một lần
Cả hai hướng có thể báo cáo cùng một lần hủy. Hãy xây dựng cơ chế xử lý idempotent (bất biến khi lặp lại): thực hiện lại cùng một thay đổi không nên làm thay đổi kết quả.
Không nên chỉ dùng order ID để loại bỏ mọi sự kiện xảy ra sau đó. Một giao dịch mua nhiều số lượng có thể có nhiều lần hoàn tiền một phần. Hãy theo dõi các điều chỉnh đã xử lý và số lượng đã hoàn để một lần hoàn tiền thực sự sau đó không bị bỏ lỡ.
5. Theo dõi khoảng trống, không chỉ số lượng tin nhắn
Theo dõi lần quét thành công cuối cùng, các trang chưa hoàn tất, lỗi worker và các đơn hàng không khớp. Đo thời gian cần để cập nhật quyền truy cập sau khi một sự kiện đã được xác nhận.
Để có báo cáo rộng hơn, hãy xem hướng dẫn về các công cụ theo dõi hoàn tiền và chargeback cho ứng dụng di động của chúng tôi.
Ví dụ: một lần hoàn tiền, hai hướng phát hiện
Đây là một quy trình giả định, không phải là một trường hợp khách hàng được báo cáo thực tế.
Một người chơi mua một gói trả phí một lần, được cấp 500 coin. Giao dịch này sau đó bị hủy toàn phần.
RTDN gửi một tin nhắn voided-purchase. Worker của bạn tìm thấy đơn hàng, kiểm tra số lượng đã cấp được ghi nhận, và áp dụng chính sách đã công bố của bạn đối với số coin liên kết với giao dịch mua đó.
Sau đó, lần quét API theo lịch trả về cùng đơn hàng này. Bộ xử lý chung nhận thấy việc điều chỉnh hủy toàn phần đã được áp dụng rồi. Nó ghi nhận sự khớp đó và không thực hiện trừ lần thứ hai.
Giờ hãy giả sử worker đã gặp lỗi trước khi áp dụng thay đổi đầu tiên. Lần quét sẽ tìm thấy đơn hàng và cho hệ thống của bạn một hướng khác để xử lý nó.
Đó chính là ý nghĩa của việc dùng cả hai. Không phải là hai lần xử phạt riêng biệt, mà là hai cách để đạt được một kết quả chính xác.
Nếu một số coin đã được chi tiêu, không nên tùy tiện trừ coin từ một gói trả phí không liên quan. Hãy áp dụng một chính sách rõ ràng, giải thích hành động, và cung cấp một kênh hỗ trợ.
Xem xét hoàn tiền đang chờ xử lý (pending refund review) là một quy trình riêng
Tài liệu hiện tại của Google cũng có pendingRefundReviewNotification cho một yêu cầu chargeback cần nhà phát triển xem xét.
Đối với sự kiện này, Google yêu cầu bạn đưa ra gợi ý hoàn tiền và bằng chứng sử dụng giao dịch mua thông qua orders.reviewrefund trong vòng 24 giờ.
Không nên nhầm lẫn nó với voidedPurchaseNotification. Một sự kiện liên quan đến việc xem xét đang chờ xử lý. Sự kiện khác báo cáo một giao dịch mua đã bị hủy.
Voided Purchases API không phải là giải pháp thay thế cho việc xử lý sự kiện xem xét đang chờ xử lý. Hãy giữ nhánh đó riêng biệt, và không nên cho rằng mọi yêu cầu hoàn tiền đều tạo ra sự kiện này.
Hoàn tiền trên App Store và thất thoát doanh thu: những điều nhà phát triển cần biết
Thất thoát doanh thu không chỉ giới hạn ở việc cửa hàng có trả lại tiền hay không. Nó cũng có thể có nghĩa là backend của bạn vẫn tiếp tục cấp quyền truy cập trả phí sau khi giao dịch mua liên quan không còn hỗ trợ điều đó.
Đối với các nhóm hoạt động trên cả hai nền tảng, mục tiêu là tương tự: giữ tiền, trạng thái mua hàng và bản ghi quyền truy cập luôn đồng bộ. Tuy nhiên, các công cụ của cửa hàng và quy tắc sự kiện là khác nhau. Không nên sao chép một quy trình của Apple sang Google Play mà không điều chỉnh.
Hướng dẫn quản lý doanh thu hoàn tiền trên App Store của chúng tôi bao quát vấn đề quản lý doanh thu rộng hơn. Đối với tích hợp Google Play này, hãy tập trung trước tiên vào các trường hợp hủy bị bỏ lỡ, các lần trừ trùng lặp và các thay đổi quyền truy cập gói đăng ký không chính xác.
Những gì phòng chống gian lận hoàn tiền trên Google Play có thể và không thể làm
Phòng chống gian lận hoàn tiền trên Google Play bắt đầu từ các bản ghi chính xác và các quy tắc công bằng. Một đơn hàng bị hủy không phải là bằng chứng chứng minh khách hàng đã hành động không trung thực.
Người dùng có thể có một khiếu nại chính đáng. Một giao dịch thanh toán có thể thất bại. Ứng dụng của bạn có thể đã giao sai sản phẩm.
Hãy dùng các công cụ này để kiểm tra sự thật và áp dụng các thay đổi quyền truy cập. Xem xét các mẫu hành vi lặp lại trong bối cảnh cụ thể. Tránh cấm tài khoản tự động chỉ dựa trên một lần hoàn tiền, và cho phép khách hàng phản hồi lại các sai sót.
Không có RTDN hay API danh sách nào đảm bảo bạn có thể ngăn chặn, từ chối hoặc đảo ngược một lần hoàn tiền.
Kết luận
Việc lựa chọn giữa RTDN và Voided Purchases API không phải là quyết định chọn một trong hai đối với hầu hết ứng dụng trả phí.
Dùng RTDN để phản ứng nhanh chóng. Dùng các lần kiểm tra giao dịch bị hủy theo lịch để đối soát bản ghi. Gửi cả hai qua một bộ xử lý an toàn duy nhất, và giữ các trường hợp xem xét đang chờ xử lý tách biệt với các lần hủy đã hoàn tất.
Hãy bắt đầu với một thử nghiệm nhỏ: gửi một lần hủy qua cả hai hướng và xác nhận rằng quyền truy cập chỉ thay đổi một lần. Sau đó, dừng worker của bạn và kiểm tra xem hướng khôi phục có phát hiện được khoảng trống đó không.
Câu hỏi thường gặp
RTDN phù hợp hơn để xử lý sự kiện tức thì. API phù hợp hơn để kiểm tra theo lịch các đơn hàng bị hủy (voided). Hầu hết ứng dụng trả phí đều nên dùng cả hai.
Có. Nó bao gồm thông báo voided-purchase (giao dịch bị hủy) kèm chi tiết về đơn hàng và loại hoàn tiền. Hãy xử lý sự kiện này riêng biệt với việc hủy gói đăng ký (subscription cancellation).
Bạn có thể phát hiện các bản ghi voided có sẵn thông qua polling, nhưng việc phát hiện sẽ phải chờ đến lần quét thành công tiếp theo. Bạn cũng sẽ bỏ lỡ luồng sự kiện vòng đời (lifecycle event) rộng hơn mà RTDN cung cấp.
Google quy định khoảng thời gian tra cứu là 30 ngày. Hãy lưu lại các bản ghi riêng của bạn lâu hơn để phục vụ kiểm tra dài hạn và nhu cầu hỗ trợ khách hàng.
Có. Hãy kích hoạt các kết quả hoàn tiền một phần (partial-refund) được hỗ trợ trong các yêu cầu danh sách (list requests). Theo dõi số lượng đã hoàn và tính đến khả năng có nhiều hơn một lần hoàn tiền một phần trên cùng một đơn hàng.



