Google Play の購入が返金またはチャージバックされたとき、それを知る手段が Voided Purchases API です
Google Play は購入が返金またはチャージバックされると、静かにその購入を無効化します。Voided Purchases API はそうした注文の一覧であり、これを使ってアクセスを取り消せます。ここではすべてのフィールド、30日間のウィンドウ、注文を隠してしまう revoke オプション、そしてそのコストを解説します。

要点
- Voided Purchases API、つまり purchases.voidedpurchases.list メソッドは、Google Play がキャンセル、返金、またはチャージバックした注文を返します。これにより、顧客がもはや所有していないものへのアクセスを断つ取り消しの仕組みを構築できます。
- 表示されるのは revoke された注文だけです。revoke オプションなしで発行された開発者返金はこの API には現れません。したがってアクセスを引き上げたいなら、revoke をオンにして返金する必要があります。
- ウィンドウは30日間です。startTime は30日前より古くは設定できないため、サーバーが1か月を超えて停止すると、それらの無効化された注文は永久に失われます。スケジュールに従ってポーリングしてください。
- voidedSource は誰が注文を無効化したかを示します。0 はユーザー、1 は開発者、2 は Google です。voidedReason は理由を示し、0 の Other から 7 の Chargeback、8 の Unacknowledged_purchase まであります。
- Real-time developer notifications は購入が無効化された瞬間に VoidedPurchaseNotification をプッシュしますが、これはあくまで合図として扱ってください。取り消す前に、権威ある一覧を得るために Voided Purchases API を呼び出してください。
- サブスクリプションの更新は purchaseToken ではなく orderId で識別してください。1つの purchaseToken はサブスクリプションのすべての更新をカバーするため、トークンだけでは2つの更新を区別できません。
- クォータは1日あたり6,000クエリ、30秒間のウィンドウあたり30クエリです。したがって継続トークンで結果をページ送りし、時間ウィンドウで問い合わせてください。注文ごとに1回呼び出すようなことは決してしないでください。
Google Play での返金は、あなたのドアをノックしてはくれません。お金は動き、顧客はアプリを開いたままにでき、あなたが探しに行かない限り、あなた側では何も変わりません。Voided Purchases API はまさにその探しに行く場所です。キャンセル、返金、またはチャージバックされた注文の一覧を渡してくれるので、顧客がもう支払っていないものへのアクセスを取り消せます。スケジュールされたジョブをそこに向け、一覧を読み、権利を断つ。それがループのすべてです。
多くのチームがつまずく落とし穴が1つあり、それはコードの中にはありません。ここに現れるのは revoke された注文だけです。Play Console で revoke オプションにチェックを入れずに購入を返金すると、その注文はこの API には決して届かず、返金された顧客があなたが売ったものすべてを保持したまま、ジョブは何事もなく動きます。この記事では API をフィールドごとに、それを制約する数値ごとに、そしてこれを省いたときにどこでお金が漏れるのかを解説します。
Voided Purchases API が実際に返すもの
この API は1つの問いに答えます。このアプリのどの注文が最近無効化されたか、です。無効化 (void) は、顧客が返金を受ける3つの結末をカバーします。キャンセル、返金、またはチャージバックです。これは1回限りのアプリ内商品にもサブスクリプションにも適用され、範囲は1つのパラメータで選びます。type を 0 にすると無効化されたアプリ内商品の購入だけが得られ、これがデフォルトです。1 にすると、無効化されたアプリ内購入と無効化されたサブスクリプション購入の両方が得られます。
一覧の各エントリは voided purchase オブジェクトです。フィールドは少なく、そのどれもが重要です。
voided purchase のフィールド
| フィールド | 何を保持するか |
|---|---|
| orderId | 1回限りの購入、サブスクリプション購入、または単一のサブスクリプション更新を一意に識別する注文 id。これが結合キーです |
| purchaseToken | 1回限りの購入またはサブスクリプションを識別するトークン。更新を区別しないため、更新には orderId を使ってください |
| purchaseTimeMillis | 購入が行われた時刻。エポックからのミリ秒 |
| voidedTimeMillis | 購入がキャンセル、返金、またはチャージバックされた時刻。エポックからのミリ秒 |
| voidedSource | 誰が無効化を開始したか。0 ユーザー、1 開発者、2 Google |
| voidedReason | 購入が無効化された理由。0 から 8 までの整数 |
| voidedQuantity | 数量ベースの部分返金による無効化された数量。includeQuantityBasedPartialRefund が true のときのみ返される |
行動する前に voidedReason を読む
voidedReason は生の一覧を判断に変えるフィールドです。買い手の後悔による返金と銀行のチャージバックはどちらも同じ一覧に入りますが、それらは同じ出来事ではなく、8月の料金体系は一方を高くつくものにします。以下がその全セットです。
| voidedReason | ラベル | あなたにとっての意味 |
|---|---|---|
| 0 | Other | カテゴリが割り当てられていません。取り消して先へ進みましょう |
| 1 | Remorse | 買い手が気を変えました。通常の返金です |
| 2 | Not_received | 顧客が商品を受け取っていないと主張しています。配送を確認する価値があります |
| 3 | Defective | 商品が機能しませんでした。品質のシグナルなので記録しましょう |
| 4 | Accidental_purchase | 意図しない購入。共有デバイスでよく起きます |
| 5 | Fraud | Google が取引を不正としてフラグしました |
| 6 | Friendly_fraud | 正当なカード所有者が自分で行った請求を争うチャージバック |
| 7 | Chargeback | 顧客の銀行が支払いを取り消しました。銀行側で確定し、いまやあなたに請求されます |
| 8 | Unacknowledged_purchase | あなたのアプリが確認しなかった購入を Google が自動返金しました |
30日間のウィンドウは一覧を空にする罠
Voided Purchases API は過去30日間の無効化された購入しか表示できません。startTime パラメータは現在時刻から30日を引いた値をデフォルトとし、それより古くは設定できません。endTime のデフォルトは現在です。したがってこのエンドポイントはアーカイブではなく、1か月のローリングウィンドウです。
その帰結は率直です。ポーリングジョブが壊れ、5週間誰も気づかなければ、1週目の無効化は API から期限切れになっています。それらを取り戻す呼び出しはありません。それらの注文を取り消すこともできず、他の方法で捕捉していない限り、それらが存在したことすら分かりません。この API は、最悪の障害の長さに合わせた穴の空いたセーフティネットです。
revoke オプションが注文が表示されるかどうかを決める
これはチームが API を壊れていると報告する最も一般的な理由です。返されるのは revoke された注文だけです。ユーザー起点の返金、キャンセル、チャージバック、および Google 起点の返金は常に revoke されるため、常に表示されます。開発者起点の返金は異なります。Play Console または Orders API を通じて自分で注文を返金するとき、それを併せて revoke するかどうかを選びます。revoke なしで返金すると、その注文は顧客との間で決済されますが、Voided Purchases API には決して現れません。
そこから導かれるルールは単純です。アクセスを引き上げるのが目的なら、revoke オプションをオンにして返金してください。そうでなければ、お金を返した上でドアを開けたままにしており、どれほどよく書かれた取り消しジョブでも、対処すべき対象が何もありません。
クォータに引っかからずにポーリングする方法
このエンドポイントはレート制限されており、その制限は素朴なループなら引っかかるほど低いです。1日あたり6,000クエリ(太平洋時間で集計)、そして30秒間で30クエリを超えないことが許されます。その予算はウィンドウ単位のポーリングには十分で、注文ごとに1リクエストする設計には敵対的です。
クエリウィンドウと継続トークン
maxResults はデフォルトで1,000で、これは上限でもあります。ウィンドウが1ページを超える無効化を保持しているとき、レスポンスには nextPageToken を持つ tokenPagination オブジェクトが含まれます。そのトークンを次の呼び出しに渡してページを辿ってください。関心のあるウィンドウを区切るために startTime と endTime を設定し、トークンが尽きるまでページ送りし、それからウィンドウを進めてください。このパターンは30秒のバースト制限と1日の上限の両方の内側に留めてくれます。
Real-time developer notifications がギャップを埋める
毎日ポーリングしても最大で丸1日の盲点が残り、30日間のウィンドウは長い空白を罰します。Real-time developer notifications はその遅延を取り除きます。Google は購入が無効化された瞬間に、あなたが所有する Cloud Pub/Sub トピックへ VoidedPurchaseNotification を発行し、あなたのバックエンドは数秒以内にそれを消費します。メッセージは小さいものです。
| RTDN フィールド | 何を保持するか |
|---|---|
| purchaseToken | 元の購入からのトークン |
| orderId | 無効化された取引の注文 id。サブスクリプション更新ごとに新しいもの |
| productType | サブスクリプションは 1、1回限りの購入は 2 |
| refundType | 全額返金は 1、数量ベースの部分返金は 2 |

