Tất cả bài viết
Deep diveĐọc trong 7 phút

Thông báo giao dịch bị hủy cho phép máy chủ Google Play của bạn thu hồi quyền truy cập ngay khi một khoản hoàn tiền xảy ra

Google Play có thể đẩy tới máy chủ của bạn một thông báo giao dịch bị hủy ngay lập tức khi một giao dịch được hoàn tiền, bị bồi hoàn, hoặc bị hủy. Nó mang theo purchaseToken, orderId, productType và refundType, và nó có nghĩa một điều, thu hồi quyền truy cập. Đây là cách đọc nó và kết nối nó.

Không gian làm việc của lập trình viên lúc chạng vạng với một chiếc điện thoại hiển thị một khoản thanh toán bị đảo ngược, minh họa một thông báo giao dịch Google Play bị hủy đến được máy chủ

Điểm chính

  • Thông báo giao dịch bị hủy là một Real-time Developer Notification mà Google Play đẩy tới topic Cloud Pub/Sub của bạn ngay khi một giao dịch được hoàn tiền, bị bồi hoàn, hoặc bị hủy theo cách khác. Đó là một tín hiệu đẩy, không phải thứ bạn phải thăm dò (poll).
  • Thông báo mang theo đúng bốn trường: `purchaseToken`, `orderId`, `productType` và `refundType`. Bấy nhiêu là đủ để tìm đúng giao dịch trong cơ sở dữ liệu của bạn và thu hồi quyền lợi gắn với nó.
  • `productType` là `1` cho một gói đăng ký bị hủy và `2` cho một giao dịch mua một lần bị hủy. `refundType` là `1` cho hoàn tiền toàn phần và `2` cho hoàn tiền một phần theo số lượng, chỉ áp dụng cho các giao dịch mua một lần nhiều số lượng.
  • Một thông báo giao dịch bị hủy có nghĩa khách hàng đã nhận lại tiền của họ. Hướng dẫn của chính Google là thu hồi quyền truy cập vào nội dung liên quan, vì người mua không còn nên giữ quyền lợi đó nữa.
  • Thông báo giao dịch bị hủy sẽ tắt cho đến khi bạn bật chúng lên. Trong Play Console, dưới Monetization setup, bạn chọn hoặc gói đăng ký cùng tất cả giao dịch bị hủy, hoặc mục đó cộng thêm các sự kiện sản phẩm mua một lần. Cả hai lựa chọn đều bao gồm giao dịch bị hủy.
  • Thông báo giao dịch bị hủy không phải là một trong hai luồng hoàn tiền yêu cầu bạn cung cấp bằng chứng. Nó là một thông báo sau khi sự việc đã xảy ra. Các luồng duy nhất nhận đầu vào của bạn là CONSUMPTION_REQUEST của Apple, với cửa sổ 12-hour, và quy trình xét duyệt bồi hoàn của Google Play thông qua `orders.reviewrefund`, với cửa sổ 24-hour.
  • Từ August 3, 2026, Google chuyển giá mua cộng với phí ngân hàng của một khoản bồi hoàn cho nhà phát triển. Thông báo giao dịch bị hủy thường là cách máy chủ của bạn lần đầu biết rằng một khoản hủy do bồi hoàn đã xảy ra, nên việc kết nối nó là điều cho phép bạn ngừng phục vụ một khách hàng mà bạn không còn được trả tiền.

Một khoản hoàn tiền trên Google Play không nhất thiết phải là thứ bạn phát hiện sau này trong một báo cáo. Google Play có thể đẩy tới máy chủ của bạn một thông báo giao dịch bị hủy ngay lập tức khi một giao dịch bị hủy, dù người mua đã tự thực hiện hoàn tiền, một nhân viên hỗ trợ đã cấp nó, một ngân hàng đã buộc một khoản bồi hoàn, hay chính bạn đã hoàn tiền đơn hàng đó với cờ thu hồi được bật. Thông điệp rất nhỏ, nó nêu đúng giao dịch, và nó mang một chỉ dẫn, trả lại quyền lợi, vì tiền đã mất rồi.

Thông báo giao dịch bị hủy thực chất là gì

Thông báo giao dịch bị hủy là một loại trong các Real-time Developer Notifications của Google Play, hay RTDN. RTDN là một kênh đẩy. Google phát một thông điệp tới một topic Cloud Pub/Sub mà bạn sở hữu, và backend của bạn nhận được nó trong khoảnh khắc sau khi sự kiện xảy ra, thay vì biết được vào lần thăm dò theo lịch tiếp theo. Đó chính là toàn bộ điểm mấu chốt của thông báo giao dịch bị hủy so với đường pull cũ hơn: bạn biết về khoản hoàn tiền ngay khi nó xảy ra, không phải nhiều giờ sau đó.

Đường pull vẫn tồn tại và vẫn quan trọng. Voided Purchases API cho phép máy chủ của bạn hỏi, theo lịch riêng của bạn, danh sách các giao dịch đã bị hủy trong một khoảng thời gian. Hai cái này bổ trợ cho nhau. Thông báo cho bạn biết ngay khoảnh khắc một giao dịch thay đổi; API cho phép bạn đối soát hàng loạt và bù đắp bất cứ điều gì mà một thông điệp bị bỏ lỡ để lại.

Nó đi kèm bên trong một Real-time Developer Notification

Thông báo giao dịch bị hủy không bao giờ đến một mình. Nó nằm bên trong một lớp bọc DeveloperNotification, và lớp bọc đó được gửi đi dưới dạng một chuỗi mã hóa base64 duy nhất trong trường data của thông điệp Pub/Sub. Trình xử lý của bạn giải mã chuỗi đó thành JSON trước khi có thể đọc bất cứ thứ gì. Lớp bọc luôn nêu tên ứng dụng và thời điểm sự kiện, và nó chứa đúng một đối tượng thông báo trong số năm loại mà Google định nghĩa. Chúng loại trừ lẫn nhau, nên một thông điệp mang voidedPurchaseNotification sẽ không đồng thời mang một sự kiện đăng ký hay mua một lần.

Trường lớp bọcNó chứa gì
versionPhiên bản lược đồ thông báo, ví dụ 1.0
packageNameỨng dụng mà sự kiện thuộc về, ví dụ com.acme.app
eventTimeMillisThời điểm sự kiện xảy ra, tính bằng mili giây kể từ epoch
Một trong năm đối tượng thông báooneTimeProductNotification, subscriptionNotification, voidedPurchaseNotification, pendingRefundReviewNotification, hoặc testNotification. Chỉ một cái hiện diện trong mỗi thông điệp

Bốn trường mà nó mang theo

Bóc lớp bọc ra và bản thân thông báo giao dịch bị hủy chỉ là bốn trường. Điều đó cố tình gọn nhẹ. Quan điểm của Google là nếu tất cả những gì bạn cần là tìm đúng giao dịch và điều chỉnh quyền lợi, bốn trường này là đủ, và bạn không phải gọi lại bất kỳ API nào để hành động.

TrườngNó là gìCách bạn sử dụng nó
purchaseTokenToken được trao cho thiết bị khi món hàng được muaKhóa chính của bạn. Khớp nó với bản ghi giao dịch bạn đã lưu lúc cấp quyền
orderIdId đơn hàng hiển thị cho người mua, ví dụ GS.0000-0000-0000Một khóa thứ hai dễ đọc cho con người, dùng cho hỗ trợ và đối soát
productTypeMón bị hủy là gói đăng ký hay giao dịch mua một lầnĐịnh tuyến tới đúng đường thu hồi
refundTypeKhoản hủy là hoàn tiền toàn phần hay hoàn tiền một phần theo số lượngQuyết định thu hồi tất cả hay chỉ số lượng đã được hoàn

productType cho bạn biết cái gì đã bị hủy

productType là một số nguyên nhỏ, và nó quyết định đường thu hồi nào của bạn cần đi. Một khoản hủy gói đăng ký phải tháo gỡ quyền truy cập đang diễn ra; một khoản hủy giao dịch mua một lần chỉ cần gỡ bỏ một quyền lợi duy nhất.

Giá trị `productType`Hằng sốÝ nghĩa
1PRODUCT_TYPE_SUBSCRIPTIONMột giao dịch đăng ký đã bị hủy
2PRODUCT_TYPE_ONE_TIMEMột giao dịch mua một lần đã bị hủy

refundType cho bạn biết bao nhiêu đã được trả lại

refundType phân tách một khoản đảo ngược toàn phần gọn gàng với một khoản một phần. Trường hợp một phần rất hẹp. Nó chỉ xuất hiện khi một giao dịch mua một lần nhiều số lượng được hoàn một phần, chứ không phải toàn bộ số lượng.

Giá trị `refundType`Hằng sốÝ nghĩa
1REFUND_TYPE_FULL_REFUNDGiao dịch đã bị hủy hoàn toàn
2REFUND_TYPE_QUANTITY_BASED_PARTIAL_REFUNDMột phần của giao dịch nhiều số lượng đã bị hủy

Bật nó lên trước, nếu không nó sẽ không bao giờ đến

