as

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

Monetization Metrics API参考

Monetization Metrics API参考

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

Monetization Metrics API的使用须遵守程序材料许可协议。

先决条件

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

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

基本URL

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

操作

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

操作 方法 终结点 描述
检查新鲜度 GET /v2/applications/{packageName}/monetization/{metricSetName} 最新可用数据时间戳
查询指标 POST /v2/applications/{packageName}/monetization/{metricSetName}:query 包含维度/筛选条件的时序指标

{metricSetName}路径参数接受以下指标集:subsSignupMetricSet、subsRenewalMetricSet、subsReactivationMetricSet、subsCancellationMetricSet、subsActiveMetricSet、subsHealthMetricSet、subsCancellationSurveyMetricSet和subsFulfillmentMetricSet。

请求

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

请求参数

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

参数 描述 类型 是否必需
timelineSpec.aggregationPeriod 返回数据的粒度: DAILY或HOURLY 字符串 是
timelineSpec.startTime 查询窗口的下界,采用ISO 8601 UTC时间戳字符串(即%Y-%m-%dT%H:%M:%SZ),例如"2026-07-01T00:00:00Z"。两个边界值均包含在内。比汇总时段更精细的字段将被忽略,而非被拒绝: 在HOURLY查询中,分钟/秒会被舍去(T10:15:00Z视为10点),在DAILY查询中,小时及更精细的字段会被舍去。 字符串 是
timelineSpec.endTime 查询窗口的上界,采用ISO 8601 UTC时间戳字符串(即%Y-%m-%dT%H:%M:%SZ)。必须等于或晚于startTime;两个边界值均包含在内。比粒度更精细的字段会被忽略,规则与startTime相同。HOURLY的endTime为T11:30:45Z时视为11点,因此第11小时仍包含在内。 字符串 是
metrics[] 要从指标集返回的指标名称的子集。省略以返回集合上定义的所有指标。 ​数组 否
dimensions[] 用于对结果分组的维度(例如subscriptionType、marketplace)。 ​数组 否
filter JSON对象形式的筛选条件。每个键都是一个维度;其值是允许值的列表(字段内为OR,跨字段为AND)。例如,{"marketplace": ["US"]}。 对象 否
pageSize 每页的最大行数。默认值:1,000。最大值:100,000。 整数 否
pageToken 前一个响应的nextPageToken中返回了不透明的光标。在第一次请求时省略。 字符串 否

验证规则

API会先验证每个查询请求,然后再执行。违反以下任何规则的请求都会以400 VALIDATION_ERROR被拒绝;响应正文的message字段会描述违规情况。以下示例展示了每条规则返回的消息。

规则 违规时出错
endTime必须大于或等于startTime timelineSpec.endTime必须等于或晚于startTime
HOURLY的时间戳必须在最近15天内 timelineSpec.startTime必须在最近15天内
DAILY的时间戳必须在最近30天内 timelineSpec.startTime必须在最近30天内
指标名称必须存在于指标集中 metrics包含'…',而'…MetricSet'不支持该指标。允许的指标:[…]
维度名称必须存在 dimensions包含'…',而该维度未知;允许的维度:[…]
维度必须受指标集支持 dimensions包含'…',而'…MetricSet'不支持该维度。允许的维度:[…]
subsActiveMetricSet和subsCancellationSurveyMetricSet仅支持DAILY '..MetricSet'不支持HOURLY汇总
marketplace必须是受支持的代码 维度'marketplace'的值'UK'无效。有效值:[CA, US, MX, JP, FR, IT, DE, BR, ES, IN, AU, GB]
metrics不得包含重复项 metrics中'fulfilled'出现多次
dimensions不得包含重复项 dimensions中'marketplace'出现多次
pageSize不得为负数 pageSize必须为非负数,当前值:-5
时间戳必须是有效的ISO 8601 UTC时刻 startTime无效: '2026-02-30T00:00:00Z'不是有效日期
每个筛选键最多100个值 400 VALIDATION_ERROR
pageToken必须是上一响应中的有效游标,并保持相同的请求结构重复使用 pageToken与此请求不匹配。生成游标后,对请求结构(metricSet、timelineSpec、dimensions或filter)进行了更改。开始新的查询。(FIELD_IMMUTABLE)

响应

响应结构因操作而异。新鲜度检查 (GET) 返回一个freshnessInfo数组,每个汇总时段对应一个条目;而查询端点 (POST) 返回一个与请求时段匹配的freshness对象。

