すべての記事
Playbook読了まで 8 分

返金処理は静かに壊れる。だから本物の顧客が先に踏む前に、sandbox でアプリ内課金の返金をテストしよう

返金処理は顧客がすでに去った後にしか走らないため、そこに潜むバグは実際に金銭的損失を出すまで見えないままです。どちらのストアも、まずテスト環境で返金を発火させることを許しています。ここでは、返金が本物になる前に App Store と Google Play でアプリ内課金の返金をテストする方法を説明します。

暗い机の上、虫眼鏡の下に置かれた iPhone と Android スマートフォン。返金が本物になる前にアプリ内課金の返金をテストすることを表しています

要点

  • Xcode の StoreKit テストでは、Transaction Manager の返金矢印をクリックするだけでローカルに購入を返金でき、アプリの Transaction.updates リスナーが発火します。ただし Apple には一切接続しないため、App Store Server Notification は送信されません。
  • Apple でサーバー側をテストするには、sandbox の App Store Server Notifications V2 URL をバックエンドに向けます。すると sandbox の返金は本物の REFUND を、返金リクエストは CONSUMPTION_REQUEST を、あなたのサーバーへ届けます。
  • Apple の Request a Test Notification エンドポイントは、設定した URL へ TEST タイプの通知を送り、testNotificationToken を返します。これにより、本物のイベントが発火する前に webhook が到達可能かを確認できます。
  • Apple の sandbox は失敗した通知を決して再送しません。そのため sandbox の発火時に webhook が停止していると、イベントは二度目の試行なく破棄されます。これは、後に本物の返金の期限を失わせるのと同じ種類の見落としです。
  • Google Play はライセンステスター向けに Test card, approves then charges back という支払い方法を提供します。これは購入直後に PendingRefundReviewNotification を発火させるため、24 hours の orders.reviewrefund への応答をリハーサルできます。
  • Google Play のライセンステスターの場合、未確認の購入は本番が待つ 3 days ではなく 3 minutes 後に自動返金されるため、壊れた確認経路はテスト中に素早く、はっきりと露呈します。
  • 一度もテストしていない返金ハンドラーこそ、返金済みの顧客に有料アクセスを保たせ続けるハンドラーです。そして 2026 年 8 月 3 日以降、テストしていない Google Play のチャージバック応答は、購入価格から Play のサービス料を引いた額に銀行の手数料を加えた分をあなたに失わせかねません。

返金処理は、顧客がすでに去った後にしか走らない唯一のコード経路です。そこに到達するには実際に返金を受けなければならないため、通常の QA では一切触れられません。こうして未テストのまま出荷され、数か月間静かに眠り、そして本物の返金で失敗します。その失敗が払わせるのは赤いテストではなく金銭です。解決策は、返金を「自分に降りかかること」として扱うのをやめ、意図的に一件発火させることです。Apple も Google も、テスト環境で返金を発火させ、あなたのサーバーの反応を観察させてくれます。ここでは、有料顧客がハンドラーの故障を証明してしまう前に、App Store と Google Play でアプリ内課金の返金をテストする方法を説明します。

返金が発火しうる三つの環境、そして本番はそのうち一つだけ

開発中に Apple や Google の返金が発火しうる場所は、それぞれ独立した三つがあり、互換ではありません。うち二つは、あなたが必要に応じて発火させられます。三つ目は本番であり、そこで返金のバグに初めて出会いたくはありません。罠は、簡単な方、つまり Xcode でのローカルテストがパイプライン全体を証明すると思い込むことです。それはあなたのアプリを証明します。あなたのサーバーについては何も語りません。

Xcode StoreKit テストはローカルなので、鍛えるのはアプリだけ

Xcode 内蔵の StoreKit テストは、Mac 上の設定ファイルに対して動き、Apple との往復はありません。デバッグバーから StoreKit Transaction Manager を開き、購入済みのトランザクションを選び、曲がった返金矢印をクリックします。トランザクションは返金済みに切り替わり、アプリの Transaction.updates リスナーが、実環境とまったく同じように発火します。beginRefundRequest を呼んで本物の返金シートを表示することもでき、Xcode 環境では選んだ問題が RevocationReason に一対一で対応し、返金は即座に適用されます。これは、revocationDate が非 nil になった瞬間にクライアントがアクセスを断つことを証明する最速の方法です。同時に、これはローカルテストが語れることのすべてでもあります。ここでは何一つ Apple のサーバーに届かないため、App Store Server Notification は送信されないからです。あなたのバックエンドは何も学びません。

sandbox は、あなたのサーバーがついに返金を耳にする場所

