Tất cả bài viết
PlaybookĐọc trong 8 phút

Xử lý hoàn tiền hỏng theo cách âm thầm, nên hãy test hoàn tiền mua hàng trong ứng dụng ở sandbox trước khi một khách hàng thật gặp phải

Việc xử lý hoàn tiền chỉ chạy sau khi khách hàng đã rời đi, nên một lỗi trong đó vẫn vô hình cho đến khi nó gây thiệt hại tiền thật. Cả hai cửa hàng đều cho phép bạn kích hoạt một khoản hoàn tiền trong môi trường test trước. Dưới đây là cách test hoàn tiền mua hàng trong ứng dụng trên App Store và Google Play trước khi một khoản hoàn tiền trở thành thật.

Một chiếc iPhone và một chiếc điện thoại Android dưới kính lúp trên bàn tối màu, đại diện cho việc test hoàn tiền mua hàng trong ứng dụng trước khi chúng trở thành thật

Điểm chính

  • StoreKit testing của Xcode cho phép bạn hoàn tiền một giao dịch cục bộ bằng cách nhấp vào mũi tên hoàn tiền trong Transaction Manager, kích hoạt listener Transaction.updates của ứng dụng, nhưng nó không bao giờ liên hệ Apple, nên không có App Store Server Notification nào được gửi.
  • Để test phía máy chủ trên Apple, hãy trỏ một URL App Store Server Notifications V2 sandbox tới backend của bạn: khi đó một khoản hoàn tiền sandbox sẽ gửi một REFUND thật, và một yêu cầu hoàn tiền sẽ gửi một CONSUMPTION_REQUEST, tới máy chủ của bạn.
  • Endpoint Request a Test Notification của Apple gửi một thông báo loại TEST tới URL bạn đã cấu hình và trả về một testNotificationToken, nên bạn có thể xác nhận webhook của mình có thể tiếp cận được trước khi bất kỳ sự kiện thật nào kích hoạt.
  • sandbox của Apple không bao giờ thử lại một thông báo thất bại, nên một webhook đang ngừng hoạt động khi sandbox kích hoạt sẽ đánh rơi sự kiện mà không có lần thử thứ hai, đúng loại thiếu sót về sau khiến bạn mất một khung thời gian hoàn tiền thật.
  • Google Play cấp cho license tester một phương thức thanh toán tên Test card, approves then charges back, thứ kích hoạt một PendingRefundReviewNotification ngay sau khi mua để bạn có thể diễn tập phản hồi orders.reviewrefund trong 24 hours.
  • Với một license tester trên Google Play, một giao dịch mua chưa được xác nhận sẽ được tự động hoàn tiền sau 3 minutes thay vì 3 days mà bản production phải chờ, nên một luồng xác nhận bị hỏng sẽ thất bại nhanh và rõ trong khi test.
  • Một trình xử lý hoàn tiền bạn chưa bao giờ test chính là trình giữ cho quyền truy cập trả phí của một khách hàng đã được hoàn tiền vẫn còn sống, và kể từ ngày 3 tháng 8 năm 2026, một phản hồi chargeback Google Play chưa được test có thể khiến bạn mất giá mua trừ đi phí dịch vụ của Play cộng với phí của ngân hàng.

Việc xử lý hoàn tiền là đường mã duy nhất chỉ chạy sau khi khách hàng đã rời đi. Không có gì trong QA thông thường của bạn chạm tới nó, vì để tới được đó bạn phải thực sự được hoàn tiền. Thế là nó ra mắt mà chưa được test, nằm im nhiều tháng, rồi thất bại vào một khoản hoàn tiền thật, nơi sự thất bại tốn tiền chứ không phải một bài test màu đỏ. Cách sửa là ngừng coi hoàn tiền như thứ xảy đến với bạn và bắt đầu chủ ý kích hoạt một khoản. Cả Apple lẫn Google đều cho phép bạn kích hoạt một khoản hoàn tiền trong môi trường test và quan sát máy chủ của mình phản ứng. Dưới đây là cách test hoàn tiền mua hàng trong ứng dụng trên App Store và Google Play trước khi một khách hàng trả tiền chứng minh rằng trình xử lý của bạn đã hỏng.

Ba môi trường mà một khoản hoàn tiền có thể kích hoạt, và chỉ một là production

Có ba nơi riêng biệt mà một khoản hoàn tiền của Apple hoặc Google có thể được kích hoạt trong khi bạn xây dựng, và chúng không thể thay thế cho nhau. Hai trong số đó là của bạn để kích hoạt theo ý muốn. Nơi thứ ba là production, nơi bạn không bao giờ muốn lần đầu gặp một lỗi hoàn tiền. Cái bẫy là cho rằng nơi dễ nhất, tức test cục bộ trong Xcode, chứng minh toàn bộ pipeline của bạn. Nó chứng minh ứng dụng của bạn. Nó không nói gì về máy chủ của bạn.

