【GooglePlayアプリ内課金】Subscriptions and In-App Purchases API

# 概要

Google Play Developer API というバックエンドからアクセスできる API 群のち、定期購入に関する API についてまとめてみました。

# Subscriptions and In-App Purchases API について

この API では、API を通じて以下を管理できます。

* [アプリ内アイテム](https://developers.google.com/android-publisher/api-ref/rest/v3/inappproducts?hl=ja)
* [アイテムの購入ステータス](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.products?hl=ja)
* [定期購入管理](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions?hl=ja)

これらの API を利用して、ステータスの確認と定期購入の変更・解約を行うことができます。

# API の使い方

## 準備

この API は、Google Play Console で設定、管理します。

### [1. 新しいプロジェクトを作成する](https://developers.google.com/android-publisher/getting_started?hl=ja#linking_your_account_and_project)

Google Play Console の 「APIアクセス」ページから「新しいプロジェクトを作成」をクリックして作成します。
既にプロジェクトが存在している場合は不要です。また、プロジェクトはアプリと 1:1 に用意する必要もありません。
用途に応じて作成すればよいと思います。

### [2. サービスから利用するアカウントを作成する](https://developers.google.com/android-publisher/getting_started?hl=ja#configure_oauth_and_service_accounts)

サービスから API 等の GCP のリソースにアクセスするにあたり認証が必要となります。
認証方法は2種類あり、OAuth を利用する方法とサービスアカウントを利用する方法があります。
[Google Play Console API アクセス](https://play.google.com/console/developers/api-access?hl=ja) ページからウィザードに従って作成するだけで、特に迷う点はないと思います。

## 実装

大体の言語にはクライアントライブラリが提供されているため、組み込み自体はそれほど迷う点はないと思います。
https://developers.google.com/api-client-library?hl=ja

## 注意点

* クエリは、1日当たり 200K に制限されています
  * クエリ数は [Google Cloud Console 割り当て](https://console.cloud.google.com/iam-admin/quotas?service=androidpublisher.googleapis.com&hl=ja) で確認できます
  * 上限に達しそうな場合、制限を超える割り当てをリクエストすることができます
  * https://developers.google.com/android-publisher/quotas?hl=ja

# API の解説

## 概要

RESTful API となっており、同じリソースのAPIは同じリソースで作成・取得できます。
リソースは、パッケージ名(アプリ名)で分けられており、API 呼び出し時には取得できるようにしておく必要があります。
アクセスできる対象は、GCP に関連付けられたアプリと認証されるアカウントの権限で管理されるため、アプリを横断することも可能です。

## inappproducts

商品管理するAPI群。商品数が少なければ、Play Console で作成してしまっても困らないため、何かに連動して商品を大量に作るときに利用する。

https://developers.google.com/android-publisher/api-ref/rest/v3/inappproducts

## purchases.subscriptions

定期購入を管理するAPI群。基本的に購入は、ユーザが行うため、API からできることは、下記の通り。

* 取得
  * 定期購入の情報を取得する
* (定期購入の)承認
  * google playの定期購入は承認が必要。これはアプリのAPIでも可能
  * 承認APIは、承認済みで再リクエストしてもエラーにはならない
* 取消、解約、払い戻し
  * 定期購入の取り消し（取消、解約、払い戻しについては、[【GooglePlayアプリ内課金】定期購入のライフサイクル]() の記事に書いているので参考にしていただけると）
  * 取消や払い戻しは重複してリクエストするとエラーになる
  * 承認・未承認のどちらであってもリクエストできる
* 課金の遅延
  * 次回の請求日を遅延することができる機能

また、全ての API は、パッケージ名 + 定期購入ID(定期購入商品のID) + purchase token でアクセスできます。

### [subscription.purchase resource](https://developers.google.com/android-publisher/api-ref/rest/v3/purchases.subscriptions?hl=ja#resource:-subscriptionpurchase)

リソースの値についての補足。基本的にはリファレンスに書かれている通りなのだけれど、わかりづらい部分もあったので、試してみた結果をまとめておきます。

| 名前 | 概要 | 詳細 |
|-----|-----|-----|
| purchaseToken | 購入トークン | 定期購入を一意に表すもの。問い合わせたところパッケージを含まなくても一意らしい。<br>文字数に関しての記載はないが、512文字あればたぶん大丈夫とのこと。 |
| expiryTimeMillis | サービスが期限切れ日時 | サービスを提供する期限が設定されている<br>猶予期間が設定されている場合は自動で更新される<br>ミリ秒のエポックで取得できる。例えば、 2021/07/26/12:34:56.001 は、 1627270496123 となる |
| priceAmountMicros | 価格 | 小数点以下6桁まである販売価格。例えば、￥550 は、 550000000 となる |
| paymentState | 支払状態 | キャンセルや期限切れだと設定されない。私は go で書いていたのですが、 go のライブラリだと 0 で初期化されるせいでキャンセル時などに判別がつかなくなりました |
| cancelReason | 解約理由 | 解約方法の識別子<br>Play Console や API から行った取消を判断したくなる場合もあると思いますが、それを表す値はないため、ここの値が「3: システム解約」である場合で分岐するといいと思います |
| userCancellationTimeMillis | ユーザ解約日時 | ユーザが解約した日時が設定される。そのため、ユーザ解約以外で解約された場合、設定されない |
| cancelSurveyResult | 解約理由調査結果 | ユーザによる解約でない場合、または、解約理由を答えないを選択された場合、設定されない |
| orderId | 注文番号 | GPA.0000-0000-0000-00000 / GPA.0000-0000-0000-00000..1 といった感じではらいだされる。サフィックスのインクリメントは請求毎(更新毎)に新規発行される<br>Play Consoleやユーザへのメールではこの注文番号が参照用のIDとなる |
| purchaseType | 支払種別 | アプリライセンスを利用したテスト課金やプロモ課金を区別するのに利用します |

### ライフサイクルの見分け方

ライフサイクルを直接表現する値はないため、各フィールドを組み合わせて判断します。
アプリのAPIでは判断つかないものも、バックエンドAPIでは全て判別がつきます。

| 状態 | expiryTimeMillis | paymentState | autoRenewing | 備考
| ----- | ----- | ----- | ----- | ----- |
| 有効 | 未来 | 1（支払受領済） | true | |
| 解約済み | 未来 | 1 | false | |
| 猶予期間中 | 未来 | 0（支払保留中） | true | |
| 保留中 | 過去 | 0 | true | |
| 一時停止 | 過去 | 1 | true | |
| 期限切れ | 過去 | なし | false | 期限切れ後、60日で参照できなくなるため、それも期限切れと判断する |

https://developer.android.com/google/play/billing/subscriptions#lifecycle


# 補足

## 用語

* デベロッパーアカウント
  * アプリ等を管理するための Google アカウント
* Google Play Console
  * デベロッパーアカウントや属するアプリの管理ができる Web GUI ツール
* GCP プロジェクト
  * GCP を利用するために発行するもの
  * API割り当てや料金がこのプロジェクト単位で管理される
* サービスアカウント
  * GCP プロジェクトに対して、アプリケーションなどから利用するためのアカウント