本页简要介绍了 REST API 惯例,并提供了常见 Google Health API 任务的索引以及每个任务的示例。
REST API 惯例
Google Health API 遵循 Google API 改进提案 (AIP) 标准,特别是 AIP-127(HTTP 和 gRPC 转码)以及 AIP-131 至 AIP-135(标准方法)。这些标准定义了如何将数据从 proto 消息映射到 HTTP 请求。
查询参数
当数据是网址的一部分时,会使用查询参数。这主要用于 GET 请求(提取资源)或 LIST 请求(过滤/分页),但也用于 DELETE 操作。
- 展示位置:附加到网址中
?之后。 - 语法:以
&分隔的键值对。 - 映射:请求消息中不属于网址路径模板的每个字段都会映射到查询参数。
- 最适合:简单类型(字符串、整数、枚举)和重复字段。
语法示例:
GET https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints?page_size=10&filter=data_type.interval.start_time >= "2025-10-01T00:00:00Z"
请求正文
当数据会修改资源的状态或数据量过大而无法放入网址中时,会使用请求正文。正文通常是资源的 JSON 表示法。通常用于 POST、PATCH 和 PUT 操作。
- 放置位置:位于 HTTP 载荷内(在网址中不可见)。
- 语法:格式为 JSON 对象。
- 映射:在
google.api.http注释中定义。body: "*"表示整个消息都是正文。body: "resource_name"表示只有 proto 中的特定字段是正文。
- 最适合:复杂对象、嵌套消息和敏感数据。
语法示例:
POST https://health.googleapis.com/v4/users/me/dataTypes/data-type/dataPoints:rollUp
Content-Type: application/json
{
"range": {
"startTime": "2025-11-05T00:00:00Z",
"endTime": "2025-11-13T00:00:00Z"
},
"windowSize": "3600s"
}混合型
在符合 AIP-134 标准的 Update 方法或 PATCH 操作中,两者都会使用。网址包含资源名称,正文包含更新后的资源数据,而查询参数(通常为 update_mask)用于指定要更改的字段。
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
Content-Type: application/json
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}
主要区别一览
| 功能 | 查询参数 | 请求正文 |
|---|---|---|
| AIP 指南 | 用于搜索、过滤和读取操作。 | 用于写入操作。 |
| 公开范围 | 显示在浏览器历史记录和服务器日志中。 | 隐藏在网址中。 |
| 复杂性 | 仅限扁平或重复结构。 | 支持深度嵌套的 JSON 对象。 |
| 编码 | 必须经过网址编码(例如,空格会变成 %20)。 |
标准 JSON 编码。 |
日期
Google Health API 中的所有日期均以 YYYY-MM-DD 格式显示。Nutrition API 支持 ISO-8601 标准的日期值,但需满足以下条件:
- 4 位数年份
YYYY - 年份值介于 0000-9999 之间
- 不强制执行 ISO-8601 标准或其他纪元所隐含的开始日期限制
标头
执行 Google Health API 端点需要使用适当的标头和访问令牌。建议为 GET 和 POST 请求添加以下标头:
Authorization: Bearer access-token Accept: application/json
API 任务索引
本部分提供了常见 Google Health API 任务的索引以及每个任务的示例。
获取 Fitbit 或 Google 用户 ID
用户通过 Google OAuth 2.0 授予同意权限后,令牌响应不包含 Fitbit 或 Google 用户 ID。如需获取用户 ID,请调用 getIdentity 端点。getIdentity
同时返回 Fitbit 旧版用户 ID 和 Google 用户 ID。
我们建议您在用户通过 OAuth 表示同意后,立即调用 getIdentity 端点并存储这两个用户 ID。这样可在集成中实现向后和向前兼容性。
例如:
请求
GET https://health.googleapis.com/v4/users/me/identity Authorization: Bearer access-token Accept: application/json
响应
{
"name": "users/me/identity",
"legacyUserId": "A1B2C3",
"healthUserId": "111111256096816351"
}获取全天收集的当日数据或详细数据
使用特定数据类型的 list 端点可获取全天收集的日内数据或详细数据,这些数据以相应数据类型支持的间隔进行收集。
例如:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"dataSource": {
"recordingMethod": "PASSIVELY_MEASURED",
"device": {
"manufacturer": "",
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"steps": {
"interval": {
"startTime": "2026-03-04T07:05:00Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T07:06:00Z",
"endUtcOffset": "0s",
"civilStartTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 6
}
}
},
"count": "40"
}
},
...
],
"nextPageToken": "Xm5h-6L0viZxIlRuWjx5bmvy98zj85uG34tuMn16mu2pntsnZI32iqhq"
}获取协调一致的间隔数据视图
如需检索不包含重叠记录或多设备冲突的区间数据,请调用 reconcile 端点。reconcile 端点会自动对同步批次和多个记录设备中重叠的时间间隔进行去重,从而返回权威的连续数据流,适合用于呈现活动时间轴和计算时长。
如需了解关联设备为何会生成重叠的时间区间,以及 list 和 reconcile 之间的操作比较,请参阅数据管理指南。
以下示例比较了 list(返回两个重叠的记录)与 reconcile(通过返回权威记录来解决冲突)针对具有两个重叠锻炼会话的用户的响应:
原始列表
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints Authorization: Bearer access-token Accept: application/json
{
"dataPoints": [
{
"name": "users/111111256096816351/dataTypes/exercise/dataPoints/7797422996486764704",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:20:00Z",
"endTime": "2026-09-03T11:50:00Z"
},
"exerciseType": "RUNNING"
}
},
{
"name": "users/111111256096816351/dataTypes/exercise/dataPoints/4389052750481144696",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:00:00Z",
"endTime": "2026-09-03T11:30:00Z"
},
"exerciseType": "RUNNING"
}
}
]
}已协调
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints:reconcile Authorization: Bearer access-token Accept: application/json
{
"dataPoints": [
{
"dataPointName": "users/111111256096816351/dataTypes/exercise/dataPoints/7797422996486764704",
"exercise": {
"interval": {
"startTime": "2026-09-03T11:20:00Z",
"endTime": "2026-09-03T11:50:00Z"
},
"exerciseType": "RUNNING"
}
}
]
}对账通过以下方式解决冲突的会话:对记录进行去重处理并选择权威记录,而不是合成人工时间并集(例如 11:00:00Z 到 11:50:00Z)。对账后的响应会返回获胜的数据点 (7797422996486764704) 及其原始记录的间隔(11:20:00Z 到 11:50:00Z),从而保留相应会话的衡量遥测数据和指标的完整性。
过滤数据
如需检索符合特定条件(例如时间间隔、日期或观测时间)的数据点记录的特定子集,请使用 list 或 reconcile 端点以及 filter 参数。
如需详细了解相关准则、格式设置规则、验证错误和查询示例,请参阅过滤数据指南。
按数据源系列过滤
如需隔离或汇总来自特定类型来源(例如,实体穿戴式设备与手动输入)的数据,请使用 dataSourceFamily 参数。
如需详细的准则、支持的系列以及 reconcile、rollUp 和 dailyRollUp 的请求和响应示例,请参阅“过滤数据”指南中的按数据源系列过滤。
按时间段的民用开始时间过滤数据
使用 list 端点和 filter 参数按民用时间或时间间隔过滤数据。
例如:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints?filter=steps.interval.civil_start_time >= "2026-03-04T00:00:00" Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"dataSource": {
"recordingMethod": "PASSIVELY_MEASURED",
"device": {
"manufacturer": "",
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"steps": {
"interval": {
"startTime": "2026-03-04T07:05:00Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T07:06:00Z",
"endUtcOffset": "0s",
"civilStartTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 3,
"day": 4
},
"time": {
"hours": 7,
"minutes": 6
}
}
},
"count": "40"
}
...
],
"nextPageToken": "Xm5h-6L0viZxIlRuQjp5bml1bZ4ve2dhNmZvMnt4Yn7qIGQhbHN3YQ"
}按样本观测的实际时间过滤数据
使用 list 端点和 filter 参数按样本观测的实际时间过滤数据。
例如:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints?filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z" Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"name": "users/123456789/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "UNKNOWN",
"application": {
"packageName": "",
"webClientId": "",
"googleWebClientId": "google-web-client-id"
},
"platform": "GOOGLE_WEB_API"
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z",
"utcOffset": "0s",
"civilTime": {
"date": {
"year": 2026,
"month": 3,
"day": 10
},
"time": {
"hours": 10
}
}
},
"percentage": 20
}
}
"nextPageToken": ""
}按数据源系列进行过滤和汇总
数据源系列是数据源(例如智能手表、移动应用或手动输入的数据)的逻辑分组。借助此功能,您可以隔离或汇总来自特定类型来源(例如,实体穿戴式设备与手动输入)的数据。
reconcile、rollUp 和 dailyRollUp 端点均支持 dataSourceFamily 参数。传递机制取决于端点:
| 端点 (HTTP 方法) | 机制 |
|---|---|
reconcile (GET) |
以网址查询参数的形式传递 dataSourceFamily。 |
rollUp (POST) |
将 dataSourceFamily 作为 JSON 请求正文中的字段进行传递。 |
dailyRollUp (POST) |
将 dataSourceFamily 作为 JSON 请求正文中的字段进行传递。 |
支持的数据源系列
下表介绍了支持的 dataSourceFamily 值:
| 选项 | 说明 |
|---|---|
users/me/dataSourceFamilies/all-sources |
默认值。返回在所有已注册的第一方 (1P) 和第三方 (3P) 数据源中经过协调的数据点。选择此选项后,系统会返回第三方应用数据(例如智能手表步数 + 第三方应用步数 + 手机步数 + 手动输入的步数)。 |
users/me/dataSourceFamilies/google-wearables |
包括 Google 和 Fitbit 追踪器设备(例如 Fitbit 穿戴式追踪器和 Pixel Watch)记录的数据。不包括手动记录的数据和手机估算的数据。如果您的集成需要由穿戴式硬件直接记录的原始传感器遥测数据,请使用此选项。 |
users/me/dataSourceFamilies/google-sources |
包括 Google 和 Fitbit 第一方来源。这包括实体追踪器设备记录、来自“健康数据共享”的数据,以及通过第一方应用(例如 Fitbit 应用或 Google 健身)手动记录的任何数据。 |
如需从特定数据源系列获取已协调的数据流,请使用 dataSourceFamily 查询参数调用 reconcile 端点。
例如,以下 GET 请求会提取 2026-03-03 之后一天的手环记录的睡眠数据:
请求
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints:reconcile?dataSourceFamily=users/me/dataSourceFamilies/google-wearables&filter=sleep.interval.civil_end_time >= "2026-03-03" Authorization: Bearer access-token Accept: application/json
响应
{
"dataPoints": [
{
"name": "users/2515055256096816351/dataTypes/sleep/dataPoints/2724123844716220216",
"dataSource": {
"recordingMethod": "DERIVED",
"device": {
"displayName": "Charge 6"
},
"platform": "FITBIT"
},
"sleep": {
"interval": {
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s"
},
"type": "STAGES",
"stages": [
{
"startTime": "2026-03-03T20:57:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-03T20:59:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
},
{
"startTime": "2026-03-04T04:07:30Z",
"startUtcOffset": "0s",
"endTime": "2026-03-04T04:41:30Z",
"endUtcOffset": "0s",
"type": "AWAKE",
"createTime": "2026-03-04T04:43:40.937183Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
],
"metadata": {
"stagesStatus": "SUCCEEDED",
"processed": true,
"main": true
},
"summary": {
"minutesInSleepPeriod": "464",
"minutesAfterWakeUp": "0",
"minutesToFallAsleep": "0",
"minutesAsleep": "407",
"minutesAwake": "57",
"stagesSummary": [
{
"type": "AWAKE",
"minutes": "56",
"count": "12"
},
{
"type": "LIGHT",
"minutes": "198",
"count": "19"
},
{
"type": "DEEP",
"minutes": "114",
"count": "10"
},
{
"type": "REM",
"minutes": "94",
"count": "4"
}
]
},
"createTime": "2026-03-04T04:43:40.337983Z",
"updateTime": "2026-03-04T04:43:40.937183Z"
}
}
],
"nextPageToken": ""
}如需在特定时间段内汇总数据点,并将数据源限制为特定系列,请调用 rollUp 端点,并在 JSON 请求正文中传递 dataSourceFamily 字段。
以下 POST 请求查询了以小时为间隔 (3600s) 的日内步行步数,这些步数仅来自穿戴式设备:
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-07-29T00:00:00Z",
"endTime": "2026-07-29T23:59:59Z"
},
"windowSize": "3600s",
"dataSourceFamily": "users/me/dataSourceFamilies/google-wearables"
}响应
{
"rollupDataPoints": [
{
"startTime": "2026-07-29T08:00:00Z",
"endTime": "2026-07-29T09:00:00Z",
"steps": {
"countSum": "1200"
}
},
{
"startTime": "2026-07-29T09:00:00Z",
"endTime": "2026-07-29T10:00:00Z",
"steps": {
"countSum": "3450"
}
}
]
}如需汇总特定来源系列中的每日数据点,请调用 dailyRollUp 端点并在请求正文中传递 dataSourceFamily 字段。
例如,以下请求会计算用户步数的每日汇总数据,包括所有第一方 Google 和 Fitbit 数据源(穿戴式设备 + 手动输入的数据):
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"start": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 7,
"day": 30
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
}
},
"windowSizeDays": 1,
"dataSourceFamily": "users/me/dataSourceFamilies/google-sources"
}响应
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 28
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "8430"
}
},
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 7,
"day": 29
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "11245"
}
}
]
}汇总一段时间范围内的数据点
使用 rollUp 端点可根据以秒为单位的时间窗口,在 datetime 范围内(基于用户的实际时间 [以 UTC 为单位])返回数据点的汇总信息。
调用 rollUp 端点时,请提供表示所需时间范围和 windowSize 的请求正文。请注意以下有关 windowSize 的要求:
- 最小窗口大小:
windowSize时长必须至少为 1 秒 ("1s")。如果时长不足 1 秒、为零或为负,系统会拒绝该请求并返回400 Bad Request(INVALID_ROLLUP_WINDOW)。 - 存储分辨率对齐:为避免汇总数据在子存储桶中分布不均,请选择一个等于或大于数据类型的基础存储分辨率的
windowSize(例如,对于 1 分钟步长间隔,请选择"60s")。如需了解详情,请参阅汇总窗口大小和底层存储分辨率。
例如,如需以 1 分钟的时间间隔汇总步数 (60s):
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:rollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"startTime": "2026-02-17T17:00:00Z",
"endTime": "2026-02-17T17:59:59Z"
},
"windowSize": "60s"
}响应
{
"rollupDataPoints": [
{
"startTime": "2026-02-17T17:55:00Z",
"endTime": "2026-02-17T17:56:00Z",
"steps": {
"countSum": "72"
}
},
{
"startTime": "2026-02-17T17:54:00Z",
"endTime": "2026-02-17T17:55:00Z",
"steps": {
"countSum": "85"
}
},
...
]
}汇总单日或多日的数据
如果您想汇总单日或多日(即 windowSize)的数据,应使用 dailyRollUp 端点。在请求正文中提供所需时间段的半开半闭民用时间范围。根据数据类型的不同,您将收到相应时间间隔内的总和或平均值。
例如:
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints:dailyRollUp
Authorization: Bearer access-token
Accept: application/json
{
"range": {
"start": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 0,
"minutes": 0,
"seconds": 0,
"nanos": 0
}
},
"end": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59,
"nanos": 0
}
}
},
"windowSizeDays": 1
}响应
{
"rollupDataPoints": [
{
"civilStartTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 2,
"day": 26
},
"time": {
"hours": 23,
"minutes": 59,
"seconds": 59
}
},
"steps": {
"countSum": "3822"
}
}
]
}当范围不是窗口大小的倍数时的分桶
如果所请求的范围不是 windowSize(或 windowSizeDays)的精确倍数,则按时间顺序排列的最后一个分桶将在范围的上限端点处截断,并且涵盖的时长将短于窗口大小。该 API 会接受您的请求,而不会进行任何修改,也不会执行任何舍入、时间偏移或数据插值。
为了涵盖整个请求范围,API 使用向上取整除法来计算汇总窗口总数:
Number of windows = ceiling(Range duration / Window size)
每个分桶都从范围的开头按顺序开始。如果添加另一个全尺寸窗口会超出您请求的结束时间,则最终窗口会在范围结束时间被截断(限制)。
分桶的工作原理
当请求具有不可分割范围的汇总时,API 会应用以下规则:
- 分桶从请求范围的开头(
range.startTime或range.start)开始,并按窗口大小(windowSize或windowSizeDays)向前推进。 - 最后一个按时间顺序排列的分桶会固定在所请求范围的末尾(
range.endTime或range.end),这意味着它涵盖的时间段比所请求的时间窗口大小短。 - 返回的
RollupDataPoint或DailyRollupDataPoint对象会明确指定自己的开始和结束时间戳,您可以使用这些时间戳来检查截断的分桶的实际时长。 - 由于 API 会按反向时间顺序(由新到旧)返回汇总数据,因此最终的时间顺序分桶(即截断的分桶)会显示为返回列表中的第一个元素 (
index 0)。
场景:12 分钟的范围,5 分钟的窗口
假设客户端请求在 12 分钟范围内汇总数据,并指定 5 分钟的 windowSize:
range.startTime:10:00:00range.endTime:10:12:00(总时长:12 分钟)windowSize:5 minutes
由于 12 分钟不是 5 分钟的倍数(12 = 5 * 2 + 2),因此 API 会接受请求并将窗口数计算为 ceiling(12 / 5) = 3。
这会生成以下三个按时间顺序排列的分桶:
- 分桶 1:
[10:00:00, 10:05:00)- 时长:5 分钟(完整窗口) - 分桶 2:
[10:05:00, 10:10:00)- 时长:5 分钟(完整窗口) - 存储分区 3(截断):
[10:10:00, 10:12:00)- 时长:2 分钟(在range.endTime处截断)
对汇总值的影响
由于最后一个时间段的时长较短,因此累加指标(例如步数总和或步数)在截断的时间段内会因时间轨道较短而降低。
如果用户在整个 12 分钟的时间范围内以每分钟 100 步的稳定速度行走:
- 第 1 组(10:00-10:05):500 步(5 分钟 × 100 步/分钟)
- 第 2 组(10:05-10:10):500 步(5 分钟 × 100 步/分钟)
- 第 3 个时间段(10:10-10:12):200 步(2 分钟 × 100 步/分钟)
显示排序的 API 响应示例
由于 API 会按时间逆序返回结果,因此截断的存储分区会显示为返回列表中的第一个元素:
{
"rollupDataPoints": [
{
"startTime": "2026-08-20T10:10:00Z",
"endTime": "2026-08-20T10:12:00Z",
"steps": {
"countSum": "200"
}
},
{
"startTime": "2026-08-20T10:05:00Z",
"endTime": "2026-08-20T10:10:00Z",
"steps": {
"countSum": "500"
}
},
{
"startTime": "2026-08-20T10:00:00Z",
"endTime": "2026-08-20T10:05:00Z",
"steps": {
"countSum": "500"
}
}
]
}
汇总窗口大小和底层存储分辨率
虽然 rollUp 端点接受任何 1 秒或更长的 windowSize,但不同的数据类型会以不同的采样率或间隔时长在底层存储空间中记录和持久保留测量结果。例如,可穿戴设备身体活动指标(如 steps、distance、active-minutes 和 active-energy-burned)通常以 1 分钟 (60s) 为间隔记录。
在汇总区间数据类型时,rollUp 端点会将每个记录的数据点放入包含该数据点 startTime 的桶中。该 API 不会跨子区间分桶对区间数据进行切分、插值或分布。
如果您指定的 windowSize 小于底层数据存储间隔(例如,请求 10 秒的窗口,但 steps 的存储间隔为 1 分钟):
- 与相应时间段的
startTime(例如,10:00:00到10:00:10)匹配的第一个子存储桶会接收整个分钟的累计数量(例如,相应分钟内记录的所有 100 个步数)。 - 同一分钟内的其余子分桶(
10:00:10至10:00:20、10:00:20至10:00:30等)不会收到任何数据点,因为在这些窗口内没有开始任何间隔。
这会导致数据出现“尖峰”,即整个时间间隔的值都集中在第一个子窗口中。
为了获得均匀分布且有意义的汇总数据,请始终将 windowSize 设置为等于或大于目标数据类型的底层存储分辨率的持续时间(例如,对于 steps,设置为 60s 或更长时间)。如需了解每种数据类型的存储分辨率和建议的最小汇总窗口,请参阅 Google 健康数据 API 数据类型参考文档。
更新用户的健康数据
使用 patch 端点更新用户的健康数据。
patch 端点会根据请求网址中指定的标识符更新现有记录。提供之前插入的数据点的标识符。该 API 会覆盖现有记录。
数据点的时间段时间戳(startTime 和 endTime)也可以由记录的所有者更新,或从健康数据共享等上游平台传播。如需详细了解时间戳的可变性,请参阅数据管理指南。如需查看更新间隔时间戳的示例,请参阅更新现有数据的间隔时间戳。
何时使用数据点标识符
在以下情况下,数据点标识符至关重要:
- 有针对性的更新:如需更新特定衡量指标,请在
patch请求中提供相应标识符。 - 删除:保留标识符可让您的应用稍后使用
batchDelete端点删除记录。
以下示例展示了用户如何更新“Scales R Us”公司生产的“HumanScale”体重秤上的体脂读数。用户在 2026 年 3 月 10 日测得的新体脂率为 20%:
请求
PATCH https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints/1234567890
Authorization: Bearer access-token
Content-Type: application/json
{
"name": "users/me/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"device": {
"formFactor": "SCALE",
"manufacturer": "Scales R Us",
"displayName": "HumanScale"
}
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z"
},
"percentage": 20
}
}响应
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.DataPoint",
"name": "users/123456789/dataTypes/body-fat/dataPoints/1234567890",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"device": {
"formFactor": "SCALE",
"manufacturer": "Scales R Us",
"displayName": "HumanScale"
},
"application": {
"googleWebClientId": "618308034039.apps.googleusercontent.com"
},
"platform": "GOOGLE_WEB_API"
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z"
},
"percentage": 20
}
}
}更新现有数据的时间间隔时间戳
如需更新现有区间数据点的 startTime 或 endTime,请向相应数据点的资源 URI 发送 PATCH 请求。只有记录的原始创建者或所有者才能修改其字段。应用无法修改其未创建的数据点。
如需了解时间戳可变性、来自健康数据共享的上游更新和缓存影响的背景信息,请参阅数据管理指南。
以下示例展示了所有者应用如何使用 patch 端点更新现有水分补充日志的间隔时间戳:
请求
PATCH https://health.googleapis.com/v4/users/me/dataTypes/hydration-log/dataPoints/4093039283164890826
Authorization: Bearer access-token
Content-Type: application/json
{
"hydrationLog": {
"interval": {
"startTime": "2026-09-03T10:05:00Z",
"endTime": "2026-09-03T10:19:59Z"
},
"amountConsumed": {
"milliliters": 350
}
}
}响应
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
"name": "users/111111256096816351/dataTypes/hydration-log/dataPoints/4093039283164890826",
"hydrationLog": {
"interval": {
"startTime": "2026-09-03T10:05:00Z",
"endTime": "2026-09-03T10:19:59Z",
"civilStartTime": {
"date": {
"year": 2026,
"month": 9,
"day": 3
},
"time": {
"hours": 10,
"minutes": 5
}
},
"civilEndTime": {
"date": {
"year": 2026,
"month": 9,
"day": 3
},
"time": {
"hours": 10,
"minutes": 19,
"seconds": 59
}
}
},
"amountConsumed": {
"milliliters": 350
}
}
}
}记录食物
如需记录食物,请向 nutrition-log dataPoints 端点发送 POST 请求。请求正文包含一个具有 nutritionLog 对象的 DataPoint。
如需了解详情,请参阅营养指南。
例如:
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/nutrition-log/dataPoints
Authorization: Bearer access-token
Content-Type: application/json
{
"nutritionLog": {
"interval": {
"startTime": "2026-06-16T12:00:00Z",
"endTime": "2026-06-16T12:30:00Z"
},
"foodDisplayName": "Banana",
"mealType": "LUNCH",
"energy": {
"kcal": 105
},
"totalCarbohydrate": {
"grams": 27
},
"totalFat": {
"grams": 0.3
}
}
}响应
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
"name": "users/123456789/dataTypes/nutrition-log/dataPoints/567890",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"platform": "GOOGLE_WEB_API"
},
"nutritionLog": {
"interval": {
"startTime": "2026-06-16T12:00:00Z",
"startUtcOffset": "0s",
"endTime": "2026-06-16T12:30:00Z",
"endUtcOffset": "0s"
},
"energy": {
"kcal": 105
},
"totalCarbohydrate": {
"grams": 27
},
"totalFat": {
"grams": 0.3
},
"mealType": "LUNCH",
"foodDisplayName": "Banana"
}
}
}删除用户健康数据
使用 batchDelete 方法可删除用户的 Fitbit 应用数据数组。
以下示例展示了用户之前在体重秤上记录了体脂,但现在想要删除该记录的情况。使用原始插播操作中的 user-id 和 data-point-id:
请求
POST https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints:batchDelete
Authorization: Bearer access-token
Accept: application/json
content-length: 93
{
"names": [
"users/123456789/dataTypes/body-fat/dataPoints/1234567890"
]
}响应
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.BatchDeleteDataPointsResponse"
}
}查找设备信息
使用 list 端点可检索与用户账号配对的设备列表。这包括设备型号信息 (deviceVersion) 以及设备上次与 Google Health 移动应用同步的时间 (lastSyncTime)。
列表配置和同步信息有助于排查同步问题或提取自上次同步时间以来的历史数据。
例如:
请求
GET https://health.googleapis.com/v4/users/me/pairedDevices Authorization: Bearer access-token Accept: application/json
响应
{
"pairedDevices": [
{
"name": "users/me/pairedDevices/123456",
"deviceType": "TRACKER",
"batteryStatus": "High",
"batteryLevel": 88,
"lastSyncTime": "2026-03-04T07:05:00Z",
"deviceVersion": "Charge 6",
"macAddress": "00:11:22:33:44:55",
"features": [
"STEPS",
"HEART_RATE"
]
}
]
}查询历史数据
Google Health API 的核心优势之一是能够长时间跟踪用户的表现并监控其健康指标。您可以查询用户自开始记录数据以来的所有数据;该 API 不会对应用可使用的历史数据量施加任何限制。
不过,查询历史数据仍受标准速率限制的约束。为了管理系统稳定性和防止过多的载荷,Google Health API 使用自动分页功能,并为每个端点设置了特定的页面大小。请注意以下边界和行为:
- 自动分页:如果您查询的数据时间跨度较长,API 将仅返回第一页结果(最多为相应端点的页面大小上限),以及
nextPageToken。您必须使用nextPageToken来请求后续页面。 - 可变页面大小:上限取决于端点和数据类型。对于大多数数据类型,页面大小上限为 10,000。
不过,对于某些数据类型(例如
exercise和sleep),默认和最大页面大小上限为 25。例如,如果客户端请求过去 10 年的所有睡眠数据,API 仍只会返回第一页上的 25 个睡眠会话。 - 汇总日期范围限制:对于数据汇总和聚合端点(例如
rollUp和dailyRollUp),查询日期范围会根据数据类型受到限制:calories-in-heart-rate-zone、heart-rate、active-minutes和total-calories的最长范围为 14 天。- 所有其他汇总数据类型的最长范围为 90 天。
根据应用所需的历史数据量,检索整个数据集需要按顺序翻阅各个页面。在设计应用的数据同步流程时,请谨记这一点。
为确保最佳性能并避免 API 错误,请在查询历史数据时遵循以下准则:
分阶段数据同步(热加载与冷加载)
- 初始“热”加载:在主要加载序列期间,仅提取并呈现最近 7-14 天的数据。这样可确保用户立即看到数据,而无需等待长时间运行的查询。
- 后台“冷”加载:在主要界面呈现后,将较旧的历史数据检索委托给异步的低优先级队列或后台进程。
针对聚合的查询分块
- 由于汇总和每日汇总端点强制执行最长日期范围限制(14 天或 90 天,具体取决于数据类型),因此您必须将大型历史汇总查询分解为较小的连续时间间隔,以符合这些限制。
- 安全地批量处理或按顺序处理这些子查询,以遵守并发限制并保持稳定的界面进度指示器。
利用预汇总的汇总数据
重构概览信息中心和趋势图表,以使用预先汇总的摘要端点(例如 DailyRollUpDataPoints)。这将大幅减少后端计算开销和客户端网络传输时间。
弹性错误处理(智能重试)
- 遇到速率限制 (
429 Too Many Requests) 和服务器网关超时 (504 Gateway Timeout) 时,请实现严格的指数退避算法处理。切勿立即重试失败的大型载荷。即时重试会加剧后端拥塞,并导致系统性能进一步下降。