StoreKit testing của Xcode là cục bộ, nên nó chỉ rèn giũa ứng dụng của bạn và không gì khác

StoreKit testing tích hợp sẵn của Xcode chạy dựa trên một tệp cấu hình trên máy Mac của bạn, không có vòng đi về tới Apple. Mở StoreKit Transaction Manager từ thanh debug, chọn một giao dịch đã mua, và nhấp vào mũi tên hoàn tiền cong. Giao dịch lật sang đã hoàn tiền và listener Transaction.updates của ứng dụng kích hoạt, đúng như trong thực tế. Bạn cũng có thể gọi beginRefundRequest để hiển thị tờ hoàn tiền thật, và trong môi trường Xcode, vấn đề bạn chọn ánh xạ một đối một sang một RevocationReason, với khoản hoàn tiền được áp dụng ngay lập tức. Đây là cách nhanh nhất để chứng minh client của bạn cắt quyền truy cập ngay khoảnh khắc revocationDate trở nên khác nil. Đó cũng là toàn bộ những gì test cục bộ có thể cho bạn biết, vì ở đây không có gì từng chạm tới máy chủ của Apple, nên không có App Store Server Notification nào được gửi. Backend của bạn không học được điều gì.

sandbox là nơi máy chủ của bạn cuối cùng nghe được về một khoản hoàn tiền

Để test nửa phần tích hợp quyết định tiền bạc, tức máy chủ của bạn, bạn cần sandbox của Apple. Cấu hình một URL App Store Server Notifications V2 sandbox trong App Store Connect, đăng nhập một sandbox tester trên một thiết bị, và mua. Bây giờ một khoản hoàn tiền trong sandbox gửi một thông báo REFUND thật tới backend của bạn, và một yêu cầu hoàn tiền trên một sản phẩm tiêu hao hoặc tự động gia hạn gửi một CONSUMPTION_REQUEST, cùng payload đã ký mà máy chủ production của bạn sẽ nhận. Trước khi kích hoạt bất cứ thứ gì, hãy gọi endpoint Request a Test Notification. Nó bảo máy chủ App Store gửi một thông báo loại TEST tới URL bạn đã cấu hình và trao cho bạn một testNotificationToken, thứ bạn chuyển cho Get Test Notification Status để xác nhận việc gửi. Nếu vòng đi về đó không chạy, thì không thông báo thật nào sẽ chạy.

Môi trườngNó có thể kích hoạt gìNó chứng minh gìNó không thể làm gì
Xcode StoreKit testingMột khoản hoàn tiền qua Transaction Manager hoặc tờ beginRefundRequestỨng dụng của bạn phản ứng với một khoản hoàn tiền cục bộ, trong vài giâyKhông bao giờ liên hệ Apple, nên không thông báo máy chủ nào được gửi
SandboxREFUND và CONSUMPTION_REQUEST thật tới máy chủ của bạn, cộng một thông báo TEST theo yêu cầuBackend của bạn nhận, xác minh và xử lý payload đã kýKhông thử lại một thông báo mà endpoint của bạn không nhận được
ProductionMọi khoản hoàn tiền, bằng tiền thậtKhông có gì bạn muốn biết đầu tiên ở đâyBạn không thể hoàn tác chi phí của một lỗi

Cách test hoàn tiền mua hàng trong ứng dụng trên App Store

Chạy theo thứ tự này, từ kiểm tra client rẻ tiền tới vòng đi về máy chủ đầy đủ. Mỗi bước rèn giũa một mảnh khác nhau, và những bước sau chính là phần mà production thực sự tính tiền bạn.

  • Tạo một In-App Purchase key dưới Users and Access, Integrations, In-App Purchase trong App Store Connect, và dùng nó để ký các lệnh gọi App Store Server API của bạn.
  • Trỏ URL App Store Server Notifications V2 sandbox của bạn tới backend, rồi gọi Request a Test Notification và xác nhận payload TEST tới nơi và xác minh được dựa trên chuỗi chứng chỉ của Apple.
  • Trong Transaction Manager của Xcode, hoàn tiền một giao dịch mua và xác nhận ứng dụng của bạn bỏ quyền lợi ngay khoảnh khắc revocationDate được đặt.
  • Đăng nhập một sandbox tester, mua một sản phẩm tiêu hao, yêu cầu hoàn tiền, và xác nhận máy chủ của bạn nhận CONSUMPTION_REQUEST và có thể lắp ráp và gửi một phản hồi Send Consumption Information thoải mái bên trong khung 12 hours.
  • Hoàn tiền một giao dịch mua sandbox và xác nhận thông báo REFUND tới được máy chủ của bạn, rằng bạn thu hồi quyền truy cập hoặc trừ số dư tiêu hao, và rằng việc gửi lặp lại cùng một thông báo không áp dụng hai lần.
