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.
For a detailed list of filter formats, field references, validation rules, and examples, see the Filter data guide.
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.
For detailed guidelines on rollup window sizes, bucketing rules, and aggregation examples, see the Aggregate data guide.
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. Call the
getIdentity endpoint immediately
after exchanging the authorization code to retrieve both legacyUserId and
healthUserId and verify that the user's Google Account is linked to Google
Health. If the account is not yet linked, getIdentity returns 400 Bad
Request with reason ACCOUNT_NOT_LINKED (see
Handle unlinked Google Accounts).
For example:
Request
GET https://health.googleapis.com/v4/users/me/identity Authorization: Bearer access-token Accept: application/json
Response (200 OK)
{
"name": "users/me/identity",
"legacyUserId": "A1B2C3",
"healthUserId": "111111256096816351"
}Response (400 ACCOUNT_NOT_LINKED)
{
"error": {
"code": 400,
"message": "The account is not linked to Google Health.",
"status": "FAILED_PRECONDITION",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "ACCOUNT_NOT_LINKED",
"domain": "health.googleapis.com",
"metadata": {
"redirect_uri": "https://fitbit.google.com/auth/signup"
}
}
]
}
}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"
}Get a reconciled view of interval data
To retrieve interval data without overlapping records or multi-device conflicts,
call the reconcile
endpoint. The
reconcile endpoint automatically deduplicates overlapping intervals across sync
batches and multiple recording devices, returning an authoritative, continuous
stream suitable for rendering activity timelines and calculating durations.
For background on why connected devices produce overlapping intervals and an
operational comparison between list and reconcile, see the
Data management guide.
The following example compares the response of list (which returns both
overlapping records) versus reconcile (which resolves the conflict by
returning the authoritative record) for a user with two overlapping exercise
sessions:
Raw list
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"
}
}
]
}Reconciled
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"
}
}
]
}Reconciliation resolves conflicting sessions by deduplicating and selecting the
authoritative record rather than synthesizing an artificial time union (such as
11:00:00Z to 11:50:00Z). The reconciled response returns the winning data
point (7797422996486764704) with its original recorded interval (11:20:00Z
to 11:50:00Z), preserving the integrity of that session's measured telemetry
and metrics.
Filter data
To retrieve specific subsets of data point records matching criteria such as a
time interval, date, or observation time, use the list or reconcile endpoint
with a filter parameter.
For detailed guidelines, formatting rules, validation errors, and query examples, see the Filter data guide.
Filter by data source family
To isolate or aggregate data from specific types of sources (for example,
physical wearable devices versus manual entries), use the dataSourceFamily
parameter.
For detailed guidelines, supported families, and request and response examples
for reconcile, rollUp, and dailyRollUp, see
Filter by data source family
in the Filter data guide.
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/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": ""
}Filter and aggregate by data source family
A data source family is a logical grouping of data sources (such as smartwatches, mobile apps, or manual entries). It allows you isolate or aggregate data from specific types of sources (for example, physical wearable devices versus. manual entries).
The reconcile, rollUp, and dailyRollUp endpoints all support the
dataSourceFamily parameter. The passing mechanism depends on the endpoint:
| Endpoint (HTTP method) | Mechanism |
|---|---|
reconcile (GET) |
Pass dataSourceFamily as a URL query parameter. |
rollUp (POST) |
Pass dataSourceFamily as a field in the JSON request body. |
dailyRollUp (POST) |
Pass dataSourceFamily as a field in the JSON request body. |
Supported Data Source Families
The following table describes the supported dataSourceFamily values:
| Option | Description |
|---|---|
users/me/dataSourceFamilies/all-sources |
Default value. Returns data points reconciled across all registered first-party (1P) and third-party (3P) data sources. Third-party app data will be returned with this option (such as smartwatch steps + third-party app steps + mobile phone steps + manual steps). |
users/me/dataSourceFamilies/google-wearables |
Includes data recorded by Google and Fitbit tracker devices (such as Fitbit wearable trackers and Pixel Watch). Excludes manually logged data and phone-estimated data. Use this option when your integration requires raw sensor telemetry recorded directly by wearable hardware. |
users/me/dataSourceFamilies/google-sources |
Includes first-party Google and Fitbit sources. This includes physical tracker device records, data from Health Connect, and any manual entries logged through first-party apps (such as the Fitbit app or Google Fit). |
To get a reconciled data stream from a specific data source family, call the
reconcile endpoint with the dataSourceFamily query parameter.
For example, the following GET request fetches 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": ""
}To aggregate data points over a specific window size restricted to a particular
data source family, call the rollUp endpoint and pass the dataSourceFamily
field in the JSON request body.
The following POST request queries intraday walking step counts in hourly
intervals (3600s), aggregated exclusively from wearable devices:
Request
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"
}Response
{
"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"
}
}
]
}To aggregate daily data points for a specific source family, call the
dailyRollUp endpoint and pass the dataSourceFamily field in the request
body.
For example, the following request calculates the daily rollups for the user's steps, including all first-party Google and Fitbit sources (wearables + manual entries):
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": 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"
}Response
{
"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"
}
}
]
}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 (windowSize), over a
datetime range in the user's physical time (in UTC).
When calling the rollUp endpoint, provide the request body representing the
required closed-open time range and windowSize (at least "1s"). For
detailed guidelines on windowSize requirements, storage resolution alignment,
bucketing rules, and response ordering, see
Aggregate over physical time intervals in
the Aggregate data guide.
For example, to roll up step counts in 1-minute intervals (60s):
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": "60s"
}Response
{
"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"
}
},
...
]
}Aggregate data across a single day or multiple days
Use the dailyRollUp
endpoint to
aggregate data across a single day or multiple days (windowSizeDays). Provide
the closed-open civil time range for the required interval in the request body.
Depending on the data type, the endpoint returns either the sum or the average
over the interval.
For details on daily aggregation behavior, civil time handling across time zones, and bucketing rules, see Aggregate across calendar days in the Aggregate data guide.
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"
}
}
]
}Bucketing when range is not a multiple of window size
If the requested range is not an exact multiple of windowSize (or
windowSizeDays), the API uses ceiling division to compute the number of
windows and clamps the final chronological bucket at the upper endpoint of the
range. Because rollup responses are returned in reverse-chronological order,
this truncated bucket appears as the first element (index 0) in the returned
list.
For the bucketing formula, non-divisible range truncation examples, and guidance on normalizing additive metrics, see Bucketing when range is not a multiple of window size in the Aggregate data guide.
Rollup window and storage resolution
When aggregating interval data types, the rollUp endpoint places each recorded
data point into the bucket containing the data point's startTime without
slicing or interpolating across sub-interval buckets. To obtain evenly
distributed aggregates, set windowSize to a duration equal to or greater than
the underlying storage resolution of the target data type (such as "60s" for
1-minute step intervals).
For underlying storage resolutions and sub-interval behavior examples, see Rollup window and storage resolution in the Aggregate data guide.
Update a user's health data
Use the
patch endpoint to
update a user's health data.
The patch endpoint updates an existing record based on the identifier
specified in the request URL. Provide the identifier of a previously inserted
data point. The API overwrites the existing record.
A data point's interval timestamps (startTime and endTime) can also
be updated by the record's owner or propagated from upstream platforms like
Health Connect. For details on timestamp mutability, see the
Data management guide. For an
example of updating interval timestamps, see
Update interval timestamps for existing data.
When to use the data point identifier
The data point identifier is essential in the following scenarios:
- Targeted updates: To update a specific measurement, provide its
identifier in the
patchrequest. - Deletions: Retaining the identifier allows your application to delete
the record later using the
batchDeleteendpoint.
Here's an example where a user updates their body fat reading 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-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
}
}Response
{
"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
}
}
}Update interval timestamps for existing data
To update the interval timestamps (startTime and endTime in REST JSON
payloads, or start_time and end_time in gRPC) of an existing data point,
send a PATCH request to the data point's resource URI. Only the original
creator or owner of a record can modify its fields. Applications cannot edit
data points they did not create.
For background on timestamp mutability, upstream updates from Health Connect, and caching implications, see the Data management guide.
The following example demonstrates an owner application updating the interval
timestamps of an existing hydration log using the patch endpoint:
Request
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
}
}
}Response
{
"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
}
}
}
}Log a food item
To log a food item, send a POST request to the nutrition-log dataPoints
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/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"
}
}
}Delete user health data
Use the batchDelete
method 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/123456789/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.