获取新鲜度响应字段

字段 始终存在 说明
name 是 指标集名称
description 是 指标集描述
metrics 是 可用指标名称数组
dimensions 是 可用维度名称数组
freshnessInfo[] 是 此指标集支持的每个汇总时段对应一个条目。仅支持DAILY的指标集(例如subsActiveMetricSet)会返回单个DAILY条目。
freshnessInfo[].aggregationPeriod 是 DAILY或HOURLY
freshnessInfo[].latestDataTimestamp 是 最新的完全完整时段,采用ISO 8601 UTC时刻表示。DAILY返回T00:00:00Z(整个UTC日已完成);HOURLY返回Thh:00:00Z(该hh:00–hh:59小时已完成)。

成功响应 (200)

标头
HTTP/1.1 200 OK
Content-Type: application/json
x-amzn-RequestId: 0d4db8e3-c535-4ba8-bdce-614eb6490570
正文
{
  "name": "subsSignupMetricSet",
  "description": "新订阅注册量和注册收入",
  "metrics": ["signups", "signupRevenue"],
  "dimensions": ["marketplace", "termSku", "deviceType", "deviceOs", "subscriptionType"],
  "freshnessInfo": [
    {"aggregationPeriod": "DAILY", "latestDataTimestamp": "2026-07-06T00:00:00Z"},
    {"aggregationPeriod": "HOURLY", "latestDataTimestamp": "2026-07-06T14:00:00Z"}
  ]
}

解读latestDataTimestamp: 该值为一个ISO 8601 UTC时刻,用于标记最新的完全完整的汇总时段。该标签为时段的开始时刻,且整个时段均已完成。对于HOURLY,Thh:00:00Z表示hh:00–hh:59这一小时已完成(例如,2026-07-06T14:00:00Z表示14:00–14:59这一小时已完成)。对于DAILY,YYYY-MM-DDT00:00:00Z表示整个UTC日已完成(例如,2026-07-06T00:00:00Z表示7月6日全天已完成)。

POST查询响应字段

字段 始终存在 说明
freshness 是 所查询汇总时段的最新数据时间戳
resultCount 是 此页的行数
rows[] 是 如果没有数据匹配,则可能为空
nextPageToken 仅适用于分多页显示结果的情况 传入下一个请求以获取下一页

成功响应 (200)

标头
HTTP/1.1 200 OK
Content-Length:735
Content-Type: application/json
Date: Mon, 21 Sep 2026 13:13:56 GMT
x-amzn-RequestId: 912d79f5-e9b6-4466-b438-b41a96c30acf
正文
{
  "freshness": {
    "aggregationPeriod": "DAILY",
    "latestDataTimestamp": "2026-07-06T00:00:00Z"
  },
  "resultCount": 3,
  "rows": [
    {
      "startTime": "2026-07-01T00:00:00Z",
      "aggregationPeriod": "DAILY",
      "dimensions": [
        {"name": "subscriptionType", "value": "FREE_TRIAL"},
        {"name": "marketplace", "value": "US"}
      ],
      "metrics": [
        {"name": "signups", "value": 2341},
        {"name": "signupRevenue", "value": 12345.6}
      ]
    }
  ],
  "nextPageToken": "MjAyNi0wNy0wMXwxNA=="
}

实现示例

以下示例展示了用于使用Monetization Metrics API执行各种任务的Python代码。

获取访问令牌

使用客户端ID和客户端密钥获取身份验证令牌。必需将身份验证令牌添加到每个API请求的标头。以下示例展示了如何获取身份验证令牌,并使用令牌创建Authorization标头。

import requests

# 需要提供的值
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}/v2/applications/{package_name}/monetization/subsSignupMetricSet"
freshness_response = requests.get(freshness_url, headers=headers)
freshness = freshness_response.json()

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

查询注册指标

以下示例显示了如何查询每日注册指标。

query_url = f"{BASE_URL}/v2/applications/{package_name}/monetization/subsSignupMetricSet:query"
body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": ["signups", "signupRevenue"]
}
response = requests.post(query_url, headers=headers, json=body)
result = response.json()

使用维度查询

以下示例显示了如何按订阅类型和市场细分注册量。

body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": ["signups", "signupRevenue"],
    "dimensions": ["subscriptionType", "marketplace"]
}
response = requests.post(query_url, headers=headers, json=body)
result = response.json()

使用筛选条件查询

