Endpoints

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

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