as

Settings
Sign out
Notifications
Alexa
Amazonアプリストア
Ring
AWS
ドキュメント
Support
Contact Us
My Cases
デバイス
ビルド
テスト
公開
関連情報
ドキュメント

Vitals APIリファレンス

Vitals APIリファレンス

このガイドには、Vitals APIの統合に役立つリファレンス情報が含まれています。

Vitals APIの使用にあたっては、Program Materials License Agreementが適用されます。

前提条件

API呼び出しを行う前に、次の要件を満たしていることを確認してください。

要件 詳細
Amazon開発者アカウント 管理者レベルの認証情報が必要
セキュリティプロファイル 開発者コンソール > [設定] > [APIアクセス] で作成
APIにマッピングされたセキュリティプロファイル プロファイルをReporting APIに関連付け
クライアントIDとクライアントシークレット セキュリティプロファイルの [ウェブ設定] タブから
LWAスコープ adx_reporting::appstore:marketer
パッケージ名 アプリのパッケージ名(例:com.example.myapp)は開発者のベンダーアカウントが所有している必要があります
Python 3.6以上とrequestsライブラリ  

ベースURL

Vitals APIのベースURLはhttps://developer.amazon.com/api/appstoreです。

操作

VitalsAPIには、以下の操作とエンドポイントが含まれています。

操作 メソッド エンドポイント 説明
最新状況の確認 GET /vitals/apps/{パッケージ名}/{指標セット名} 最新の利用可能なデータのタイムスタンプ
指標の照会 POST /vitals/apps/{パッケージ名}/{指標セット名}:query ディメンション/フィルター付きの時系列指標

リクエスト

パラメーターと検証規則の詳細については、次のセクションを参照してください。

リクエストパラメーター

すべてのクエリリクエストには、次のパラメーターを含める必要があります。

パラメーター 説明 必須
timelineSpec.aggregationPeriod 返されるデータの詳細度です。 DAILYまたはHOURLYを指定できます。 文字列 はい
timelineSpec.startTime クエリの対象期間の開始日を、UTCでの日付として{年, 月, 日}の形式で指定します。 オブジェクト はい
timelineSpec.endTime クエリの対象期間の開始日を、UTCでの日付として{year, month, day}の形式で指定します。startTimeより後の日付にする必要があります。 オブジェクト はい
metrics[] 指標セットから返す指標名のサブセットを指定します(crashRatecrashCountなど)。省略すると、セットで定義されているすべての指標が返されます。 配列 いいえ
dimensions[] 結果をグループ化するディメンションを指定します(versionCodecountryCodeなど)。 配列 いいえ
filter フィルター条件を表すJSONオブジェクトです。各キーはディメンションを示し、その値には許容する値のリストを指定します(フィールド内はOR、フィールド間はANDとして処理されます)。たとえば、{"countryCode": ["US","CA"], "deviceType": ["AMAZON_FIRE_TV"]}のようになります。 文字列 いいえ
pageSize 1ページあたりの最大行数です。デフォルトは 1,000です。最大値: 100,000です。 整数 いいえ
pageToken 前回のレスポンスのnextPageTokenとして返された不透明なカーソルです。初回のリクエストでは省略します。 文字列 いいえ
reportType issuesMetricSetの場合にのみエラータイプを指定します。CRASHかANRのいずれかです。発生率指標セットには適用されません。 文字列 いいえ

レスポンス

レスポンスフィールドの詳細については、以下のセクションを参照してください。

レスポンスフィールド

フィールド 常に存在する 説明
status はい HTTPステータスコード(200)
requestId はい デバッグ用のUUID、サポートチケットに含める
freshness はい クエリ対象期間の最新データのタイムスタンプ
resultCount はい このページの行数
rows[] はい 一致するデータがない場合は空になることがあります
nextPageToken さらにページがある場合のみ 次のページを取得するには、次のリクエストに渡します

成功時のレスポンス(200)

{
  "status": 200,
  "requestId": "8a3f2c71-e4b9-4012-a8c1-9d5e7f3b2a10",
  "freshness": {
    "aggregationPeriod": "DAILY",
    "latestDataTimestamp": "2026-04-25T00:00:00Z"
  },
  "resultCount": 3,
  "rows": [
    {
      "startTime": {"year": 2026, "month": 4, "day": 25},
      "aggregationPeriod": "DAILY",
      "dimensions": [
        {"name": "versionCode", "value": "151"},
        {"name": "countryCode", "value": "US"}
      ],
      "metrics": [
        {"name": "crashRate", "value": "0.0142"},
        {"name": "distinctDevices", "value": "54320"}
      ]
    }
  ],
  "nextPageToken": "MjAyNi0wNC0yNXwxNA=="
}

実装例

Vitals APIを介して行うさまざまなタスクで使用するPythonコードについて、以下に例を示します。

アクセストークンの取得

クライアントIDとクライアントシークレットを使用して認可トークンを取得し、各APIリクエストのヘッダーに追加する必要があります。以下の例では、認可トークンを取得し、このトークンを利用してAuthorizationヘッダーを作成する方法を紹介します。