金銭を決めるインテグレーションの半分、つまりあなたのサーバーをテストするには、Apple の sandbox が必要です。App Store Connect で sandbox の App Store Server Notifications V2 URL を設定し、端末で sandbox テスターとしてサインインして購入します。すると sandbox での返金は本物の REFUND 通知をバックエンドへ届け、消耗型または自動更新型に対する返金リクエストは CONSUMPTION_REQUEST を届けます。これは本番サーバーが受け取るのと同じ署名済みペイロードです。何かを発火させる前に、まず Request a Test Notification エンドポイントを呼びます。これは App Store サーバーに、設定した URL へ TEST タイプの通知を送るよう指示し、testNotificationToken を渡します。それを Get Test Notification Status に渡して配信を確認します。この往復が動かなければ、本物の通知も動きません。

環境発火できるもの証明できることできないこと
Xcode StoreKit テストTransaction Manager または beginRefundRequest シートによる返金アプリがローカルで数秒のうちに返金へ反応するApple に一切接続しないため、サーバー通知は送信されない
Sandboxサーバーへの本物の REFUND と CONSUMPTION_REQUEST、加えて必要に応じた TEST 通知バックエンドが署名済みペイロードを受信、検証し、処理するエンドポイントが受信し損ねた通知を再送しない
本番すべての返金、本物の金銭でここで最初に学びたいことは何もないバグのコストを取り消すことはできない

App Store でアプリ内課金の返金をテストする方法

この順序で実行します。安価なクライアントの確認から、完全なサーバーの往復まで。各ステップは異なる部品を鍛え、後半こそ本番が実際にあなたへ請求する部分です。

  • App Store Connect の Users and Access, Integrations, In-App Purchase の下で In-App Purchase key を作成し、それを使って App Store Server API 呼び出しに署名します。
  • sandbox の App Store Server Notifications V2 URL をバックエンドに向け、Request a Test Notification を呼び、TEST ペイロードが届き、Apple の証明書チェーンに対して検証されることを確認します。
  • Xcode の Transaction Manager で購入を返金し、revocationDate が設定された瞬間にアプリがエンタイトルメントを外すことを確認します。
  • sandbox テスターとしてサインインし、消耗型を購入し、返金をリクエストし、サーバーが CONSUMPTION_REQUEST を受信し、12 hours の期限の十分内側で Send Consumption Information の返信を組み立てて送れることを確認します。
  • sandbox の購入を返金し、REFUND 通知がサーバーに届くこと、アクセスを取り消すか消耗型の残高を差し引くこと、そして同じ通知が繰り返し配信されても二重に適用されないことを確認します。
作業灯の下、小さな万力に挟まれたスマートフォンとその横のピンセット。テスト対象の端末が、返金が本物になる前にリハーサルすることを表しています

Google Play で返金とチャージバックをリハーサルする方法

Google Play には Xcode のようなローカルモードはありません。すべてが Google のサーバーに対して動きますが、ライセンステスターがそれを無料かつ安全に保ちます。Play Console でテスト用の Google アカウントをライセンステスターとして追加すると、本物の金銭を一切請求しない一連のテスト支払い方法が付与されます。Google はすべてのテスト購入に、購入ダイアログの中央を横切る告知を付け、税額は計算されません。返金テストで重要なのは、どのテスト手段を選ぶかです。それぞれが異なる結果を導くからです。

テスト支払い方法何をシミュレートするかなぜ使うか
Test instrument, always approvesきれいな成功購入あとで返金または取り消しできる注文を用意する
Test instrument, always declines失敗した支払い拒否時に何も付与しないことを確認する
Slow test card, approves after a few minutes後で成功する保留中の購入アクセスを付与する前に PENDING 処理を鍛える
Slow test card, declines after a few minutes後で失敗する保留中の購入保留中の拒否がエンタイトルメントを漏らさないことを確認する
Test card, approves then charges backユーザー起点のチャージバックPendingRefundReviewNotification を発火させ、24 hours の応答をリハーサルする

返金、チャージバック、そして確認の自動返金を発火させる

  • 承認後にチャージバックするテストカードで購入すると、少し後に PendingRefundReviewNotification があなたの Real-time Developer Notifications トピックに着きます。単一の orders.reviewrefund 呼び出しで応えてください。Google は最初の応答しか保持しないからです。
  • Play Console の Orders タブでテスト注文を返金し取り消して VoidedPurchaseNotification を発火させ、サーバーがエンタイトルメントを引き上げることを確認します。
  • ライセンステスターの購入をわざと未確認のままにします。Google は本番が許す 3 days ではなく 3 minutes 後に自動返金し、キャンセルをメールで知らせます。そのため壊れた確認経路は、本番の四日目ではなく数分で表面化します。

未テストの返金経路が実際にいくらかかるか

返金ハンドラーは飾りではありません。もはやあなたに払わない相手のために払い続けるのを止めるコードです。それが静かに失敗すると、返金自体は通り続けますが、その背後のアクセス、残高、支出は止まりません。

