as

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

Vitals API V2参考

Vitals API V2参考

本页面提供集成VitalsAPI V2所需的参考信息。有关指标集、指标和维度,请参阅Vitals API V2概述。

亚马逊将继续支持Vitals API的版本1 (V1)。使用V2进行新的集成。将现有集成迁移到V2。有关V1,请参阅Vitals API参考。有关必须进行的更改,请参阅从V1迁移。

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

先决条件

在发送请求之前,请确保您有以下各项:

要求 详情
亚马逊开发者账户 管理员级别的凭证
安全配置文件 在开发者控制台的“我的设置”>“API访问”中创建安全配置文件。
关联到报告API的安全配置文件 将安全配置文件附加到报告API。
客户端ID和客户端密钥 从安全配置文件的“Web设置”选项卡获取这些值。
LWA范围 adx_reporting::appstore:marketer
程序包名称 应用的程序包名称,例如com.example.myapp。您的开发者账户必须拥有该应用。

本页上的代码示例使用Python 3.8或更高版本以及requests库。

基本URL

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

操作

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

操作 方法 终结点 描述
检查新鲜度 GET /v2/applications/{程序包名称}/vitals/{指标集名称} 返回指标集的元数据和新鲜度
查询指标 POST /v2/applications/{程序包名称}/vitals/{指标集名称}:query 返回每个时段的指标,包括维度和筛选条件
查询问题 POST /v2/applications/{程序包名称}/vitals/issuesMetricSet:query 返回高频崩溃问题或ANR问题

终结点使用以下路径参数:

参数 描述
packageName 应用的程序包名称,例如com.example.myapp
metricSetName 指标集的名称,但issuesMetricSet除外。有关列表,请参阅可用指标集。
  • issuesMetricSet仅支持查询问题。针对它的检查新鲜度请求返回404 RESOURCE_NOT_FOUND。
  • 查询指标和查询问题路径必须以:query结尾。

请求标头

标头 必需 值​
Authorization 是 Bearer ACCESS_TOKEN。ACCESS_TOKEN是来自Login with Amazon的access_token值。
Content-Type 是,对于POST application/json
Accept 否 application/json.该API仅发送JSON。

请求规则

本节中的规则适用于查询指标操作和查询问题操作。

时间值

对于startTime和endTime,使用格式为YYYY-MM-DDThh:mm:ssZ的UTC时间戳。

时间值遵循以下规则:

  • 时间范围包含startTime和endTime的时段。endTime必须与startTime相同或更晚。
  • 对于DAILY,API使用UTC日期。对于HOURLY,API会忽略分钟和秒。例如,2026-08-18T14:35:00Z选择从2026-08-18T14:00:00Z开始的UTC时段。
  • 对于DAILY,startTime必须在最近30个UTC日期之内,或者对于HOURLY,必须在最近15个UTC日期之内。API会根据新鲜度值计算这些日期。新鲜度值的日期是其中的第一个。
  • endTime的UTC日期 (DAILY) 或UTC小时 (HOURLY) 不得晚于新鲜度值。
  • 对于违反这些规则的时间范围,API会发送400 VALIDATION_ERROR,并在破坏规则的字段(timelineSpec.startTime或timelineSpec.endTime)上显示FIELD_OUT_OF_RANGE。
  • 如果没有可用的新鲜度值,查询将不返回任何行。

API拒绝这些时间值:

  • 没有时间的日期,例如2026-08-18
  • 带有秒的小数部分的时间,例如2026-08-18T00:00:00.000Z
  • 带有时区偏移的时间,例如2026-08-18T00:00:00+00:00
  • 以小写字母z结尾的时间

维度和筛选条件

  • 筛选键必须命名指标集的维度。它不需要出现在dimensions中。
  • 使用非空区分大小写的字符串作为筛选值。countryCode值必须是大写的ISO3166-1alpha-2代码,例如US。API匹配每个键的任意值并要求每个键都匹配。空数组没有效果。
  • 细分会省略缺少任何所请求维度值的数据。

分页

要获取下一页,请将nextPageToken作为pageToken发送。除pageToken以及pageSize(如果需要)外保持请求不变。重复直到nextPageToken为null。省略pageToken以开始新查询。

检查新鲜度