Thông báo giao dịch bị hủy không tự động chảy về. Bạn bật RTDN một lần, trong Play Console, và trỏ nó tới một topic Pub/Sub mà bạn kiểm soát. Công tắc nằm dưới Monetize, rồi Monetization setup, trong mục Real-time developer notifications ở đầu trang. Đánh dấu Enable real-time notifications, rồi dán tên topic đầy đủ của bạn theo dạng projects/{project_id}/topics/{topic_name}, và dùng Send Test Message để xác nhận đường ống hoạt động trước khi bạn tin nó.

Công tắc nội dung là nơi mọi người bỏ lỡ giao dịch bị hủy. Cả hai lựa chọn đều bao gồm chúng, nên bạn không thể vô tình từ chối hoàn tiền trong khi vẫn giữ các gói đăng ký.

  • Nhận thông báo cho các gói đăng ký và tất cả giao dịch bị hủy. Bạn nhận các sự kiện đăng ký và mọi giao dịch bị hủy, nhưng không nhận các sự kiện mua sản phẩm một lần.
  • Nhận tất cả thông báo cho các gói đăng ký và sản phẩm mua một lần. Bạn nhận những cái trên cộng với các sự kiện sản phẩm mua một lần như ONE_TIME_PRODUCT_PURCHASEDONE_TIME_PRODUCT_CANCELED.
Một thẻ tín dụng úp mặt xuống bên cạnh một hóa đơn giấy, tượng trưng cho một giao dịch Google Play bị hủy

Nó tốn kém bao nhiêu, tính bằng tiền

Một khoản hủy là một tổn thất đã được ghi sổ vào thời điểm thông báo đến tay bạn. Giá bán đã mất, và cả những gì bạn đã chi để phục vụ khách hàng đó cũng vậy. Nếu họ đã tạo ra hình ảnh, chạy các lệnh gọi tới các mô hình của bạn, dùng dung lượng lưu trữ, hay kích hoạt một khoản chi trả cho bên thứ ba, những chi phí đó đã được trả bằng tiền thật và không quay lại cùng khoản hoàn tiền. Thông báo không thể phục hồi bất kỳ điều nào trong số đó. Điều nó có thể làm là chặn dòng chảy máu từ đây trở đi, và đó là toàn bộ lý do để hành động nhanh với nó.

Sự chảy máu tồi tệ nhất ở các gói đăng ký và tồi tệ nhất ở các khoản bồi hoàn. Một gói đăng ký mà bạn không thu hồi sẽ tiếp tục tốn kém để phục vụ, tháng này qua tháng khác, cho một khách hàng không còn trả tiền. Và một khoản bồi hoàn là loại hủy đắt đỏ nhất. Từ August 3, 2026, tài liệu của Google nêu rằng một khoản bồi hoàn chuyển giá mua cộng với phí của ngân hàng cho nhà phát triển. Thông báo giao dịch bị hủy thường là nơi đầu tiên mà chính các hệ thống của bạn nghe được rằng một khoản bồi hoàn đã hoàn tất, nên một trình xử lý thu hồi ngay tại chỗ là điều giữ cho một khoản bán bị mất không biến thành một khoản bán bị mất cộng với nhiều tuần phục vụ miễn phí.

Cách xử lý một thông báo giao dịch bị hủy, từng bước

Xác minh và loại trùng lặp thông điệp

  • Xác nhận thông điệp Pub/Sub đến từ Google và nhắm tới topic bạn đã cấu hình, rồi giải mã trường data base64 để lấy JSON DeveloperNotification.
  • Dùng messageId của Pub/Sub để loại bỏ bản trùng. Google cảnh báo rằng cùng một thông báo có thể được gửi nhiều hơn một lần, nên hãy coi việc phát lại là bình thường và làm cho trình xử lý của bạn có tính idempotent.
  • Chỉ xác nhận (acknowledge) thông điệp sau khi bạn đã ghi lại nó an toàn, để một sự cố giữa chừng trình xử lý không làm mất sự kiện.

Tra cứu giao dịch

  • Khớp purchaseToken với giao dịch bạn đã lưu khi lần đầu cấp quyền lợi. Dùng orderId làm phương án dự phòng cho tra cứu hỗ trợ và đối soát thủ công.
  • Đọc productType để chọn đường thu hồi gói đăng ký hoặc mua một lần, và đọc refundType để quyết định giữa thu hồi toàn phần và một phần.

Thu hồi và ghi lại

  • Gỡ bỏ quyền lợi. Với hoàn tiền toàn phần, cắt quyền truy cập vào món hàng. Với hoàn tiền một phần theo số lượng, giảm số lượng đã cấp đi đúng lượng đã hoàn và giữ nguyên phần còn lại.
  • Ghi lại bạn đã làm gì và khi nào, khóa theo purchaseTokenorderId. Bản ghi đó là thứ cho phép bạn trả lời một phiếu hỗ trợ về sau, và là thứ cho phép Voided Purchases API đối soát gọn gàng với trạng thái của chính bạn.

