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)](https://google.aip.dev/)
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](https://developers.google.com/health/filters).

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.http` annotation.
  - `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](https://developers.google.com/health/aggregate-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. Call the
[`getIdentity` endpoint](https://developers.google.com/health/reference/rest/v4/users/getIdentity) 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](https://developers.google.com/health/troubleshooting#412-precondition-failed)).

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](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/list) for a specific
data type to get intraday or detailed data collected throughout the day in
supported intervals for that data type.

> [!NOTE]
> **Note:** When connected devices sync, on-device algorithms can re-bucket telemetry and upload new records with overlapping boundaries. To retrieve a deduplicated, reconciled view of interval data, see [Get a reconciled view of interval data](https://developers.google.com/health/endpoints#get-reconciled-view). For background on connected device synchronization and an operational comparison between `list` and `reconcile`, see the [Data management guide](https://developers.google.com/health/data-management#interval-timestamps).

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](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/reconcile). 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](https://developers.google.com/health/data-management#interval-timestamps).

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](https://developers.google.com/health/filters).

### 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](https://developers.google.com/health/filters#filter-by-data-source)
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.

<br />

**Important:** The format of data type identifiers differs when the data type has more than one word. In an endpoint, the data type name must be in kebab case, such as `body-fat`. In a filter parameter, however, the data type name must be in snake case, such as `body_fat`.

<br />

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.

<br />

**Important:** The format of data type identifiers differs when the data type has more than one word. In an endpoint, the data type name must be in kebab case, such as `body-fat`. In a filter parameter, however, the data type name must be in snake case, such as `body_fat`.

<br />

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). |

> [!IMPORTANT]
> **Important:** You must specify the `dataSourceFamily` parameter using the full resource URI format, such as `users/me/dataSourceFamilies/google-wearables`. Short identifier strings (like `"google-wearables"`, `"wearables"`, or `"FITBIT"`) are invalid and cause the API to return a `400 Bad Request` with an `INVALID_ARGUMENT` error.

<br />

**Important:** The format of data type identifiers differs when the data type has more than one word. In an endpoint, the data type name must be in kebab case, such as `body-fat`. In a filter parameter, however, the data type name must be in snake case, such as `body_fat`.

<br />

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](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/rollUp) 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 request and response examples, see
[Aggregate over physical time intervals](https://developers.google.com/health/aggregate-data#aggregate) in
the Aggregate data guide.

### Aggregate data across a single day or multiple days

Use the [`dailyRollUp`
endpoint](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/dailyRollUp) 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 each window.

For details on daily aggregation behavior, civil time handling, per-request
range limits, and request and response examples, see
[Aggregate across calendar days](https://developers.google.com/health/aggregate-data#aggregate-by-day) in
the Aggregate data guide.

### Update a user's health data

Use the
[`patch` endpoint](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/patch) 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.

> [!NOTE]
> **Note:** `PATCH` cannot be used to create new records. To insert a new record, see [Log a food item](https://developers.google.com/health/endpoints#log-food-item) for an example of using the `POST` method.

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](https://developers.google.com/health/data-management#timestamp-mutability). For an
example of updating interval timestamps, see
[Update interval timestamps for existing data](https://developers.google.com/health/endpoints#update-interval-timestamps).

#### 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 `patch` request.
- **Deletions:** Retaining the identifier allows your application to delete the record later using the [`batchDelete` endpoint](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/batchDelete).

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](https://developers.google.com/health/data-management#timestamp-mutability).

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](https://developers.google.com/health/data-types/nutrition).

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](https://developers.google.com/health/reference/rest/v4/users.dataTypes.dataPoints/batchDelete) 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 <var translate="no">user-id</var> and
<var translate="no">data-point-id</var> 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](https://developers.google.com/health/reference/rest/v4/users.pairedDevices/list) 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](https://developers.google.com/health/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 the `nextPageToken` to 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 `exercise` and `sleep`, 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 `rollUp` and `dailyRollUp`), 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`, and `total-calories`.
  - A maximum range of 90 days for all other rollup data types.

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.

> [!WARNING]
> **Warning:** Not following these guidelines can introduce
> unexpected behavior and errors.