检查新鲜度操作返回指标集的元数据及其数据的新鲜度。该请求没有正文。

检查新鲜度响应字段

字段 类型 始终存在 说明
name 字符串 是 指标集的名称
description 字符串 是 指标集的描述
metrics[] 字符串数组 是 指标集的所有指标适用于所有汇总时段。某些指标仅支持DAILY。顺序不固定。
dimensions[] 字符串数组 是 指标集的维度。顺序不固定。
freshnessInfo[] 对象数组 是 具有新鲜度值的每个汇总时段有一个条目。该数组可以包含零个、一个或两个条目。
freshnessInfo[].aggregationPeriod 字符串 是 DAILY或HOURLY
freshnessInfo[].latestDataTimestamp 字符串 是 最新处理的天 (DAILY) 或小时 (HOURLY) 的UTC开始时间,格式为YYYY-MM-DDThh:mm:ssZ

检查新鲜度请求示例

GET /api/appstore/v2/applications/com.example.myapp/vitals/crashMetricSet HTTP/1.1
Host: developer.amazon.com
Authorization: Bearer ACCESS_TOKEN

检查新鲜度响应示例

{
  "name": "crashMetricSet",
  "description": "应用崩溃指标",
  "metrics": [
    "crashRate",
    "crashRate7dUserWeighted",
    "crashRate28dUserWeighted",
    "userPerceivedCrashRate",
    "userPerceivedCrashRate7dUserWeighted",
    "userPerceivedCrashRate28dUserWeighted",
    "distinctDevices",
    "crashCount"
  ],
  "dimensions": [
    "versionCode",
    "countryCode",
    "deviceModel",
    "deviceType",
    "deviceOs",
    "osVersion"
  ],
  "freshnessInfo": [
    {"aggregationPeriod": "HOURLY", "latestDataTimestamp": "2026-08-18T14:00:00Z"},
    {"aggregationPeriod": "DAILY", "latestDataTimestamp": "2026-08-18T00:00:00Z"}
  ]
}

查询指标

查询指标操作返回时间范围内具有数据的每个时段的一个指标集的指标。

查询指标请求参数

参数 描述 类型 必需
timelineSpec 汇总时段和时间范围。有关规则,请参阅时间值。 对象 是
timelineSpec.aggregationPeriod DAILY或HOURLY 字符串 是
timelineSpec.startTime 时间范围的开始,格式为YYYY-MM-DDThh:mm:ssZ 字符串 是
timelineSpec.endTime 时间范围的结束,格式相同。该值必须与startTime相同或更晚。 字符串 是
metrics[] 要返回的指标。如果不包含metrics,则API会返回指标集中支持该汇总时段的所有指标。 字符串数组 否
dimensions[] 细分的维度。对于slowStartRateMetricSet,dimensions必须包含startType。 字符串数组 否
filter 要包含的维度值。每个键都是一个维度名称,每个值都是一个字符串数组。有关规则,请参阅维度和筛选条件。 对象 否
pageSize 一页中的最大行数。默认值为1,000。值为0时使用默认值。值超过100,000时使用100,000。 整数 否
pageToken 上一响应中的nextPageToken值。不要在第一个请求中包含pageToken。 字符串 否

查询指标请求示例

查询指标和查询问题请求示例中的日期仅为示意。对于真实的请求,请根据时间值和检查新鲜度选择日期。

{
  "timelineSpec": {
    "aggregationPeriod": "DAILY",
    "startTime": "2026-08-12T00:00:00Z",
    "endTime": "2026-08-18T00:00:00Z"
  },
  "metrics": ["crashRate", "crashCount", "distinctDevices"],
  "dimensions": ["versionCode"],
  "filter": {
    "countryCode": ["US", "CA"],
    "deviceType": ["FIRE_TV"]
  },
  "pageSize": 1000
}

查询指标响应字段