Một chiếc điện thoại thông minh kẹp trong một ê tô bàn nhỏ dưới đèn làm việc với một cây nhíp bên cạnh, một thiết bị đang được test đại diện cho việc diễn tập một khoản hoàn tiền trước khi nó trở thành thật

Cách diễn tập một khoản hoàn tiền và một khoản chargeback trên Google Play

Google Play không có chế độ cục bộ như của Xcode. Mọi thứ chạy dựa trên máy chủ của Google, nhưng license tester giữ cho nó miễn phí và an toàn. Thêm các tài khoản Google test của bạn làm license tester trong Play Console và họ nhận được một bộ phương thức thanh toán test không bao giờ tính tiền thật. Google đánh dấu mọi giao dịch mua test bằng một thông báo chạy ngang giữa hộp thoại mua, và thuế không được tính. Điều quan trọng cho test hoàn tiền là bạn chọn công cụ test nào, vì mỗi công cụ dẫn tới một kết quả khác nhau.

Phương thức thanh toán testNó mô phỏng gìVì sao bạn dùng nó
Test instrument, always approvesMột giao dịch mua thành công sạch sẽThiết lập một đơn hàng bạn có thể hoàn tiền hoặc thu hồi sau đó
Test instrument, always declinesMột khoản thanh toán thất bạiXác nhận bạn không cấp gì khi bị từ chối
Slow test card, approves after a few minutesMột giao dịch mua đang chờ rồi sau đó thành côngRèn giũa xử lý PENDING của bạn trước khi cấp quyền truy cập
Slow test card, declines after a few minutesMột giao dịch mua đang chờ rồi sau đó thất bạiXác nhận một khoản chờ bị từ chối không bao giờ rò rỉ quyền lợi
Test card, approves then charges backMột khoản chargeback do người dùng khởi tạoKích hoạt một PendingRefundReviewNotification và diễn tập phản hồi 24 hours của bạn

Kích hoạt một khoản hoàn tiền, một khoản chargeback, và khoản tự động hoàn tiền do xác nhận

  • Mua bằng thẻ test duyệt rồi chargeback, và một PendingRefundReviewNotification đáp xuống chủ đề Real-time Developer Notifications của bạn ngay sau đó. Trả lời nó bằng một lệnh gọi orders.reviewrefund duy nhất, vì Google chỉ giữ phản hồi đầu tiên của bạn.
  • Hoàn tiền và thu hồi một đơn hàng test từ tab Orders trong Play Console để kích hoạt một VoidedPurchaseNotification, và xác nhận máy chủ của bạn kéo lại quyền lợi.
  • Cố ý để giao dịch mua của một license tester chưa được xác nhận. Google tự động hoàn tiền nó sau 3 minutes thay vì 3 days mà production cho phép, và gửi email cho bạn về việc hủy, nên một luồng xác nhận bị hỏng lộ ra trong vài phút, chứ không phải vào ngày thứ tư ở production.

Một đường hoàn tiền chưa được test thực sự tốn bao nhiêu

Một trình xử lý hoàn tiền không phải là đồ trang trí. Nó là đoạn mã ngăn bạn trả tiền để phục vụ ai đó không còn trả tiền cho bạn. Khi nó thất bại âm thầm, khoản hoàn tiền vẫn được thực hiện, nhưng quyền truy cập, số dư, và khoản chi đằng sau chúng thì không dừng lại.

Đi theo dòng tiền. Khi Apple hoặc Google hoàn tiền một giao dịch, bạn trả lại giá bán và cửa hàng trả lại hoa hồng của họ, đến đây sổ sách cân bằng. Thứ không quay lại là tất cả những gì bạn đã chi để giao sản phẩm: sức tính toán đằng sau một kết quả được tạo ra, các lệnh gọi API mô hình, dung lượng lưu trữ cho những gì người dùng đã lưu, khoản chi trả bạn đã gửi cho một nhà sáng tạo. Một trình xử lý hoàn tiền không bao giờ thu hồi quyền truy cập để một người dùng đã được hoàn tiền tiếp tục tiêu những thứ đó trên ngân sách của bạn, mà không còn gì trong hệ thống để cắt họ đi.