お金を追ってください。Apple や Google が購入を返金すると、あなたは販売価格を返し、ストアは手数料を返すので、ここまで帳簿は釣り合います。返ってこないのは、製品を届けるために既に使ったすべてです。生成結果の背後の計算資源、モデルの API 呼び出し、ユーザーが保存したものの保管、すでに送ったクリエイターへの支払い。アクセスを決して取り消さない返金ハンドラーは、返金済みユーザーにそれらをあなたの予算で使い続けさせ、それを断つものはシステムに何も残りません。

二つの証拠期限がこれを鋭くします。sandbox で一度も鍛えていない CONSUMPTION_REQUEST は、形式不正または遅れて送る返信であり、あなたの回答が 12 hours の内側に着かないと、Apple はしばしば既定で返金を認めます。テストカードで一度も発火させていない Google Play のチャージバック応答は、本番で取りこぼす 24 hours の期限であり、2026 年 8 月 3 日以降、失われた Play のチャージバックは、購入価格から Play のサービス料を引いた額に銀行のチャージバック手数料を加えた分をあなたに払わせます。これらの失敗はどれも、まずテスト環境で無料に再現できます。そのどれも本番では安くありません。

未テストの経路本番でどう失敗するか何をあなたに払わせるか
REFUND ハンドラー返金済みユーザーがアクセスを保つあなたが彼らに使い続ける計算資源、API 呼び出し、保管、支払い
CONSUMPTION_REQUEST の返信形式不正、または 12 hours 後に送信Apple が既定で返金を認めるため、売上と支出の両方を失う
orders.reviewrefund の応答24 hours の内側で見落とすか誤る2026 年 8 月 3 日以降、購入価格から Play のサービス料を引いた額に、銀行のチャージバック手数料を加えた分

返金処理を出荷する前の短いチェックリスト

ラボは要りません。各イベントがコードに当たるのを一度、見届けておくことが必要です。

  • StoreKit のトランザクションが revocationDate を示した瞬間にアプリがアクセスを外すこと。Xcode の Transaction Manager で確認済み。
  • あなたの sandbox サーバー URL が TEST 通知を受信し、Apple の証明書に対して検証すること。
  • sandbox の REFUND がアクセスを取り消すか残高を差し引き、再配信が二重計上しないこと。
  • sandbox の CONSUMPTION_REQUEST が、12 hours の十分内側で有効な Send Consumption Information の返信を生成すること。
  • チャージバックのテストカードからの Google PendingRefundReviewNotification が、ちょうど一回の orders.reviewrefund 呼び出しを生成すること。
  • 未確認の Google Play テスト購入が 3 minutes で自動返金され、あなたの照合がそれに気づくこと。

そのリストを一度走らせれば、返金処理は「動くと願うコード」ではなくなります。それは、あなたが動くのを見届けたコードになります。

よくある質問

本物の購入なしで App Store の返金をテストできますか。
できます。Xcode の StoreKit テストは、Transaction Manager を通じてローカルに購入を返金でき、本物の金銭も App Store アカウントも不要で、アプリの Transaction.updates リスナーを発火させます。サーバー通知は送らないため、テストするのはアプリだけで、バックエンドはテストしません。
ローカルの StoreKit テストは App Store Server Notifications を送りますか。
いいえ。Xcode の StoreKit テストは Mac 上のローカル設定に対して完全に動き、Apple のサーバーには一切接続しないため、REFUND や CONSUMPTION_REQUEST を含め、App Store Server Notification は一切送信されません。サーバーのテストには sandbox を使ってください。
Google Play のチャージバック応答はどうテストしますか。
Test card, approves then charges back という名前のライセンステスター用支払い方法を使います。それは購入直後に PendingRefundReviewNotification を発火させ、本物の銀行チャージバックが送るのと同じ通知なので、24 hours の orders.reviewrefund 返信をリハーサルできます。
なぜ私の Google Play テスト購入は数分後に返金されるのですか。
ライセンステスターの場合、アプリが確認していないと Google は 3 minutes 後に購入を自動返金し、キャンセルをメールで知らせます。本番は 3 days 待ちますが、テスターには加速版が与えられ、壊れた確認経路が素早く表面化します。
Apple の sandbox は失敗した返金通知を再送しますか。
いいえ。sandbox は App Store Server Notifications を再送しないため、sandbox の返金が発火したときにエンドポイントが停止していると、通知は二度目の試行なく破棄されます。まず Request a Test Notification で URL が到達可能なことを確認してください。

出典と参考資料

RefundHalt

App Store と Google Play の返金を自動処理

続きを読む

次の返金リクエストは、すでに向かってきています。

異議を申し立てられなかった返金について、もう 1 通のサポートメールを読む時間で RefundHalt を設定できます。