字段 类型 始终存在 说明
freshness 对象,或null 是 查询汇总时段的新鲜度。如果没有可用的新鲜度,则该值为null。在这种情况下,rows为空。
freshness.aggregationPeriod 字符串 是,如果freshness不为null DAILY或HOURLY
freshness.latestDataTimestamp 字符串 是,如果freshness不为null 最新处理的天 (DAILY) 或小时 (HOURLY) 的UTC开始时间,格式为YYYY-MM-DDThh:mm:ssZ
resultCount 整数 是 此页的行数
rows[] 对象数组 是 此页的行。如果没有数据与查询匹配,则该数组为空。
nextPageToken 字符串,或null 是 请参阅分页。
availability 对象 仅适用于readyToUseMetricSet 查询的就绪数据状态。有关更多信息有关更多信息,请参阅就绪可用性。

每一行都包含以下字段:

字段 类型 始终存在 说明
startTime 字符串 是 时段的开始时间,格式为YYYY-MM-DDThh:mm:ssZ
aggregationPeriod 字符串 是 DAILY或HOURLY
dimensions[] 对象数组,或为null 是 每个请求的维度对应一个包含name和value字段的对象,顺序与请求中的dimensions一致。如果请求没有维度,则该字段为null。
metrics[] 对象数组 是 每个请求的指标对应一个指标对象。有关结构,请参阅指标对象。

指标对象

指标对象有以下两种形式之一:

  • 比率或计数指标:{"name": "crashRate", "value": 0.0142}
  • 时长指标:{"name": "coldStartAppLaunchTime", "statistics": {"Average": 1234.5678, "P90": 1500.0000, "P95": 1800.0000}}.appLatencyMetricSet和readyToUseMetricSet的四个时长指标使用此形式。statistics对象始终存在。每个统计值都可以为null。

比率为小数(0.0142表示1.42%),计数为整数,时长统计值以毫秒为单位。null指标值或统计值表示API无法计算该值。有关指标的含义,请参阅指标值。

其他指标规则

以下规则适用于特定指标:

  • 冷启动时应用启动时间至少为5秒,或热启动时至少为2秒,即为慢启动。
  • 对于HOURLY 7日比率,API会合并7天中每个相同的UTC小时。

查询指标响应示例

在此示例中,应用仅包含8月17日和8月18日的数据。

{
  "freshness": {
    "aggregationPeriod": "DAILY",
    "latestDataTimestamp": "2026-08-18T00:00:00Z"
  },
  "resultCount": 2,
  "rows": [
    {
      "startTime": "2026-08-17T00:00:00Z",
      "aggregationPeriod": "DAILY",
      "dimensions": [
        {"name": "versionCode", "value": "151"}
      ],
      "metrics": [
        {"name": "crashRate", "value": 0.0142},
        {"name": "crashCount", "value": 912},
        {"name": "distinctDevices", "value": 54320}
      ]
    },
    {
      "startTime": "2026-08-18T00:00:00Z",
      "aggregationPeriod": "DAILY",
      "dimensions": [
        {"name": "versionCode", "value": "151"}
      ],
      "metrics": [
        {"name": "crashRate", "value": 0.0138},
        {"name": "crashCount", "value": 887},
        {"name": "distinctDevices", "value": 55012}
      ]
    }
  ],
  "nextPageToken": null
}

时长指标示例

以下示例显示了不带维度的appLatencyMetricSet查询的一行。

{
  "startTime": "2026-08-18T00:00:00Z",
  "aggregationPeriod": "DAILY",
  "dimensions": null,
  "metrics": [
    {
      "name": "coldStartAppLaunchTime",
      "statistics": {"Average": 1234.5678, "P90": 1500.0000, "P95": 1800.0000}
    },
    {
      "name": "warmStartAppLaunchTime",
      "statistics": {"Average": 412.2500, "P90": 620.0000, "P95": 710.5000}
    }
  ]
}

就绪可用性

每个readyToUseMetricSet响应都有一个availability对象。其他指标集的响应没有此对象。

字段 类型 始终存在 说明
availability.state 字符串 是 AVAILABLE或ACTION_REQUIRED
availability.reasonCode 字符串 仅适用于ACTION_REQUIRED READY_TO_USE_DATA_UNAVAILABLE
availability.message 字符串 仅适用于ACTION_REQUIRED 一条告诉您该如何操作的消息
availability.documentationUrl 字符串 仅适用于ACTION_REQUIRED 指向就绪数据说明的链接