Hai khung thời gian bằng chứng làm điều đó sắc bén hơn. Một CONSUMPTION_REQUEST bạn chưa bao giờ rèn giũa trong sandbox là một phản hồi bạn gửi sai định dạng hoặc trễ, và Apple thường cấp khoản hoàn tiền theo mặc định khi câu trả lời của bạn không tới nơi bên trong 12 hours. Một phản hồi chargeback Google Play bạn chưa bao giờ kích hoạt bằng thẻ test là một khung 24 hours bạn làm hỏng khi chạy thật, và kể từ ngày 3 tháng 8 năm 2026, một khoản chargeback Play bị thua khiến bạn mất giá mua trừ đi phí dịch vụ của Play cộng với phí chargeback của ngân hàng. Mỗi một trong những thất bại đó đều có thể tái hiện miễn phí trong môi trường test trước. Không cái nào rẻ ở production.

Đường chưa được testNó thất bại thế nào ở productionNó khiến bạn tốn gì
Trình xử lý REFUNDMột người dùng đã được hoàn tiền vẫn giữ quyền truy cậpSức tính toán, lệnh gọi API, lưu trữ, và các khoản chi trả bạn tiếp tục tiêu cho họ
Phản hồi CONSUMPTION_REQUESTSai định dạng, hoặc gửi sau 12 hoursApple cấp khoản hoàn tiền theo mặc định, nên bạn mất cả doanh thu lẫn khoản chi
Phản hồi orders.reviewrefundBỏ lỡ hoặc sai bên trong 24 hoursKể từ ngày 3 tháng 8 năm 2026, giá mua trừ đi phí dịch vụ của Play, cộng với phí chargeback của ngân hàng

Một danh sách kiểm tra ngắn trước khi bạn ra mắt xử lý hoàn tiền

Bạn không cần một phòng thí nghiệm. Bạn cần đã tận mắt thấy mỗi sự kiện chạm vào mã của mình một lần.

  • Ứng dụng của bạn bỏ quyền truy cập ngay khoảnh khắc một giao dịch StoreKit hiện một revocationDate, đã xác nhận trong Transaction Manager của Xcode.
  • URL máy chủ sandbox của bạn nhận một thông báo TEST và xác minh nó dựa trên chứng chỉ của Apple.
  • Một REFUND sandbox thu hồi quyền truy cập hoặc trừ số dư, và một lần gửi lặp lại không tính hai lần.
  • Một CONSUMPTION_REQUEST sandbox tạo ra một phản hồi Send Consumption Information hợp lệ thoải mái bên trong 12 hours.
  • Một PendingRefundReviewNotification của Google từ thẻ test chargeback tạo ra đúng một lệnh gọi orders.reviewrefund.
  • Một giao dịch mua test Google Play chưa được xác nhận tự động hoàn tiền trong 3 minutes và khâu đối chiếu của bạn nhận ra.

Chạy danh sách đó một lần và xử lý hoàn tiền thôi không còn là đoạn mã bạn hy vọng chạy được. Nó trở thành đoạn mã bạn đã tận mắt thấy chạy.

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

Tôi có thể test một khoản hoàn tiền App Store mà không cần một giao dịch mua thật không?
Có. StoreKit testing của Xcode cho phép bạn hoàn tiền một giao dịch cục bộ qua Transaction Manager, không có tiền thật và không có tài khoản App Store, thứ kích hoạt listener Transaction.updates của ứng dụng. Nó không gửi thông báo máy chủ, nên nó chỉ test ứng dụng của bạn, không phải backend.
StoreKit testing cục bộ có gửi App Store Server Notifications không?
Không. StoreKit testing của Xcode chạy hoàn toàn trên máy Mac của bạn dựa trên một cấu hình cục bộ và không bao giờ liên hệ máy chủ của Apple, nên không App Store Server Notification nào, bao gồm REFUND hay CONSUMPTION_REQUEST, từng được gửi. Hãy dùng sandbox để test máy chủ của bạn.
Làm sao tôi test một phản hồi chargeback Google Play?
Dùng phương thức thanh toán license tester tên Test card, approves then charges back. Nó kích hoạt một PendingRefundReviewNotification ngay sau khi mua, cùng thông báo mà một khoản chargeback ngân hàng thật gửi, nên bạn có thể diễn tập phản hồi orders.reviewrefund trong 24 hours của mình.
Vì sao giao dịch mua test Google Play của tôi bị hoàn tiền sau vài phút?
Với license tester, Google tự động hoàn tiền một giao dịch sau 3 minutes nếu ứng dụng của bạn chưa xác nhận nó, và gửi email cho bạn về việc hủy. Production chờ 3 days, nhưng tester nhận phiên bản tăng tốc để một luồng xác nhận bị hỏng lộ ra nhanh.
sandbox của Apple có thử lại một thông báo hoàn tiền thất bại không?
Không. sandbox không thử lại App Store Server Notifications, nên nếu endpoint của bạn ngừng hoạt động khi một khoản hoàn tiền sandbox kích hoạt, thông báo bị đánh rơi mà không có lần thử thứ hai. Hãy xác nhận URL của bạn có thể tiếp cận được bằng Request a Test Notification trước.

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.