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 |
返回数据的粒度: DAILY或HOURLY |
字符串 | 是 |
timelineSpec.startTime |
查询时段的下限,以UTC表示的日历日期:{年、月、日} |
对象 | 是 |
timelineSpec.endTime |
查询时段的上限,以UTC表示的日历日期:{年、月、日}。必须大于startTime。 |
对象 | 是 |
metrics[] |
要从指标集返回的指标名称的子集(例如,crashRate、crashCount)。省略以返回集合上定义的所有指标。 |
数组 | 否 |
dimensions[] |
用于对结果进行分组的维度(例如,versionCode、countryCode) |
数组 | 否 |
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[],就会返回所有指标,导致查询速度变慢。 |
相关主题
- Vitals API概述: 可用指标、维度和常见问题解答
- “应用运行状况洞察”控制面板: 相同指标的可视化仪表板
- 报告API浏览器: 开发者门户上的交互式API浏览器
Last updated: 2026年6月29日