当请求的一个或多个就绪指标在查询时间范围内有数据时,状态为AVAILABLE。否则,状态为ACTION_REQUIRED。API会检查查询的所有页面,而不仅是当前页面。以下是ACTION_REQUIRED的可能原因:

  • 您的应用未报告其已就绪。在Fire OS上,您的应用必须调用Activity.reportFullyDrawn()。在Vega OS上,您的应用必须调用useReportFullyDrawn()中的回调。有关步骤,请参阅可用指标集。
  • 亚马逊尚无您应用的就绪数据。
  • 查询的汇总时段没有可用的新鲜度值。

对于ACTION_REQUIRED,响应可能包含行。在这些行中,统计值为null。

以下示例显示了不带行的ACTION_REQUIRED响应。

{
  "freshness": {
    "aggregationPeriod": "DAILY",
    "latestDataTimestamp": "2026-08-18T00:00:00Z"
  },
  "resultCount": 0,
  "rows": [],
  "nextPageToken": null,
  "availability": {
    "state": "ACTION_REQUIRED",
    "reasonCode": "READY_TO_USE_DATA_UNAVAILABLE",
    "message": "此应用无Ready to Use数据。这可能意味着该应用尚未针对Ready to Use进行埋点,或者数据尚未生成。请参阅以下文档以验证您的埋点设置,或联系您的亚马逊联系人寻求帮助。",
    "documentationUrl": "https://developer.amazon.com/apps-and-games/blogs/2023/06/improve-app-startup-times"
  }
}

查询问题

查询问题操作会返回整个时间范围内的高频崩溃问题或ANR问题。响应中每个问题对应一行。如果您请求维度,则响应中每个问题与维度值的组合对应一行。

查询问题请求参数

参数 描述 类型 必需
timelineSpec 汇总时段和时间范围。有关规则,请参阅时间值。 对象 是
reportType CRASH或ANR 字符串 是
dimensions[] 细分的维度。维度与crashMetricSet相同。 字符串数组 否
filter 要包含的维度值。有关规则,请参阅维度和筛选条件。 对象 否
pageSize 一页中的最大行数。默认值为25。值为0时使用默认值。值超过1,000时使用1,000。 整数 否
pageToken 上一响应中的nextPageToken值。不要在第一个请求中包含pageToken。 字符串 否

查询问题请求没有metrics字段。API会为每个问题返回errorEventCount和affectedDeviceCount。

查询问题请求示例

{
  "timelineSpec": {
    "aggregationPeriod": "DAILY",
    "startTime": "2026-08-05T00:00:00Z",
    "endTime": "2026-08-18T00:00:00Z"
  },
  "reportType": "CRASH",
  "filter": {"versionCode": ["152"]},
  "pageSize": 25
}

查询问题响应字段

字段 类型 始终存在 说明
rows[] 对象数组 是 此页面的问题。如果没有问题与查询匹配,则该数组为空。
rows[].crashDescriptor 字符串 是 问题的标识符
rows[].reportText 字符串,或null 是 该问题的一个示例堆栈跟踪。每个响应中的示例可能不同。API可以缩短过长的堆栈跟踪。如果没有可用的堆栈跟踪,则该值为null或空字符串。
rows[].dimensions[] 对象数组,或为null 是 每个请求的维度对应一个包含name和value字段的对象。如果请求没有维度,则该字段为null。
rows[].metrics[] 对象数组 是 两个指标对象,分别对应errorEventCount和affectedDeviceCount。每个对象都包含name和整数值value。有关其含义,请参阅可用指标集。
nextPageToken 字符串,或null 是 下一页的令牌。在最后一页,该值为null。

响应中没有resultCount或freshness。问题按errorEventCount降序排列。

查询问题响应示例

{
  "rows": [
    {
      "crashDescriptor": "67f35eb2c1a94d0e",
      "reportText": "java.lang.IllegalStateException: Player is not ready\n\tat com.example.myapp.Player.start(Player.java:88)",
      "dimensions": null,
      "metrics": [
        {"name": "errorEventCount", "value": 78},
        {"name": "affectedDeviceCount", "value": 45}
      ]
    }
  ],
  "nextPageToken": null
}

实现示例

以下示例显示了Vitals API V2的Python代码。在一个Python会话中按顺序运行这些示例。每个示例都会使用其前面示例中的函数和变量。