以下示例显示了如何将结果缩小到仅限美国的免费试用注册。

body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": ["signups"],
    "filter": {"subscriptionType": ["FREE_TRIAL"], "marketplace": ["US"]}
}
response = requests.post(query_url, headers=headers, json=body)
result = response.json()

查询按小时指标

以下示例显示了如何查询每小时数据以进行近实时订阅监控。

body = {
    "timelineSpec": {
        "aggregationPeriod": "HOURLY",
        "startTime": "2026-07-07T08:00:00Z",
        "endTime": "2026-07-07T11:00:00Z"
    },
    "metrics": ["signups"],
    "dimensions": ["subscriptionType"]
}

要覆盖一整天,请将startTime设置为T00:00:00Z,将endTime设置为T23:00:00Z。每小时返回一行。任一边界中的分钟和秒都会被忽略(舍去并归入所属小时)。

body = {
    "timelineSpec": {
        "aggregationPeriod": "HOURLY",
        "startTime": "2026-07-07T00:00:00Z",
        "endTime": "2026-07-07T23:00:00Z"
    },
    "metrics": ["signups"],
    "dimensions": ["subscriptionType"]
}
response = requests.post(query_url, headers=headers, json=body)
result = response.json()

查询履行指标

以下示例显示了如何查询收据送达性能。

fulfillment_url = f"{BASE_URL}/v2/applications/{package_name}/monetization/subsFulfillmentMetricSet:query"
body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": [
        "totalReceipts",
        "fulfilled",
        "unavailable",
        "pending",
        "p50AcknowledgementDelay",
        "p90AcknowledgementDelay",
        "p95AcknowledgementDelay"
    ],
    "filter": {"purchaseChannel": ["QS"]}
}
response = requests.post(fulfillment_url, headers=headers, json=body)
result = response.json()

查询订阅状况

以下示例显示了如何跟踪自动续订变更和宽限期事件。

health_url = f"{BASE_URL}/v2/applications/{package_name}/monetization/subsHealthMetricSet:query"
body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": ["autoRenewalOff", "autoRenewalOn", "gracePeriodEntries", "gracePeriodRecoveries"],
    "dimensions": ["subscriptionType"]
}
response = requests.post(health_url, headers=headers, json=body)
result = response.json()

查询取消调查回复

以下示例显示了如何按客户在取消调查中选择的原因来细分已调查的取消情况。此指标集仅支持DAILY粒度。

survey_url = f"{BASE_URL}/v2/applications/{package_name}/monetization/subsCancellationSurveyMetricSet:query"
body = {
    "timelineSpec": {
        "aggregationPeriod": "DAILY",
        "startTime": "2026-07-01T00:00:00Z",
        "endTime": "2026-07-07T00:00:00Z"
    },
    "metrics": ["surveyedCancellations"],
    "dimensions": ["cancellationReason"]
}
response = requests.post(survey_url, headers=headers, json=body)
result = response.json()

分页显示结果

以下示例展示了在响应中包含nextPageToken时如何获取所有结果。

all_rows = []
page_token = None
while True:
    body = {
        "timelineSpec": {
            "aggregationPeriod": "DAILY",
            "startTime": "2026-07-01T00:00:00Z",
            "endTime": "2026-07-07T00:00:00Z"
        },
        "metrics": ["signups"],
        "dimensions": ["subscriptionType", "marketplace"],
        "pageSize": 100
    }
    if page_token:
        body["pageToken"] = page_token
    response = requests.post(query_url, headers=headers, json=body)
    result = response.json()
    all_rows.extend(result["rows"])
    page_token = result.get("nextPageToken")
    if not page_token:
        break

错误处理

所有错误都会返回结构化的JSON。HTTP状态行包含状态类别 (4xx/5xx);;正文包含机器可读代码、人类可读消息,以及(对于验证失败)标识每个违规字段的字段级errors[]数组。

  字段 始终存在 说明
1 code 是 来自标准枚举的机器可读错误代码(例如VALIDATION_ERROR)
2 message 是 错误的人类可读描述
3 errors[] 仅用于验证失败 字段级详细信息;每个条目都包含field(指向违规元素的点分隔路径,适用时包含数组索引,例如metrics[1]或filter.deviceType[0])、code(字段级代码,例如VALUE_NOT_ALLOWED或FIELD_INVALID)以及message

单错误示例