# 指定する必要がある値
client_id = "<クライアントID>"
client_secret = "<クライアントシークレット>"
package_name = "<アプリのパッケージ名>"

BASE_URL = "https://developer.amazon.com/api/appstore"

scope = "adx_reporting::appstore:marketer"
data = {
    "grant_type": "client_credentials",
    "client_id": client_id,
    "client_secret": client_secret,
    "scope": scope
}
auth_response = requests.post("https://api.amazon.com/auth/o2/token", data=data)
auth_token = auth_response.json()["access_token"]

headers = {
    "Authorization": f"Bearer {auth_token}",
    "Content-Type": "application/json"
}

データの最新状況の確認

次の例は、クエリを実行する前に、利用可能な最新データのタイムスタンプを確認する方法を示しています。

freshness_url = f"{BASE_URL}/vitals/apps/{package_name}/crashMetricSet"
freshness_response = requests.get(freshness_url, headers=headers)
freshness = freshness_response.json()

for info in freshness["freshnessInfo"]:
    print(f"{info['aggregationPeriod']}: {info['latestDataTimestamp']}")

最新状況取得のレスポンスの例

{
    "name": "crashMetricSet",
    "metrics": ["crashRate", "crashRate7dUserWeighted", "crashRate28dUserWeighted", "userPerceivedCrashRate", "userPerceivedCrashRate7dUserWeighted", "userPerceivedCrashRate28dUserWeighted",
"distinctDevices", "crashCount"],
    "dimensions": ["versionCode", "countryCode", "deviceModel", "deviceType", "deviceOS", "osVersion"],
    "freshnessInfo": [
        {"aggregationPeriod": "DAILY", "latestDataTimestamp": "2026-04-25"},
        {"aggregationPeriod": "HOURLY", "latestDataTimestamp": "2026-04-25T14"}
    ]
}

ローカル時刻をUTCに変換する方法

次の例は、ローカル時刻のdatetimeをUTCに変換する方法を示しています。

from datetime import datetime, timezone, timedelta


def utc_date_components(local_dt=None):
    """API向けに、datetimeをUTCのyear/month/dayに変換します。

    タイムゾーン情報のないlocal_dtは、システムのローカル時刻として解釈されます。
    あいまいさを避けるには、タイムゾーン付きのdatetimeを渡してください。
    """
    if local_dt is None:
        utc_dt = datetime.now(timezone.utc)
    else:
        if local_dt.tzinfo is None:
            local_dt = local_dt.astimezone()  # システムのローカルタイムゾーンを明示的に適用
        utc_dt = local_dt.astimezone(timezone.utc)
    return {"year": utc_dt.year, "month": utc_dt.month, "day": utc_dt.day}


# 例:UTCでの「昨日」(ローカルタイムゾーンとは無関係)
yesterday_utc = datetime.now(timezone.utc) - timedelta(days=1)
start = utc_date_components(yesterday_utc)

指標の照会

次の例は、発生率指標セット(クラッシュ、ANR、LMK)に対するクエリの完全な構造を示しています。コメントで、フィールドが必須であるか、省略可能であるかを示しています。

metric_set = "crashMetricSet"   # or "anrMetricSet", "lmkMetricSet"
query_url = f"{BASE_URL}/vitals/apps/{package_name}/{metric_set}:query"

body = {
    # 必須:時間範囲と詳細度
    "timelineSpec": {
        "aggregationPeriod": "DAILY", # DAILYまたはHOURLY
        "startTime": {"year": 2026, "month": 4, "day": 01},
        "endTime":   {"year": 2026, "month": 4, "day": 01},
    },

    # 省略可能:クエリ対象の指標セット内の指標
    "metrics": ["crashRate", "crashCount", "distinctDevices"],

    # 省略可能:ディメンション別の内訳(最大5つ)
    "dimensions": ["versionCode", "countryCode"],

    # 省略可能: AIP-160仕様のフィルター式
    "filter": {"countryCode": ["US", "CA"], "deviceType": ["AMAZON_FIRE_TV"]},

    # 省略可能:ページ分割(デフォルトは1000、最大100000)
    "pageSize": 1000,
    "pageToken": "<前回のレスポンスから取得>",
}

response = requests.post(query_url, headers=headers, json=body)
result = response.json()

結果のページ分割

次の例は、レスポンスにnextPageTokenが含まれている場合に、すべての結果を取得する方法を示しています。

all_rows = []
body.pop("pageToken", None)
while True:
    result = requests.post(query_url, headers=headers, json=body).json()
    all_rows.extend(result["rows"])
    token = result.get("nextPageToken")
    if not token:
        break
    body["pageToken"] = token

上位のクラッシュ問題のクエリ