获取访问令牌

要获取访问令牌,请向https://api.amazon.com/auth/o2/token发送POST请求,并包含以下表单字段:

  • grant_type:client_credentials
  • client_id: 您的客户端ID
  • client_secret: 您的客户端密钥
  • scope:adx_reporting::appstore:marketer

响应中包含access_token和expires_in。expires_in的值为令牌过期前的秒数。

以下示例会保留该令牌。它会在令牌过期前5分钟获取新令牌。

import time

import requests

# 必须提供的值
client_id = "<客户端ID>"
client_secret = "<客户端密钥>"
package_name = "<您的应用程序包名称>"

BASE_URL = "https://developer.amazon.com/api/appstore"
VITALS_URL = f"{BASE_URL}/v2/applications/{package_name}/vitals"

_token = {"value": None, "expires_at": 0.0}


def auth_headers():
    """返回带有有效LWA访问令牌的请求标头。""
    if time.time() > _token["expires_at"] - 300:
        response = requests.post(
            "https://api.amazon.com/auth/o2/token",
            data={
                "grant_type": "client_credentials",
                "client_id": client_id,
                "client_secret": client_secret,
                "scope": "adx_reporting::appstore:marketer",
            },
            timeout=30,
        )
        response.raise_for_status()
        token = response.json()
        _token["value"] = token["access_token"]
        _token["expires_at"] = time.time() + token["expires_in"]
    return {
        "Authorization": f"Bearer {_token['value']}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    }

发送重试请求

以下辅助函数会重试429和临时错误。在首次出现401时,它会刷新令牌,并在仍有剩余尝试次数时重试。有关重试规则,请参阅重试策略。

import random
import time

import requests

# 使用“获取访问令牌”中的auth_headers()和_token。

MAX_ATTEMPTS = 4
RETRYABLE_STATUS_CODES = {429, 500, 503, 504}


def send(method, url, body=None):
    """发送请求。重试受限制的请求或临时错误。"""
    token_renewed = False
    for attempt in range(1, MAX_ATTEMPTS + 1):
        headers = auth_headers()
        try:
            response = requests.request(
                method, url, headers=headers, json=body, timeout=60
            )
        except (requests.ConnectionError, requests.Timeout):
            if attempt == MAX_ATTEMPTS:
                raise
            time.sleep(2 ** attempt + random.uniform(0, 1))
            continue

        renew = response.status_code == 401 and not token_renewed
        if renew and attempt < MAX_ATTEMPTS:
            token_renewed = True
            _token["expires_at"] = 0.0  # 为下一次尝试获取新令牌。
            continue
        if response.status_code not in RETRYABLE_STATUS_CODES:
            response.raise_for_status()
            return response.json()
        if attempt == MAX_ATTEMPTS:
            response.raise_for_status()

        retry_after = response.headers.get("Retry-After")
        if retry_after is not None:
            delay = float(retry_after)
        else:
            delay = 2 ** attempt + random.uniform(0, 1)
        time.sleep(delay)

选择时间范围

以下辅助函数会构建一个以指标集新鲜度值结束的时间范围。在时间值的限制范围内选择一个范围。

from datetime import datetime, timedelta

TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"


def time_range(metric_set_name, aggregation_period, periods):
    """返回指标集最新时段的 (startTime, endTime)。"""
    info = send("GET", f"{VITALS_URL}/{metric_set_name}")
    latest = {item["aggregationPeriod"]: item["latestDataTimestamp"] for item in info["freshnessInfo"]}
    end = datetime.strptime(latest[aggregation_period], TIME_FORMAT)
    step = timedelta(days=1) if aggregation_period == "DAILY" else timedelta(hours=1)
    start = end - step * (periods - 1)
    return start.strftime(TIME_FORMAT), end.strftime(TIME_FORMAT)

查询崩溃指标

以下示例获取每个应用版本的每日崩溃率、崩溃次数和设备数。该筛选条件仅包含美国和加拿大的Fire TV设备。

start_time, end_time = time_range("crashMetricSet", "DAILY", 7)
crash_body = {
    "timelineSpec": {"aggregationPeriod": "DAILY", "startTime": start_time, "endTime": end_time},
    "metrics": ["crashRate", "crashCount", "distinctDevices"],
    "dimensions": ["versionCode"],
    "filter": {"countryCode": ["US", "CA"], "deviceType": ["FIRE_TV"]},
}

result = send("POST", f"{VITALS_URL}/crashMetricSet:query", crash_body)
for row in result["rows"]:
    values = {metric["name"]: metric["value"] for metric in row["metrics"]}
    print(row["startTime"], row["dimensions"], values)

查询应用启动时间

时长指标包含statistics,而非value。以下示例获取每种设备类型的冷启动和热启动应用启动时间。

start_time, end_time = time_range("appLatencyMetricSet", "DAILY", 7)
result = send("POST", f"{VITALS_URL}/appLatencyMetricSet:query", {
    "timelineSpec": {"aggregationPeriod": "DAILY", "startTime": start_time, "endTime": end_time},
    "metrics": ["coldStartAppLaunchTime", "warmStartAppLaunchTime"],
    "dimensions": ["deviceType"],
})

查询慢启动率

slowStartRateMetricSet要求在dimensions中包含startType。以下示例获取最近24小时仅冷启动的每小时慢启动率。

start_time, end_time = time_range("slowStartRateMetricSet", "HOURLY", 24)
slow_start_body = {
    "timelineSpec": {"aggregationPeriod": "HOURLY", "startTime": start_time, "endTime": end_time},
    "metrics": ["slowStartRate", "slowStartRate7dDeviceWeighted", "distinctDevices"],
    "dimensions": ["startType"],
    "filter": {"startType": ["COLD"]},
}

result = send("POST", f"{VITALS_URL}/slowStartRateMetricSet:query", slow_start_body)
for row in result["rows"]:
    values = {metric["name"]: metric["value"] for metric in row["metrics"]}
    print(row["startTime"], values["slowStartRate"], values["distinctDevices"])

查询准备就绪时间

以下示例获取就绪时间并检查availability对象。

from datetime import timezone

try:
    start_time, end_time = time_range("readyToUseMetricSet", "DAILY", 7)
except KeyError:
    # 尚无新鲜度;请查询近期UTC日期以获取可用性状态。
    end = datetime.now(timezone.utc)
    start_time = (end - timedelta(days=6)).strftime(TIME_FORMAT)
    end_time = end.strftime(TIME_FORMAT)

ready_to_use_body = {
    "timelineSpec": {"aggregationPeriod": "DAILY", "startTime": start_time, "endTime": end_time},
    "metrics": ["coldStartReadyToUseTime", "warmStartReadyToUseTime"],
}

result = send("POST", f"{VITALS_URL}/readyToUseMetricSet:query", ready_to_use_body)
availability = result["availability"]
if availability["state"] == "ACTION_REQUIRED":
    print(availability["message"])
    print(availability["documentationUrl"])

for row in result["rows"]:
    for metric in row["metrics"]:
        print(row["startTime"], metric["name"], metric["statistics"]["Average"])

分页显示结果

以下函数获取查询的所有页面。它在两个页面之间等待0.4秒,以保持在速率限制以下。它返回最后一页的行数和freshness对象。对于查询问题,第二个值为None,因为响应中没有freshness。

def query_all_rows(url, body):
    """发送查询。返回所有页面的行数和最后一页的freshness。"""
    rows = []
    page_body = dict(body)
    page_body.pop("pageToken", None)
    while True:
        result = send("POST", url, page_body)
        rows.extend(result["rows"])
        if result["nextPageToken"] is None:
            return rows, result.get("freshness")
        page_body["pageToken"] = result["nextPageToken"]
        time.sleep(0.4)

查询高频崩溃问题

以下示例获取最近14天内版本代码152的高频崩溃问题的第一页。该筛选条件选择版本。

start_time, end_time = time_range("crashMetricSet", "DAILY", 14)
issues_body = {
    "timelineSpec": {"aggregationPeriod": "DAILY", "startTime": start_time, "endTime": end_time},
    "reportType": "CRASH",
    "filter": {"versionCode": ["152"]},
    "pageSize": 25,
}

result = send("POST", f"{VITALS_URL}/issuesMetricSet:query", issues_body)
for issue in result["rows"]:
    counts = {metric["name"]: metric["value"] for metric in issue["metrics"]}
    print(issue["crashDescriptor"], counts["errorEventCount"], counts["affectedDeviceCount"])
    print(issue["reportText"])

错误处理

有关如何处理错误,请参阅以下几节。

错误响应格式

API会为每个错误响应发送JSON正文。HTTP状态码位于响应的状态行中。正文不包含状态码或请求ID。

字段 类型 始终存在 说明
code 字符串 是 错误代码,例如VALIDATION_ERROR
message 字符串 是 对错误的描述
errors[] 对象数组 仅适用于400 VALIDATION_ERROR 每个问题对应一个条目
errors[].field 字符串 是 字段的路径,例如timelineSpec.endTime、metrics[1]或filter.countryCode[0]
errors[].code 字符串 是 字段错误代码。有关这些值,请参阅字段错误代码。
errors[].message 字符串 是 问题的描述

每个成功响应和每个错误响应都有一个x-amzn-RequestId标头。记录该值。如果您就某个请求联系亚马逊开发者支持,请提供此值。

单错误示例

以下响应针对请求crashRate28dUserWeighted的HOURLY查询。

{
  "code": "VALIDATION_ERROR",
  "message": "指标'crashRate28dUserWeighted'不适用于HOURLY汇总",
  "errors": [
    {
      "field": "metrics[0]",
      "code": "VALUE_NOT_ALLOWED",
      "message": "指标'crashRate28dUserWeighted'不适用于HOURLY汇总"
    }
  ]
}

多字段验证示例

以下响应针对"startTime": "2026-08-18"和"pageSize": -5的查询。

{
  "code": "VALIDATION_ERROR",
  "message": "请求中包含2个无效字段。",
  "errors": [
    {
      "field": "timelineSpec.startTime",
      "code": "FIELD_INVALID",
      "message": "timelineSpec.startTime必须是YYYY-MM-DDThh:mm:ssZ格式的有效规范UTC时间戳"
    },
    {
      "field": "pageSize",
      "code": "FIELD_OUT_OF_RANGE",
      "message": "pageSize必须为非负数,当前值:-5"
    }
  ]
}

错误代码

HTTP状态 代码 原因 操作
400 VALIDATION_ERROR 请求存在问题,例如未知的指标或未知的metricSetName,或者Content-Type标头不是application/json。 如果响应中包含errors[],则使用它来查找问题。更正请求,然后发送更正后的请求。
401 AUTHENTICATION_FAILED 访问令牌缺失、已过期或无效,或者安全配置文件未关联到报告API。 获取新的访问令牌。确保您已将安全配置文件关联到报告API。
403 ACCESS_DENIED 您的开发者账户不拥有该应用,或者Vitals API V2不适用于您的开发者账户。 确保您的开发者账户拥有该应用。如果您的开发者账户拥有该应用,请等待1分钟,然后再次发送该请求一次。如果再次出现该错误,请联系亚马逊开发者支持。提供x-amzn-RequestId值。
404 RESOURCE_NOT_FOUND 没有应用使用此程序包名称、路径不正确,或者HTTP方法不适用于该路径。 确保程序包名称和路径正确。使用GET检查新鲜度。使用POST处理查询指标和查询问题,并在路径末尾添加:query。
429 RATE_LIMIT_EXCEEDED 您发送的请求数超过了速率限制允许的数量。 等待Retry-After标头中指定的秒数。然后再次发送请求。
500 INTERNAL_ERROR 服务中发生意外错误,或者查询期间某个服务依赖项失败。 使用指数退避策略再次发送请求,最多3次。如果响应中包含Retry-After标头,则等待该标头指定的秒数。有关等待时间,请参阅重试策略。
503 SERVICE_UNAVAILABLE 服务依赖项暂时不可用,或者网关无法访问该服务。 使用指数退避策略再次发送请求,最多3次。如果响应中包含Retry-After标头,则等待该标头指定的秒数。有关等待时间,请参阅重试策略。
504 GATEWAY_TIMEOUT 网关未及时收到来自服务的响应。 使用指数退避策略再次发送请求,最多3次。如果响应中包含Retry-After标头,则等待该标头指定的秒数。有关等待时间,请参阅重试策略。

字段错误代码

字段错误代码 含义
FIELD_REQUIRED 请求缺少必填字段,或者数组包含空元素。
FIELD_INVALID 值的格式或类型错误,或者该字段不受支持。
FIELD_TOO_LONG versionCode值超过32个字符。
FIELD_OUT_OF_RANGE 该值超出允许范围。例如,时间范围过长,或者pageSize为负数。
FIELD_NOT_UNIQUE 某个值或JSON键出现多次。
FIELD_IMMUTABLE pageToken无效。使用上一响应中的nextPageToken,或省略pageToken以开始新查询。
VALUE_NOT_ALLOWED 该值不在允许值集合中。例如,指标或维度未知。filter中的null值,或者metrics或dimensions中的null元素,也会导致此代码。

常见错误和修复

错误 结果 修复
使用V1时间对象 400 VALIDATION_ERROR 使用UTC时间戳字符串,例如2026-08-18T00:00:00Z。
使用V1设备类型,例如AMAZON_FIRE_TV 400 VALIDATION_ERROR 使用FIRE_TV、FIRE_TABLET或OTHER。
请求HOURLY的28d指标 400 VALIDATION_ERROR 使用DAILY。
从slowStartRateMetricSet查询中省略startType 400 VALIDATION_ERROR 将startType添加到dimensions。
从时长指标读取value 没有value字段 读取statistics.Average、statistics.P90或statistics.P95。

比率限制、重试和最佳实践

作为参考,API允许每个开发者账户每秒约3个请求,短时间内最多可突发至10个请求。所有Vitals API V2操作共享此限制,适用于您的所有应用。该限制可能会变化,API可能会在您达到限制之前就返回429响应。Vitals API的V1版本有单独的限制。

当您超出限制时,API会返回429 RATE_LIMIT_EXCEEDED响应,并附带Retry-After标头。在再次发送请求之前,等待该标头中指定的秒数。

重试策略

send函数会在出现429、500、503、504、连接错误或超时后再次发送请求,最多3次。如果响应中包含Retry-After标头,该函数会等待该标头指定的秒数。否则,它会等待约2秒、4秒和8秒,外加最多1秒的随机抖动。在首次出现401后,该函数会获取新的访问令牌,并在仍有剩余尝试次数时再次发送请求。该函数不会重试其他4xx错误或失败的令牌请求。

生产最佳实践

练习 建议
重新查询近期时段 重新查询近期时段并替换存储的值;延迟数据可能会改变这些值。
使用错误代码 使用code、errors[].code和errors[].field,而不是解析错误消息。
忽略未知值 忽略您不认识的响应字段、指标和维度值;亚马逊可能会在Beta阶段添加这些内容。

从V1迁移

Vitals API的版本1 (V1) 继续运行。下表显示了迁移到版本2 (V2) 必须进行的更改。

项目 V1 V2
终结点路径 /vitals/apps/{程序包名称}/{指标集名称} /v2/applications/{程序包名称}/vitals/{指标集名称}
请求中的时间值 一个对象,例如{"year": 2026, "month": 8, "day": 18, "hours": 14} 一个字符串,例如"2026-08-18T14:00:00Z"
查询问题的时间范围 正文顶层的startTime和endTime timelineSpec,包含aggregationPeriod、startTime和endTime
行中的startTime 一个对象 格式为YYYY-MM-DDThh:mm:ssZ的字符串
新鲜时间值 例如2026-08-18和2026-08-18T14 例如2026-08-18T00:00:00Z和2026-08-18T14:00:00Z
指标值 字符串,例如"0.0142" 数字,例如0.0142
时长指标(应用启动时间和就绪时间) 一个value statistics,包含Average、P90和P95
查询指标响应中的status和requestId 存在 已移除。请求ID位于x-amzn-RequestId标头中。
deviceType值 AMAZON_FIRE_TV或AMAZON_TABLETS或AMAZON_FIRE_PHONE或AUCC或CORO FIRE_TV或FIRE_TABLET或OTHER
操作系统维度 deviceOS deviceOs
您的开发者账户不拥有的应用 404 NOT_FOUND 403 ACCESS_DENIED
错误正文 code、message、status 用于验证错误的code、message和errors[]

Last updated: 2026年10月13日