as

Settings
Sign out
Notifications
Alexa
亚马逊应用商店
Ring
AWS
文档
Support
Contact Us
My Cases
设备
构建
测试
应用发布
相关资源
文档

Vitals API参考

Vitals API参考

本指南包含参考信息,供您在集成Vitals API时参考。

Vitals API的使用受程序材料许可协议的约束。

先决条件

进行API调用之前,请确保满足以下要求:

要求 详情
亚马逊开发者账户 需要管理员级别的凭证
安全配置文件 通过开发者控制台 >“我的设置”>“API访问”创建
映射到API的安全配置文件 将配置文件附加到报告API
客户端ID和客户端密钥 从安全配置文件的“Web设置”选项卡中
LWA范围 adx_reporting::appstore:marketer
程序包名称 您应用的程序包名称(例如com.example.myapp)所有者必须是您的供应商账户
Python 3.6+,包含requests  

基本URL

Vitals API的基本URL是https://developer.amazon.com/api/appstore

操作

Vitals API包含了以下操作和终结点:

操作 方法 终结点 描述
检查新鲜度 GET /vitals/apps/{程序包名称}/{指标集名称} 最新可用数据时间戳
查询指标 POST /vitals/apps/{程序包名称}/{指标集名称}:query 包含维度/筛选条件的时序指标

请求

有关参数和验证规则的详细信息,请参阅以下几节。

请求参数

每个查询请求都必须包含以下参数:

参数 描述 类型 是否必需
timelineSpec.aggregationPeriod 返回数据的粒度: DAILYHOURLY 字符串
timelineSpec.startTime 查询时段的下限,以UTC表示的日历日期:{年、月、日} 对象
timelineSpec.endTime 查询时段的上限,以UTC表示的日历日期:{年、月、日}。必须大于startTime。 对象
metrics[] 要从指标集返回的指标名称的子集(例如,crashRatecrashCount)。省略以返回集合上定义的所有指标。 ​数组
dimensions[] 用于对结果进行分组的维度(例如,versionCodecountryCode ​数组
filter JSON对象形式的筛选条件。每个键都是一个维度;其值是允许值的列表(字段内为OR,跨字段为AND)。例如,{"countryCode": ["US","CA"], "deviceType": ["AMAZON_FIRE_TV"]} 字符串
pageSize 每页的最大行数。默认值: 1000。最大数目: 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):
    """将日期时间转换为UTC的年/月/日格式,以供API使用。

    不带时区信息的local_dt会被解释为系统本地时间。
    请提供tz-aware,以免系统误判。
    """
    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", # 按日/按小时
        "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问题(按频率排序)。和发生率指标集不同,它会对整个时间范围进行汇总,并通过堆栈跟踪针对每个唯一崩溃签名返回一行。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": "Unknown metric 'bogus'.Valid metrics for crashMetricSet: crashRate, crashRate7dUserWeighted, ...",
  "status": 400
}

错误代码

HTTP状态 代码 原因 操作
400 INVALID_ARGUMENT 请求参数错误(指标、维度、日期范围无效) 修复请求;不要重试
403 UNAUTHORIZED 令牌过期或无效 刷新令牌,然后重试
404 NOT_FOUND 未知的指标集名称 检查metricSetName的拼写
429 RATE_LIMITED 超过每秒3次请求 回退,然后以指数级延迟重试
500 INTERNAL 服务器错误 使用回退功能重试(最多3次)

常见错误和修复

错误 您会看到的错误 修复
缺少timelineSpec "timelineSpec is required" 添加必需的timelineSpec对象
HOURLY(按小时)与28日指标一起使用 "crashRate28dUserWeighted not available for HOURLY" 切换为DAILY(按日)或移除28日指标
日期范围太宽(按小时) "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  # Non-retriable error

        wait = (2 ** attempt) + 0.5  # 1.5s, 2.5s, 4.5s
        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调用都请求新令牌。
先检查新鲜度 在查询之前,请务必调用freshness终结点,以避免结果为空。
使用分页 默认pageSize为1000。对于较大的维度细分,请进行分页以避免超时。
速率限制 保持在每秒3个请求以下。在连续调用之间添加time.sleep(0.4)
仅重试可重试的错误 重试429、500、502、503。切勿重试400(改为修复请求)。
日志requestId 每个响应都包含requestId。进行调试和工单支持时,请登录该ID。
处理空结果 返回rows: [] 的查询不是错误。这表示该日期范围内没有数据。
避免过度获取 仅请求所需的指标。如果metrics[],就会返回所有指标,导致查询速度变慢。

Last updated: 2026年6月29日