issuesMetricSetは、頻度順にランク付けされた上位のクラッシュ/ANR/LMKの問題を返します。発生率指標セットとは異なり、時間範囲全体にわたって集計され、スタックトレースと共に一意のクラッシュシグニチャごとに1行が返されます。reportTypeには、共有スタックトレースのタイプとしてCRASHまたはANRを指定します。

issues_url = f"{BASE_URL}/vitals/apps/{package_name}/issuesMetricSet:query"
body = {
  "startTime": { "year": 2025, "month": 6, "day": 1 },
  "endTime": { "year": 2025, "month": 6, "day": 15 },
  "reportType": "CRASH",
  "dimensions": ["deviceType", "osVersion"],
  "filter": { "countryCode": ["US", "CA"] },
  "pageSize": 25,
  "pageToken": null
}
response = requests.post(issues_url, headers=headers, json=body)
result = response.json()

# レスポンス構造(発生率指標セットとは異なります):
# {
#   "rows": [
#     {
#       "crashDescriptor": "67f35eb2...",
#       "reportText": "java.lang.IllegalStateException: ...",
#       "metrics": [
#         {"name": "errorEventCount", "value": "78"},
#         {"name": "affectedDeviceCount", "value": "45"}
#       ]
#     }
#   ],
#   "nextPageToken": "..."
# }

エラー処理

エラーの処理方法については、次のセクションを参照してください。

エラーレスポンス形式

すべてのエラーは構造化されたJSONを返します。

{
  "code": "INVALID_ARGUMENT",
  "message": 「不明な指標'bogus'です。crashMetricSetの有効な指標:crashRate, crashRate7dUserWeighted, ...",
  "status": 400
}

エラーコード

HTTPステータス コード 原因 対処法
400 INVALID_ARGUMENT リクエストパラメーターが正しくありません(指標、ディメンション、日付範囲が無効です) リクエストを修正してください。再試行しないでください
403 UNAUTHORIZED トークンが期限切れまたは無効です トークンを更新して再試行します
404 NOT_FOUND 指標セット名が不明です 指標セット名のスペルをチェックします
429 RATE_LIMITED 3リクエスト/秒の制限を超えました 待機時間を指数的に伸ばしながら再試行します
500 INTERNAL サーバーエラー 待機時間を伸ばしながら再試行します(最大3回)

よくある誤りと修正

誤り 表示されるエラー 修正
timelineSpecが見つからない "timelineSpec is required" 必要なtimelineSpecオブジェクトを追加します
28d指標でHOURLYを使用 "crashRate28dUserWeighted not available for HOURLY" DAILYに切り替えるか、28d指標を削除します
日付範囲が広すぎる(時間単位の場合) "HOURLY queries limited to 15 days" 15日以内に絞り込む
トークンの期限切れ 403 Forbidden LWAトークンを更新します
リクエストが多すぎる 429 Too Many Requests 呼び出しの間にtime.sleep()を追加します

再試行とベストプラクティス

再試行の戦略とベストプラクティスについては、次のセクションを参照してください。

再試行戦略の例

import time

MAX_RETRIES = 3
RETRIABLE_CODES = {429, 500, 502, 503}

def query_with_retry(client, package, metric_set, body):
    for attempt in range(MAX_RETRIES):
        resp = client.query(package, metric_set, body)

        if resp.status_code == 200:
            return resp.json()

        if resp.status_code not in RETRIABLE_CODES:
            break  # 再試行不可のエラー

        wait = (2 ** attempt) + 0.5  # 1.5秒、2.5秒、4.5秒
        print(f"Retry {attempt + 1}/{MAX_RETRIES} after {wait}s (HTTP {resp.status_code})")
        time.sleep(wait)

    # 最後の試行は失敗しました
    error = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
    raise RuntimeError(f"Failed after {MAX_RETRIES} retries: {resp.status_code} {error.get('message', '')}")

本番環境でのベストプラクティス

ベストプラクティス 推奨される方法
トークンのキャッシング トークンをキャッシュに保存し、有効期限が切れる5分前に更新します。API呼び出しごとに新しいトークンをリクエストしないでください。
最初に鮮度を確認する 結果が空にならないように、クエリを実行する前に必ず鮮度エンドポイントを呼び出します。
ページ分割を使用する デフォルトのpageSizeは1000です。ディメンションによる内訳が多い場合は、タイムアウトを避けるためにページ分割を行います。
リクエスト頻度の制限 リクエストは1秒あたり3回未満にします。連続した呼び出しの間にtime.sleep(0.4)を追加します。
再試行可能なエラーについてのみ再試行する エラーが429、500、502、503の場合、再試行します。400の場合は再試行しないでください(代わりにリクエストを修正してください)。
requestIdをログに記録する すべてのレスポンスにはrequestIdが含まれています。デバッグやサポートチケット用に、これをログに記録します。
空の結果を処理する rows: []を返すクエリはエラーではありません。これは、その日付範囲のデータがないことを意味します。
オーバーフェッチを回避する 必要な指標のみをリクエストします。metrics[]を省略すると、すべてが返されますが、速度は遅くなります。

Last updated: 2026年6月29日