This page provides an overview of REST API conventions, along with an index of common Google Health API tasks and examples of each.
REST API conventions
The Google Health API follows the Google API Improvement Proposals (AIP) standards, specifically AIP-127 (HTTP and gRPC Transcoding) and AIP-131 through AIP-135 (Standard Methods). These standards define how data is mapped from a proto message to an HTTP request.
Query parameters
Query parameters are used when the data is part of the URL. This is primarily
for GET requests (fetching a resource) or LIST requests
(filtering/pagination), but is also used for DELETE operations.
- Placement: Appended to the URL after a
?. - Syntax: Key-value pairs separated by
&. - Mapping: Every field in the request message that is not part of the URL path template is mapped to a query parameter.
- Best For: Simple types (strings, ints, enums) and repeated fields.
Example syntax:
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"
Request body
The request body is used when the data modifies the state of a resource or is
too large for a URL. The body is usually a JSON representation of the resource
itself. Typically used for POST, PATCH, and PUT operations.
- Placement: Inside the HTTP payload (not visible in the URL).
- Syntax: Formatted as a JSON object.
- Mapping: Defined in the
google.api.httpannotation.body: "*"means the entire message is the body.body: "resource_name"means only a specific field in the proto is the body.
- Best For: Complex objects, nested messages, and sensitive data.
Example syntax:
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"
}The hybrid case
In an AIP-134 compliant Update method, or a PATCH operation, both are used.
The URL contains the
resource name, the body contains the updated resource data, and a query
parameter (usually update_mask) specifies which fields to change.
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
Content-Type: application/json
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}
Key differences at a glance
| Feature | Query Parameters | Request Body |
|---|---|---|
| AIP Guidance | Used for searching, filtering, and read operations. | Used for write operations. |
| Visibility | Visible in browser history and server logs. | Hidden from the URL. |
| Complexity | Limited to flat or repeated structures. | Supports deeply nested JSON objects. |
| Encoding | Must be URL-encoded (for example, spaces become %20). |
Standard JSON encoding. |
Dates
All dates in the Google Health API are displayed in the format YYYY-MM-DD. The
Nutrition API supports the ISO-8601 standard for date values with the following
conditions:
- A 4-digit year
YYYY - Year values within the range of 0000-9999
- No enforcement of start date restrictions implied by the ISO-8601 standard or other epoch
Headers
Executing the Google Health API endpoints requires using the appropriate headers and access token. The following header is recommended for both GET and POST requests:
Authorization: Bearer access-token Accept: application/json
API task index
This section provides an index of common Google Health API tasks and examples of each.
Get the Fitbit or Google user ID
After a user consents through Google OAuth 2.0, the token response does not
contain the Fitbit or Google user ID. To obtain the user ID, call the
getIdentity endpoint. getIdentity
returns both the Fitbit legacy user ID and the Google user ID.
We recommend that as soon as a new user consents through OAuth, you call the
getIdentity endpoint and store both user IDs. This provides backward and
forward compatibility in your integration.
For example:
Request
GET https://health.googleapis.com/v4/users/me/identity Authorization: Bearer access-token Accept: application/json
Response
{
"name": "users/me/identity",
"legacyUserId": "A1B2C3",
"healthUserId": "111111256096816351"
}Get intraday or detailed data collected throughout a day
Use the list
endpoint for a specific
data type to get intraday or detailed data collected throughout the day in
supported intervals for that data type.
For example:
Request
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints Authorization: Bearer access-token Accept: application/json
Response
{
"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"
}Filter data by an interval civil start time
Use the list endpoint with a filter parameter to filter data by civil time
or an interval.
For example:
Request
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
Response
{
"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"
}Filter data by a sample observation physical time
Use the list endpoint with a filter parameter to filter data by sample
observation physical time.
For example:
Request
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
Response
{
"dataPoints": [
{
"name": "users/2515055256096816351/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": ""
}Filter data by data sources such as wearables
Use the reconcile
endpoint to get
data by a "data source family" in a reconciled stream.
Here's an example of filtering only the tracker-recorded sleep for the day after 2026-03-03:
Request
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
Response
{
"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": ""
}Aggregate data points over a range of time
Use the rollUp
endpoint to return the
aggregate of data points based on a window in seconds, over the datetime range
based on the users physical time (in UTC).
When calling the rollUp endpoint, you must provide the request body
representing the required date range in the user's civil time. For example:
Request
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": "30s"
}Response
{
"rollupDataPoints": [
{
"startTime": "2026-02-17T17:55:00Z",
"endTime": "2026-02-17T17:55:30Z",
"steps": {
"countSum": "41"
}
},
{
"startTime": "2026-02-17T17:54:00Z",
"endTime": "2026-02-17T17:54:30Z",
"steps": {
"countSum": "31"
}
},
...
]
}Aggregate data across a single day or multiple days
The dailyRollUp
endpoint should be
used when you want to aggregate data across
a single day or multiple days, known as windowSize. Provide the closed-open
civil time range for the required interval in the request body. Depending on the
data type, you will either receive the sum or the average over the interval.
For example:
Request
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
}Response
{
"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"
}
}
]
}Insert or update a user's health data
Use the patch
endpoint to insert or
update a user's Fitbit app data.
Here's an example where a user recorded their body fat on a scale called "HumanScale" from the company "Scales R Us". The user's new body fat reading is 20% for the date of 2026-03-10.
Request
PATCH https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints/1234567890
Authorization: Bearer access-token
content-length: 329
{
"name": "bodyFatName",
"dataSource": {
"recordingMethod": "ACTIVELY_MEASURED",
"device": {
"formFactor": "SCALE",
"manufacturer": "Scales R Us",
"displayName": "HumanScale"
}
},
"bodyFat": {
"sampleTime": {
"physicalTime": "2026-03-10T10:00:00Z"
},
"percentage": 20
}
}Response
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.DataPoint",
"name": "users/2515055256096816351/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
}
}
}Delete user health data
Use the batchDelete
endpoint to delete
an array of a user's Fitbit app data.
Here's an example where a user previously recorded their body fat on a scale, but they want to delete the record. Using the user-id and data-point-id from the original insert action:
Request
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/2515055256096816351/dataTypes/body-fat/dataPoints/1234567890"
]
}Response
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4main.BatchDeleteDataPointsResponse"
}
}