Nó nằm ở đâu giữa các tín hiệu hoàn tiền khác

Một thông báo giao dịch bị hủy là một thông báo, không phải một cuộc thương lượng. Nó cho bạn biết một kết quả đã được quyết định. Đáng để đặt nó bên cạnh các tín hiệu dễ bị nhầm lẫn với nó, vì chỉ một số trong chúng từng hỏi phía câu chuyện của bạn.

Tín hiệuHướngNó có nhận đầu vào của bạn không
Thông báo giao dịch bị hủy (RTDN)Google đẩy tới máy chủ của bạnKhông. Nó báo cáo một khoản hủy đã xảy ra
Voided Purchases APIMáy chủ của bạn kéo về từ GoogleKhông. Nó là một danh sách chỉ đọc các khoản hủy trong quá khứ
pendingRefundReviewNotification (RTDN)Google đẩy tới máy chủ của bạnCó, một cách gián tiếp. Nó gắn cờ một khoản bồi hoàn mà sau đó bạn phản đối thông qua orders.reviewrefund trong vòng 24 giờ
Apple CONSUMPTION_REQUESTApple hỏi máy chủ của bạnCó. Bạn trả lời bằng Send Consumption Information trong vòng 12 giờ

Điều cần ghi nhớ rất đơn giản. Trên cả hai cửa hàng có đúng hai luồng hoàn tiền mà nhà phát triển có tiếng nói, CONSUMPTION_REQUEST của Apple và quy trình xét duyệt bồi hoàn của Google Play. Một thông báo giao dịch bị hủy không phải là cái nào cả. Đến lúc nó tới tay bạn, quyết định đã ở sau lưng bạn và điều duy nhất còn lại trong tay bạn là bạn thu hồi nhanh đến mức nào.

Câu hỏi thường gặp

Thông báo giao dịch bị hủy trên Google Play có nghĩa là gì?
Nó có nghĩa một giao dịch đã được hoàn tiền, bị bồi hoàn, hoặc bị hủy theo cách khác, và khách hàng đã nhận lại tiền của họ. Hướng dẫn của Google là thu hồi quyền truy cập vào nội dung liên quan, vì người mua không còn nên giữ quyền lợi đó nữa. Thông báo nêu đúng giao dịch qua `purchaseToken` và `orderId` của nó.
Một thông báo giao dịch Google Play bị hủy chứa những trường nào?
Bốn: `purchaseToken`, `orderId`, `productType` và `refundType`. `productType` là `1` cho một gói đăng ký và `2` cho một giao dịch mua một lần. `refundType` là `1` cho hoàn tiền toàn phần và `2` cho hoàn tiền một phần theo số lượng trên một giao dịch nhiều số lượng.
Làm thế nào để bật thông báo giao dịch bị hủy?
Trong Play Console, mở Monetize rồi Monetization setup, và trong mục Real-time developer notifications, đánh dấu Enable real-time notifications, rồi nhập tên topic Cloud Pub/Sub của bạn. Cả hai lựa chọn nội dung, gói đăng ký cùng tất cả giao dịch bị hủy, và mục đó cộng thêm các sự kiện sản phẩm mua một lần, đều bao gồm giao dịch bị hủy.
Sự khác biệt giữa thông báo giao dịch bị hủy và Voided Purchases API là gì?
Thông báo là một tín hiệu đẩy được gửi theo thời gian thực qua Cloud Pub/Sub ngay khi một giao dịch bị hủy. Voided Purchases API là một đường pull mà máy chủ của bạn truy vấn theo lịch riêng của nó để liệt kê các khoản hủy trong một khoảng thời gian. Dùng thông báo để phản ứng tức thì và API để đối soát và bù đắp.
Thông báo giao dịch bị hủy có cho phép tôi phản đối khoản hoàn tiền không?
Không. Nó là một thông báo sau khi sự việc đã xảy ra về một quyết định đã được đưa ra. Luồng Google Play duy nhất nhận đầu vào của bạn là quy trình xét duyệt bồi hoàn thông qua `orders.reviewrefund`, mà bạn có 24 giờ để trả lời, và trên Apple đó là CONSUMPTION_REQUEST với cửa sổ 12-hour.

Nguồn và tài liệu đọc thêm

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 tiếp theo đã đang trên đường đến.

Thiết lập RefundHalt trong khoảng thời gian bạn cần để đọc thêm một email hỗ trợ về khoản hoàn tiền mà mình chưa kịp phản biện.