アプリ内課金(IAP)アプリのレシート検証
レシート検証サービス(RVS)を使用すると、アプリのユーザーが行った購入を検証できます。
RVSの概要
次の画像は、レシート検証を使用する購入ワークフローを表しています。RVSは、アプリ内課金(IAP)APIによる購入が完了した後に開始され、購入レシートをアプリに返します。

次の表の手順番号は、上図の引き出し線の番号に対応しています。
手順 | コンポーネント | タスク |
---|---|---|
1 | IAP API | IAP APIがユーザーとやり取りして購入を完了します。IAP APIからアプリに購入レシートが返されます。 |
2 | アプリ | アプリがアプリサーバーに購入レシートを転送します。 |
3 | アプリサーバー | アプリサーバーがRVSサーバーにレシート検証リクエストを送信します。 |
4 | RVSサーバー | レシートが有効であることをRVSサーバーが確認します。 |
5 | アプリサーバー | アプリサーバーがユーザーに対してコンテンツを利用可能にします。 |
また、RVSでは、アプリ以外のプラットフォーム(ウェブサイトなど)で購入された定期購入型アイテムへのアクセスを有効にすることもできます。ただし、その購入がAmazonを通じて行われた場合に限ります。このワークフローは次のようになります。
- アプリのユーザーが、アプリ提供元のウェブサイトからAmazonを通じて定期購入型アイテムを購入します。
- アプリが、購入された定期購入型アイテムのレシートを受け取ります。
- アプリがレシートの情報をアプリサーバーに送信します。アプリサーバーがRVSに問い合わせを送信して、このトランザクションを検証します。成功すればアクセスが有効になります。
RVSのセットアップ
RVSには、アプリが開発/テスト段階にあるか、Amazonアプリストアで公開されているかに応じて、2つの環境オプションが用意されています。
- RVS Cloud Sandbox: アプリの開発中およびテスト中は、RVS Sandbox環境を使用して、App Testerテストツールで生成されたレシートを検証します。RVS Cloud Sandboxをセットアップするには、RVS Cloud Sandboxの使用を参照してください。
- RVS本番サーバー: アプリをAmazonアプリストアに公開した後は、Amazon RVS本番サーバーを使用できます。RVS本番環境のセットアップを参照してください。
RVSリクエストの構文
RVSは、PurchaseResponse
オブジェクト(英語のみ)またはPurchaseUpdatesResponse
オブジェクト(英語のみ)を検証するために使用します。これらのレスポンスオブジェクトから、ユーザーを一意に識別するUserId
を抽出できます。PurchaseResponse
オブジェクトにはReceiptId
が含まれています。これをUserId
と共に使用して、サーバー側で購入のアウトオブバンド検証を実行します。アプリサーバーから送信するリクエストには、共有シークレットを渡す必要があります。これによって身元確認が行われ、セキュリティが確保されます。
リクエストの形式は次のとおりです。
<Protocol>//<Server>[/<sandbox>]/version/<Operation_version_number>/verifyReceiptId/developer/<Shared_Secret>/user/<UserId>/receiptId/<ReceiptId>
山かっこで囲まれた用語はリクエストパラメーターです。以下を参考に、検証対象のトランザクションに応じた値に置き換えてください。
- Protocol: サーバーまたはRVS Sandboxとの通信に使用するプロトコル(httpsなど)。
- Server: 通信相手となるRVSサーバーのURL。
- RVS Cloud SandboxサーバーとRVS本番サーバーはどちらも「appstore-sdk.amazon.com」というURLを使用します。
- sandbox: RVS Cloud Sandboxサーバーを使用している場合は、「sandbox」という値を使用します。RVS本番サーバーを使用している場合は、このパラメーターを省略します。
- Operation_version_number:
verifyReceiptId
オペレーションのバージョン番号。このバージョン番号は、IAPのバージョン番号とは関係ありません。現在のverifyReceiptId
バージョン番号は「1.0」です。 - Shared_secret: リクエストを発行した開発者を識別するための共有シークレット。共有シークレットは、Amazonアプリストアの開発者アカウントの [共有キー] ページ(https://developer.amazon.com/sdk/shared-key.html)で確認できます。RVSSandboxの場合は、空でない任意の文字列を共有シークレットとして使用できます。
- UserId: Amazonアプリストアで公開したアプリを使用する個々のAmazonユーザーを表すID (
PurchaseResponse.getUserData().getUserId()
)。 - ReceiptId: 購入を一意に識別するID (
PurchaseResponse.getReceipt().getReceiptId()
またはPurchaseUpdatesResponse.getReceipts()
→Receipt.getReceiptId()
)。
RVSレスポンスの構文
RVSは、RESTfulなJSON APIインターフェイスを提供します。ベストプラクティスとして、RVSサーバーから返されたJSONレスポンスを読み取るには、JSONパーサークラスを使用することをお勧めします。
トランザクションの検証をリクエストすると、RVSサーバーまたはRVS Sandboxから、リクエストが成功したかどうかを示すレスポンスコードが返されます。成功した場合、JSONレスポンスにはトランザクションに関する情報が含まれています。
以下は、リクエストに成功した場合のレスポンスの例です。
{
"autoRenewing":false,
"betaProduct":false,
"cancelDate":null,
"cancelReason":null,
"freeTrialEndDate":null,
"gracePeriodEndDate":null,
"parentProductId":null,
"productId":"com.amazon.iapsamplev2.gold_medal",
"productType":"CONSUMABLE",
"promotions":null,
"purchaseDate":1399070221749,
"purchaseMetadataMap":null,
"quantity":1,
"receiptId":"wE1EG1gsEZI9q9UnI5YoZ2OxeoVKPdR5bvPMqyKQq5Y=:1:11",
"renewalDate":null,
"term":null,
"termSku":null,
"testTransaction":true
}
RVSのレスポンスコード
レシート検証サービスは、応答として次のいずれかのコードを返します。各コードは、検証チェックの結果を示しています。
レスポンスコード | 説明 |
---|---|
HTTP 200 | 成功しました。 レシートID、ユーザーID、共有シークレットがすべて有効です。商品タイプは、 「ENTITLED」(非消費型アイテム)、「CONSUMABLE」(消費型アイテム)、「SUBSCRIPTION」(定期購入型アイテム)のいずれかです。 |
HTTP 400 | このreceiptId で表されるトランザクションが無効です。または、このreceiptId に対応するトランザクションが見つかりませんでした。 |
HTTP 410 | このreceiptId で表されるトランザクションが無効になりました。キャンセルされたレシートとして処理されます。 |
HTTP 429 | リクエストがスロットリングされました。呼び出しの頻度を減らして、しばらくしてから再試行してください。 |
HTTP 496 | sharedSecret が無効です。 |
HTTP 497 | ユーザーIDが無効です。 |
HTTP 500 | 内部サーバーエラーが発生しました。 |
成功したトランザクションのRVSレスポンスフィールド
次の表は、成功したトランザクションのRVSレスポンスに含まれるフィールドとその説明をまとめたものです。
フィールド | データ型 | 説明 |
---|---|---|
autoRenewing |
ブール型 | ユーザーの定期購入が自動更新されるかどうかを示します。 |
betaProduct |
ブール型 | 購入商品がライブアプリテスト商品かどうかを示します。 |
cancelDate |
長整数 | 購入をキャンセルした日、または定期購入の期限が切れた日。購入がキャンセルされていない場合、このフィールドはnullになります。時間はミリ秒単位です。 |
cancelReason |
整数 | 商品がキャンセルされた理由を示します。指定できる値は、null、0、1、2です。各整数はキャンセル理由を表します。 null - 購入がキャンセルされていない。0 - 現時点ではキャンセル理由が特定されていないため、後で表示される。1 - ユーザーが注文をキャンセルした。2 - 購入がAmazonのシステムによってキャンセルされた(定期購入型アイテム購入時のユーザーの支払いが無効で、その購入が猶予期間内に完了しなかった場合など)。このコードは、Amazonカスタマーサポートがユーザーのリクエストに応じて注文をキャンセルした場合にも返されます。 |
freeTrialEndDate |
長整数 | 定期購入が無料トライアル期間中であることを示します。定期購入の無料トライアル期間の終了日をエポック(ミリ秒)単位で提供します。定期購入が無料トライアル期間中でない場合、このフィールドはnullになります。 |
gracePeriodEndDate |
長整数 | 定期購入が猶予期間中であることを示します。定期購入の猶予期間の終了日をエポック(ミリ秒)単位で提供します。定期購入が猶予期間中でない場合、このフィールドはnullになります。 |
parentProductId |
文字列 | null。将来使用するために予約されています。 |
productId |
文字列 | アプリ内でこのアイテムに対して定義したSKU。 |
productType |
文字列 | 購入された商品の種類。有効な商品タイプは、CONSUMABLE(消費型アイテム)、SUBSCRIPTION(定期購入型アイテム)、ENTITLED(非消費型アイテム)です。 |
promotions |
リスト<Promotion> | 定期購入型アイテムのプロモーション価格の詳細です。プロモーションがない場合はnullになります。詳細については、RVSのプロモーション価格を参照してください。 |
purchaseDate |
長整数 | 購入日。エポックからのミリ秒数として格納されます。定期購入型アイテムの場合、purchaseDate は最初の購入日を表します。それ以降の更新日を表すものではありません。 |
purchaseMetadataMap |
マップ | 将来使用するために予約されています。常にnullになります。本番環境でのみ返されます。 |
quantity |
整数 | 購入された数量。常にnullまたは1になります。 |
receiptId |
文字列 | 購入の一意の識別子。 |
renewalDate |
長整数 | 定期購入型アイテムの更新が必要となる日付。エポックからのミリ秒で計算されます。 |
term |
文字列 | 定期購入型IAPアイテムの有効期間(期間は購入日から始まります)。数字と期間(日、週、月、年)で構成されます(「1週間」、「2か月」など)。 |
termSku |
文字列 | 定期購入期間に対応する一意のSKU。 |
testTransaction |
ブール型 | この購入が、Amazonによる公開・テストプロセスの一部として実行されたものかどうかを示します。 |
RVSのプロモーション価格
プロモーション価格を設定する方法の詳細については、プロモーション価格の設定を参照してください。ユーザーが定期購入型アイテムをプロモーション価格で購入した場合、RVSから返されるレシートにはプロモーションの詳細が含まれます。前のセクションで説明したJSONレスポンスには、promotions
フィールドが含まれています。このセクションでは、このpromotions
フィールドについて詳しく説明します。プロモーションの詳細は、ユーザーが定期購入型アイテムをプロモーション価格で購入したレシートにのみ表示されます。
レシートに関連付けられたプロモーションがない場合、promotions
フィールドはnullになります。プロモーションが関連付けられている場合は、このフィールドにPromotion
オブジェクトのリストが含まれ、次のフィールドも表示されます。
フィールド | データ型 | 説明 |
---|---|---|
promotionType |
文字列 | プロモーションのタイプ。有効な値は Introductory Price とPromotional Price です。有効な値の説明を参照してください。 |
promotionStatus |
文字列 | このユーザーのプロモーションのステータス。有効な値は Queued 、InProgress 、Completed です。有効な値の説明を参照してください。 |
例:
"promotions": [
{
"promotionType":"Introductory Price - All customers",
"promotionStatus":"Completed"
}
]
有効な値の説明
promotionType
フィールドで有効な値は次のとおりです。
Introductory Price - All customers
- すべてのユーザー(新規ユーザーおよび休眠ユーザーを含む)に提供される価格。Promotional Price - Lapsed customers
- 休眠ユーザーにのみ提供される価格。
promotionStatus
フィールドで有効な値は次のとおりです。
Queued
- ユーザーが定期購入型アイテムをプロモーション価格で購入しました。現在は無料トライアル期間であり、まだプロモーション期間は始まっていません。InProgress
- ユーザーは現在、プロモーション価格の期間中です。Completed
- ユーザーのプロモーション期間が終了しました。
プロモーション価格に関するよくある質問(FAQ)
- Q: ユーザーの定期購入型アイテムのレシートには必ずプロモーションの詳細が表示されているのですか?
- いいえ。プロモーションの詳細情報は、定期購入型アイテムをプロモーション価格で購入したレシートにのみ表示されます。
- Q: プロモーションの詳細は、レシートがキャンセルされた後も表示されますか?
- はい。ユーザーの定期購入がキャンセルされた場合は、プロモーションの詳細が
Completed
と表示されます。 - Q: ユーザーが無料トライアル中に定期購入型アイテムをキャンセルし、プロモーションプランを更新しなかった場合、プロモーションのステータスはどうなりますか?
- ユーザーのプロモーション期間が開始しなかったため、レシートには関連付けられているプロモーションの詳細がありません。
キャンセル日と更新日
renewalDate
フィールドには、自動更新される定期購入型アイテムの購入が次に更新される日付が格納されます。このフィールドは、定期購入型アイテムの購入にのみ適用されます。ユーザーが月額制の定期購入型アイテムを所有している場合、その定期購入型アイテムは、初回購入日と同じ日付で毎月更新されます。翌月に同じ日付がない場合は、最も近い前の日付が更新日となります。次に例を示します。
- ユーザーが1月2日に定期購入型アイテムを購入した場合、次の3か月間の更新日は、2月2日、3月2日、4月2日になります。
- ユーザーが1月31日に定期購入型アイテムを購入した場合、次の3か月の更新日は、2月28日(うるう年の場合は2月29日)、3月31日、4月30日になります。
cancelDate
フィールドには、定期購入型アイテムの購入が期限切れになった日付、またはAmazonカスタマーサービスが購入をキャンセルした日付が格納されます。キャンセル日は、ユーザーがコンテンツにアクセスできなくなった日付を表します。ユーザーが自動更新をオフにして定期購入をキャンセルした場合は、次の更新予定日がキャンセル日となります。
renewalDate
フィールドとcancelDate
フィールドは、ミリ秒単位の時間として格納されます。この値を日付オブジェクトに変換するには、java.util.Date(timeInMillis)
を使用します。
消費型アイテムまたは非消費型アイテムの購入
有効なレシートでは、キャンセル日と更新日はどちらもnull値になります。キャンセル日フィールドがnullでない場合、その値は、Amazonカスタマーサービスが購入をキャンセルした日付を表します。
定期購入型アイテムの購入
有効な定期購入型アイテムのレシートでは、キャンセル日はnullになります。cancelDate
フィールドがnullでない場合、その値は、定期購入型アイテムが期限切れになった日付、またはAmazonカスタマーサービスが購入をキャンセルした日付を表します。
renewalDate
フィールドには、自動更新される定期購入型アイテムの購入が次に更新される日付が格納されます。自動更新が設定されていない定期購入型アイテムでは、このフィールド値はnullになります。
例として、ユーザーがキャンセルした定期購入型アイテムがあるとします。
- この定期購入型アイテムは、2016年1月1日から2016年3月1日までアクティブでした。レシートでは、この定期購入型アイテムのpurchaseDateは2016年1月1日に設定され、cancelDateは2016年3月1日に設定されます。
- この定期購入型アイテムが2016年4月1日に再びアクティブにされた場合、2つ目のレシートが生成されます。2つ目のレシートでは、purchaseDateは2016年4月1日、cancelDateはnullとなります。
RVS SandboxとRVS本番環境の例
レシート検証サービス(RVS)の例を参照してください。
Last updated: 2023年3月13日