{
  "code": "VALIDATION_ERROR",
  "message": "metrics包含'subsSignupMetricSet'不支持的'bogus';允许的指标:[signupRevenue, signups]",
  "errors": [
    {
      "field": "metrics[0]",
      "code": "VALUE_NOT_ALLOWED",
      "message": "metrics包含'subsSignupMetricSet'不支持的'bogus';允许的指标:[signupRevenue, signups]"
    }
  ]
}

多字段验证示例

{
  "code": "VALIDATION_ERROR",
  "message": "请求中包含3个无效字段。",
  "errors": [
    {
      "field": "metrics[1]",
      "code": "VALUE_NOT_ALLOWED",
      "message": "metrics包含'subsSignupMetricSet'不支持的'bogus';允许的指标:[signupRevenue, signups]"
    },
    {
      "field": "dimensions[0]",
      "code": "VALUE_NOT_ALLOWED",
      "message": "dimensions包含未知维度'startType';允许的维度:[deviceOs, deviceType, marketplace, subscriptionType, termSku]"
    },
    {
      "field": "filter.deviceType[1]",
      "code": "VALUE_NOT_ALLOWED",
      "message": "维度'deviceType'的'AMAZON_FIRE_TV'值无效。Valid: [FIRE_TABLET, FIRE_TV, OTHER]"
    }
  ]
}

错误代码

HTTP状态 代码 原因 操作
400 VALIDATION_ERROR 请求参数错误(指标、维度、筛选值、日期范围无效) 修复请求;不要重试
401 AUTHENTICATION_FAILED 访问令牌缺失、无效或已过期 刷新令牌,然后重试
403 ACCESS_DENIED 经过身份验证的调用方没有此应用或API的权限 验证该程序包归您的供应商账户所有,并且您的安全配置文件已映射到报告API
404 RESOURCE_NOT_FOUND 程序包名不正确或为空 检查程序包名称的拼写
429 RATE_LIMIT_EXCEEDED 超过每秒5次请求 回退,然后以指数级延迟重试
500 INTERNAL_ERROR 服务器意外错误 使用回退功能重试(最多3次)
503 SERVICE_UNAVAILABLE 服务或依赖项暂时不可用 使用退避策略重试

常见错误和修复

错误 您会看到的错误 修复
缺少timelineSpec "timelineSpec is required" 添加必需的timelineSpec对象
将HOURLY与subsActiveMetricSet一起使用 "subsActiveMetricSet不支持HOURLY汇总" 切换到DAILY
startTime或endTime超出了可查询窗口 "timelineSpec.startTime必须在最近15天内" (FIELD_OUT_OF_RANGE) 将违规的时间戳移到窗口内: DAILY:过去30天(截至昨天);HOURLY:过去15天
令牌过期 401 AUTHENTICATION_FAILED 刷新LWA令牌
请求过多 429 Too Many Requests 在调用之间添加time.sleep()
对指标集使用了错误的维度 "dimensions包含'renewalType',而'subsSignupMetricSet'不支持该维度。允许的维度:[…]" 为该指标集使用正确的维度
更改dimensions、filter或timelineSpec后重复使用分页令牌 FIELD_IMMUTABLE: "pageToken与此请求不匹配" 在不使用旧令牌的情况下启动新查询。仅允许在不同页面之间更改pageSize。
URL中的metricSetName拼写错误 400 VALIDATION_ERROR: "不支持的metricSetName: …;允许的指标集名称:[…]" 使用错误消息中列出的指标集名称之一

重试和最佳实践

有关重试策略和最佳实践,请参阅以下几节。

重试策略示例

import time

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

def query_with_retry(url, headers, body):
    for attempt in range(MAX_RETRIES):
        resp = requests.post(url, headers=headers, json=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', '')}")

生产最佳实践

练习 建议
令牌缓存 缓存令牌并在到期前五分钟刷新。切勿每次API调用都请求新令牌。
先检查新鲜度 在查询之前,请务必调用freshness终结点,以避免结果为空。
使用分页 默认pageSize为1,000。对于较大的维度细分,请进行分页以避免超时。
速率限制 保持在每秒5个请求以下。在连续调用之间添加time.sleep(0.2)。
仅重试可重试的错误 重试429、500、502、503和504。切勿重试400(改为修复请求)。
处理空结果 返回rows: [] 的查询不是错误。这表示该日期范围内没有数据。
避免过度获取 仅请求所需的指标。如果metrics[],就会返回所有指标,导致查询速度变慢。

Last updated: 2026年10月13日