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 for a specific "data source family". To do this, specify the
dataSourceFamily parameter as a query parameter.
The following table describes the supported dataSourceFamily options:
| Option | Description |
|---|---|
users/me/dataSourceFamilies/all-sources |
Default value. Includes data from all available data sources. |
users/me/dataSourceFamilies/google-wearables |
Includes data from Google and Fitbit tracker devices (such as Fitbit trackers and Pixel Watch). Excludes manually logged data. |
users/me/dataSourceFamilies/google-sources |
Includes first-party Google data, such as data from tracker devices and manually logged data. |
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
}
}
}Log a food item
To log a food item, send a POST request to the nutrition-log data points
endpoint. The request body contains a DataPoint with a nutritionLog object.
For more information, see the Nutrition guide.
For example:
Request
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
}
}
}Response
{
"done": true,
"response": {
"@type": "type.googleapis.com/google.devicesandservices.health.v4.DataPoint",
"name": "users/2515055256096816351/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"
}
}
}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"
}
}Find device information
Use the list endpoint to
retrieve the list of devices paired to a user's account. This includes the
device's model information (deviceVersion) and the last time it synchronized
with the Google Health mobile app (lastSyncTime).
The list configuration and sync information is useful for troubleshooting syncing issues or fetching historical data since the last sync time.
For example:
Request
GET https://health.googleapis.com/v4/users/me/pairedDevices Authorization: Bearer access-token Accept: application/json
Response
{
"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"
]
}
]
}Query historical data
One of the core benefits of the Google Health API is the ability to track a user's performance and monitor their health vitals over long periods of time. You can query a user's data as far back as it has been recorded; the API imposes no limitations or restrictions on the amount of historical data your application can consume.
However, querying historical data is still governed by standard rate limits. To manage system stability and prevent excessive payloads, the Google Health API uses automatic pagination with endpoint-specific page sizes. Note the following boundaries and behavior:
- Automatic pagination: If you query a long span of data, the
API will only return the first page of results up to the page size cap for that
endpoint, along with a
nextPageToken. You must use thenextPageTokento request subsequent pages. - Variable page sizes: Capping limits depend on the endpoint
and data type. For most data types, page sizes are capped at a maximum of 10,000.
However, for certain data types like
exerciseandsleep, the default and maximum page size is capped at 25. For example, if a client requests all sleep data for the past 10 years, the API will still return only 25 sleep sessions on the first page. - Rollup date range restrictions: For data rollup and aggregation endpoints
(such as
rollUpanddailyRollUp), query date ranges are restricted based on the data type:- A maximum range of 14 days for
calories-in-heart-rate-zone,heart-rate,active-minutes, andtotal-calories. - A maximum range of 90 days for all other rollup data types.
- A maximum range of 14 days for
Depending on the volume of historical data your application needs, retrieving the entire dataset will require paginating through the pages sequentially. Keep this in mind when designing your application's data synchronization process.
To ensure optimal performance and avoid API errors, follow these guidelines when querying historical data:
Phased data sync (hot versus cold load)
- Initial "hot" load: Fetch and render only the most recent 7–14 days of data during the primary load sequence. This ensures that users see data immediately without waiting for long-running queries.
- Background "cold" load: Delegate older historical data retrieval to an asynchronous, lower-priority queue or background process after the primary UI is rendered.
Query chunking for aggregation
- Because rollup and daily rollup endpoints enforce a maximum date range limit (14 or 90 days depending on the data type), you must break down large historical aggregation queries into smaller, sequential intervals within these limits.
- Batch or sequence these sub-queries safely to respect concurrency limits and maintain steady UI progress indicators.
Leverage pre-aggregated roll-ups
Restructure overview dashboards and trend charts to use pre-aggregated,
summary endpoints (such as DailyRollUpDataPoints). This will
drastically reduce compute overhead on the backend and network transfer time to
the client.
Resilient error handling (smart retries)
- Implement strict exponential backoff handling when encountering rate
limits (
429 Too Many Requests) and server gateway timeouts (504 Gateway Timeout). Never retry large, failed payloads immediately. Instant retries multiply backend congestion and compound system degradation.