これがお金の面であなたに何をもたらすか
この API は配管ですが、それを配線する理由は請求書です。その一覧にあるすべての無効化は実際の数字に対応し、そのうち2つはより高くつくようになります。
チャージバックの請求は2026年8月3日からあなたに来る
2026年8月3日から、Google はチャージバックのコストを開発者に移します。購入価格を失い、その上に銀行のチャージバック手数料を支払います。voidedReason が 7 の場合、それはもはや失われた売上というだけでなく、手数料が付いた費用項目です。チャージバックを取り消すことはできず、銀行との間で確定していますが、その後の出血を止めることはできます。無効化を素早く捕えれば、権利を取り消し、まだ提供しているものについては、返金されてから取り消された顧客への支出を止められます。
返金された顧客にサービスを提供し続けるコストを払い続ける
無効化が現れた瞬間、購入価格は消えます。あなたがまだ制御できるのは、提供を続けるコストです。返金された権利が有効なままの1時間ごとに、顧客がもはや資金を出していないものへの支払いを続けます。コンピュート、モデルの API 呼び出し、ストレージ、そして彼らの利用に紐づくクリエイターやパートナーへの支払いです。この API で駆動される取り消しの仕組みは、そのメーターを止める方法です。それを省けば、ストアがすでに払い戻した人々のために製品を賄うことになります。
friendly fraud は傾向を追う価値のあるパターン
voidedReason が 5 または 6 は単発ではありません。Fraud と friendly fraud はアカウント別、デバイス別、そして時にはプロモーション別に集まります。API はすべての無効化に voidedSource と voidedReason を与えるので、各取り消しを孤立したコストとして扱うのではなく、アカウント別に不正の傾向を追うのに十分です。2回チャージバックする顧客は、最初の返金では分からなかった何かをあなたに告げています。
RefundHalt 流の配線
すべてのピースを手にすれば、モデルは小さなものです。何も丸1日待たないように、リアルタイムで VoidedPurchaseNotification を待ち受けます。サブスクリプションの更新が決して混同されないよう orderId をキーにして、真実の源として Voided Purchases API を呼び出します。チャージバックが後悔による返金とは違う扱いになるよう、voidedSource と voidedReason を読みます。30日間のウィンドウが決して噛みつかないよう十分に短いスケジュールでポーリングし、アクセスを断つのが目的なら常に revoke オプションをオンにして返金します。
これは RefundHalt があなたのために動かす部分です。リアルタイム通知を消費し、すべての無効化を API と突き合わせ、製品全体ではなく正確な注文を取り消し、高くつくものが埋もれずにフラグされるよう、銀行のチャージバックを通常の返金と切り分けます。Pub/Sub パイプラインやポーリングジョブを自分で立ち上げることなく、数秒でアクセスが取り消され、誰が何をなぜ無効化したかの記録が得られます。
よくある質問
- 返金した注文が Voided Purchases API に表示されないのはなぜですか?
- 返されるのは revoke された注文だけだからです。ユーザーの返金、キャンセル、チャージバック、および Google 起点の返金は常に revoke され、常に表示されます。開発者起点の返金は、あなたが revoke オプションも選んだ場合にのみ表示されます。revoke せずに注文を返金した場合、その注文は決済されていますがこの API には見えません。したがってアクセスを引き上げるつもりがあるときは常に revoke をオンにして返金してください。
- Voided Purchases API はどこまで遡れますか?
- 30日間です。startTime パラメータは現在時刻から30日を引いた値をデフォルトとし、それより古くは設定できないため、このエンドポイントはアーカイブではなく1か月のローリングウィンドウです。30日を過ぎて期限切れになった無効化された注文は API から消え、取り戻す方法はありません。だからこそスケジュールに従ってポーリングし、リアルタイム通知でそれを補強します。
- アクセスを取り消すには Real-time developer notifications と Voided Purchases API のどちらを使うべきですか?
- 両方使ってください。VoidedPurchaseNotification は数秒以内に届き、見るべきだと告げますが、Google 自身の指針はそれを真実の源ではなく合図として扱うことです。Voided Purchases API を呼び出して現在の状態を確認してから取り消してください。通知は遅延を取り除き、API は対処すべき権威ある voidedSource と voidedReason を与えます。
- API でチャージバックと通常の返金をどう見分けますか?
- voidedReason フィールドを読んでください。値が 7 なら顧客の銀行が支払いを取り消したことを意味するチャージバックで、6 は friendly fraud です。値が 1 なら後悔による返金です。これが重要なのは、2026年8月3日から Google がチャージバックの購入価格と銀行手数料を開発者に渡すため、voidedReason が 7 の場合は通常の返金よりも高くつくからです。
- Voided Purchases API はサブスクリプションをカバーしますか?
- はい。type パラメータを 1 に設定すると、無効化されたアプリ内購入と無効化されたサブスクリプション購入の両方が得られます。デフォルトの type 0 はアプリ内商品の購入のみを返します。サブスクリプションについては、1つの purchaseToken がすべての更新をカバーし、各更新取引に対して新しい orderId が生成されるため、正確な無効化された期間を orderId で識別してください。
出典と参考資料
- Google Play Developer API: Voided Purchases API guide
- Google Play Developer API: purchases.voidedpurchases.list method
- Google Play Developer API: purchases.voidedpurchases resource (voidedSource and voidedReason)
- Android Developers: Real-time developer notifications reference (VoidedPurchaseNotification)
- Android Developers: Fight fraud and abuse with Play Billing
RefundHalt
App Store と Google Play の返金を自動処理
続きを読む
Apple が判断を下した後に 3 種類の App Store 返金通知が届き、REFUND_REVERSED は売上を返してくれる
Apple は App Store Server Notifications V2 を通じて 4 種類の返金メッセージを送りますが、ほとんどのアプリは 2 種類しか処理していません。REFUND は権利の取り消しを指示し、REFUND_DECLINED は売上をそのまま保持することを意味し、REFUND_REVERSED は売上を返したうえで、あなたが取り上げたものを復元するよう求めます。それぞれに何が必要かを説明します。
Apple の返金リクエストにはすべて理由が付くようになり、consumptionRequestReason がそれを読み取る手段です
WWDC24 以降、すべての Apple CONSUMPTION_REQUEST は consumptionRequestReason、つまり顧客自身が述べた返金希望の理由を含んでいます。値は UNINTENDED_PURCHASE から LEGAL まで五つあり、それぞれが 12 時間の対応枠の中で返すべき内容を変えるはずです。ここではその一つひとつの読み方を説明します。