アプリ内課金
PR

【Google】参照期限が過ぎたレシートやトークン無効化のレスポンス(400, 410エラー)

saratogax
記事内に商品プロモーションを含む場合があります

この記事の内容は Google の仕様変更等で古くなっている可能性があります。2025 年以降の、GooglePlay のアプリ内課金については、以下の記事をベースにまとめ直しましたので参考にしてください。

【Google】アプリ内課金の購入ライフサイクルと通知(RTDN)

Google Play Billing(Android)の古いレシートの話。

先日、有効期限が切れてそれなりの期間が経過した purchaceToken のレシートを検証してみたところ、有効期限切れで無効なレシート情報が返ってくるのかと思ったら、Google Play から 400 や 410 ステータスのエラーが返された。

400 はともかく、「410 Gone」って初めて見たかも。

そこで、この有効期限が切れた古いレシートについて調べてみましたのでまとめておきます。

Google のサブスクの基本については以下を参照してください。

あわせて読みたい
【Google】アプリ内課金のサブスクリプションのライフサイクル
【Google】アプリ内課金のサブスクリプションのライフサイクル

Googleの400エラーの詳細内容

purchases.subscriptionsv2 の API では、失効から一定の日数が経過した参照で 400 エラーが返されます。

メッセージの通り、「有効期限を過ぎてから長期間経過しているので、そのサブスクリプションのクエリ問い合わせはできなくなりました」ということです。

具体的には以下のようなレスポンスです。

{
    "error": {
        "code": 400,
        "message": "The subscription purchase is no longer available for query because it has been expired for too long.",
        "errors": [
            {
                "message": "The subscription purchase is no longer available for query because it has been expired for too long.",
                "domain": "global",
                "reason": "failedPrecondition"
            }
        ],
        "status": "FAILED_PRECONDITION"
    }
}

Googleの410エラーの詳細内容

purchases.subscriptions の API では、失効から一定の日数が経過した参照で 410 エラーが返されます。

v2 の API の時と同様の内容ですが、ステータスコードが 410 になっています。

この 410 を返す purchases.subscriptions(v1)は、2025 年 5 月 21 日付けで非推奨になりました。

シャットダウン予定日は 2027 年 8 月 31 日で、それ以降は subscriptions.get の呼び出し自体ができなくなります。

サポートへの申請で 2027 年 11 月 1 日まで延長できるとされていますが、あくまで例外措置です。

これから実装するなら、400 を返す subscriptionsv2.get を使ってください。

つまり、この記事の 410 は「いずれ見られなくなるエラー」で、410 のハンドリングを作り込むより v2 への移行が本筋です。

具体的には以下のようなレスポンスです。

{
    "error": {
        "errors": [
            {
                "domain": "androidpublisher",
                "reason": "subscriptionPurchaseNoLongerAvailable",
                "message": "The subscription purchase is no longer available for query because it has been expired for too long."
            }
        ],
        "code": 410,
        "message": "The subscription purchase is no longer available for query because it has been expired for too long."
    }
}

どのタイミングからレシート検証が弾かれるのか

では一体、有効期限をどのくらい過ぎると問い合わせができなくなるのでしょうか。

Google Play の公式的な資料やコメントが見当たらなかったので、stackoverflow に頼ることになったのですが、どうやら有効期限から 60 日のようです。

Starting on May 21, 2018, Purchases.subscriptions.get will return HTTP status 410 with no content in the response for subscriptions that have been expired for 60 days or more. There is no change for active subscriptions or canceled subscriptions that have not yet expired or been expired for fewer than 60 days.

Google Android publisher API responds with “410 purchaseTokenNoLongerValid” error

有効期限が切れた場合の挙動

有効期限が切れた場合、通常だと以下のフローを辿って解約状態(無効)となります。

・ユーザの意図的な解約があった(この場合は即時無効)
・決済不備で猶予期間になった
・猶予期間を過ぎて一時停止になった
・一時停止期間を過ぎて無効になった

猶予期間や一時停止期間の有無は Google Play Console の設定によりますが、どちらにしてもサブスクリプションが継続更新されないと最終的には解約状態(無効)となります。

ここで注意したいのは、60 日のカウントがどこから始まるかです。

公式ドキュメントによると、一時停止(Account Hold)に入った時点で expiryTime は過去の日時に書き換えられます。

つまり 60 日は「一時停止が明けてから」ではなく、一時停止が始まった時点から数え始めるということですね。

一時停止を 30 日で運用しているなら、それが明けてからさらに 30 日ほど参照できる計算になります。

ただし、一時停止の長さが 30 日という前提は今は成り立ちません。

現在の既定では、一時停止の期間は「60 日から猶予期間を引いた日数」として自動計算されます。

猶予期間を設定していなければ一時停止だけで 60 日となり、一時停止が明けた時点で購入トークンの 60 日も尽きていることになります。

「無効になってから確認すればいい」と考えていると参照できないので、自分のアプリの猶予期間と一時停止の設定を Google Play Console で確認しておきましょう。

ちょうど手元に、55 日前と 65 日前が有効期限の purchaceToken があったので、それぞれについてレシート検証してみました。

結果はご覧の通り。

55日前:レシートの内容が返される
65日前:410エラー

通常、一時停止(Account Hold)が切れてから 30 日以上も後にレシート検証することはないと思いますが、運用上、そういったケースが発生しないとも限らないので挙動だけ覚えておきたいですね。

2020 年の後半に Google の公式ドキュメントにも記載され、現在のドキュメントにも同じ内容が引き継がれています。

購入トークンは定期購入の登録後から有効期限の 60 日後まで有効です。この期間を経過すると、購入トークンは無効となり、それを使用して Google Play Developer API を呼び出すことはできなくなります。

定期購入のライフサイクル(Android Developers)

トークンが無効化されるパターン

古いレシートの件とは別に、トークン(purchaseToken)が無効化された場合にも 410 エラーが返ってくるパターンがありました。

Google に問い合わせてみないと詳しいことはわかりませんが、ユーザがサブスクの解約ではなくて Google のアカウント削除をしてしまったのではないかと推測しています。

ただ、それならそれで、レシートの解約理由(cancelReason)などにそれっぽい設定をして、解約済のレシートを返却して欲しいですよね。

こちらとしては一時的な問題なのか判断に迷うところです。

{
    "error": {
        "code": 410,
        "message": "The purchase token is no longer valid.",
        "errors": [
            {
                "message": "The purchase token is no longer valid.",
                "domain": "androidpublisher",
                "reason": "purchaseTokenNoLongerValid"
            }
        ]
    }
}

参考(出典)

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました