L'API Google Health s'appuie sur des expressions de filtre pour limiter les points de données renvoyés lors de l'appel de méthodes de récupération standards. Plus précisément, les filtres sont utilisés avec :
- Points de terminaison
list: pour interroger les points de données brutes. - Points de terminaison
reconcile: interroger les points de données de flux réconciliés.
Ce guide explique comment le filtrage est implémenté, la syntaxe et les conventions, et fournit des exemples pour chaque type d'enregistrement.
Conventions de filtrage
L'API Google Health implémente des filtres conformément à la norme Google API Improvement Proposals (AIP-160).
Paramètres de requête
Les filtres sont transmis à l'aide de la chaîne de requête de l'URL dans le paramètre filter.
Étant donné que les filtres contiennent des caractères spéciaux (tels que <, >= et des guillemets), ils doivent être encodés au format URL lorsqu'ils sont transmis dans la requête HTTP.
Par exemple, une requête avec le filtre steps.interval.civil_start_time >= "2026-03-04T00:00:00" doit être encodée comme suit :
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time%20%3E%3D%20%222026-03-04T00%3A00%3A00%22
Format de nommage
Si un type de données comporte plusieurs mots, le format de l'identifiant diffère entre le chemin d'accès à la ressource et le filtre :
- Chemin d'accès au point de terminaison : utilisez des traits d'union (par exemple,
/dataTypes/body-fat). - Chaîne de filtre : utilisez des traits de soulignement (par exemple,
body_fat).
Si vous utilisez des traits d'union dans l'identifiant de filtre, l'API renvoie un 400 Bad Request avec le motif d'erreur INVALID_DATA_POINT_FILTER.
Types et champs de filtres
Les champs que vous utilisez dans un filtre dépendent du type d'enregistrement du type de données que vous interrogez. Le tableau suivant décrit les champs compatibles pour chaque type d'enregistrement :
| Type d'enregistrement | Description | Champs de filtre acceptés |
|---|---|---|
| Intervalle | Points de données enregistrés sur une période donnée (par exemple, steps, distance, calories). |
{dataType}.interval.start_time{dataType}.interval.civil_start_time
Exemple : steps.interval.civil_start_time
|
| Sample | Observations instantanées ou mesures courtes (par exemple, weight, body-fat, blood-glucose). |
{dataType}.sample_time.physical_time{dataType}.sample_time.civil_time
Exemple : body_fat.sample_time.physical_time
|
| Tous les jours | Métriques et résumés quotidiens (par exemple, daily-heart-rate-variability). |
{dataType}.date
Exemple : daily_heart_rate_variability.date
|
| Session | Sessions utilisateur étendues avec des règles de timing spécifiques. |
Exercice : {dataType}.interval.civil_start_timeSommeil : sleep.interval.end_time, sleep.interval.civil_end_timeECG : electrocardiogram.interval.start_time
Exemple : sleep.interval.civil_end_time
|
Opérateurs et règles de format compatibles
Les expressions de filtre doivent respecter les règles de mise en forme suivantes :
Opérateurs de comparaison
Seuls deux opérateurs de comparaison sont acceptés :
| Opérateur | Description |
|---|---|
>= |
Limite inférieure (incluse). |
< |
Limite supérieure (exclusive). |
L'utilisation d'autres opérateurs de comparaison (tels que >, <= ou =) renvoie un 400 Bad Request avec INVALID_DATA_POINT_FILTER_RESTRICTION_COMPARATOR.
Opérateurs logiques
| Opérateur | Assistance |
|---|---|
AND |
Opérateur par défaut et seul opérateur accepté. Utilisé pour combiner les limites de début et de fin. |
OR |
Non compatible. L'utilisation de OR renvoie un 400 Bad Request avec le motif d'erreur INVALID_DATA_POINT_FILTER_EXPRESSION_STRUCTURE ("Le filtre doit être une conjonction ou une séquence de restrictions. Trouvé : DISJUNCTION"). |
Littéraux d'heure
Les littéraux temporels dans les expressions de filtre doivent utiliser les formats suivants :
| Type Time (heure) | Conditions requises | Exemples |
|---|---|---|
| Temps physique | Format RFC 3339, se terminant par Z ou un décalage UTC. Représente des événements réels en UTC. |
Correct : "2026-03-01T00:00:00Z", "2026-03-01T00:00:00-08:00"Incorrect : "2026-03-01" |
| Heure civile | Format ISO 8601 : YYYY-MM-DD[THH:mm:ss]. Représente l'heure sur l'horloge d'un utilisateur, indépendamment des décalages de localisation ou de fuseau horaire. |
Correct : "2026-03-01", "2026-03-01T08:30:00" |
Filtrer les règles de validation
Les filtres suivent les règles suivantes :
| Règle | Description | Exemples |
|---|---|---|
| Pas de types temporels mixtes | Ne mélangez pas les limites temporelles physiques et civiles. | Non valide : steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.civil_start_time < "2026-03-02"Erreur : INVALID_DATA_POINT_FILTER_MIXED_TIME_RESTRICTIONS ("Le filtre ne peut pas contenir à la fois des plages horaires physiques et civiles") |
| Pas de types de données mixtes | Utilisez les champs appartenant au type de données dans le chemin de la requête. | Non valide : chemin d'accès /users/.../dataTypes/steps/... avec le filtre distance.interval.start_time >= "..."Erreur : INVALID_DATA_POINT_FILTER_COLLECTION_MISMATCH ("Le type de données du filtre ne correspond pas à celui de la collection de données parent") |
| Logique d'ordre chronologique | La limite supérieure doit être supérieure à la limite inférieure. | Non valide : steps.interval.start_time >= "2026-03-02T00:00:00Z" AND steps.interval.start_time < "2026-03-01T00:00:00Z"Erreur : INVALID_TIME_RANGE ("L'heure de fin de la requête doit être strictement supérieure à l'heure de début") |
| Format de la demande | Utilisez snake case en fonction du nom du type de données. | Non valide : body-fat.sample_time.physical_time >= "..."Erreur : INVALID_DATA_POINT_FILTER ("Filtre non valide") |
L'API renvoie le code HTTP 400 Bad Request pour les filtres non valides. Consultez error.details[].metadata.detailedReasons pour connaître le code du motif de l'erreur.
Niveaux d'accès OAuth requis
Pour interroger des points de données à l'aide de filtres, l'utilisateur autorisé doit accorder le champ d'application OAuth approprié pour ce type de données. Si le champ d'application requis est manquant, l'API renvoie un état 403 Forbidden avec MISSING_OAUTH_SCOPE.
Le tableau suivant mappe les niveaux d'accès OAuth aux types de données auxquels ils accordent un accès en lecture. Le tableau affiche les niveaux d'accès dans leur format relatif (par exemple, .activity_and_fitness.readonly représente https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly) :
| Champ d'application OAuth requis | Types de données |
|---|---|
.activity_and_fitness.readonly |
active-energy-burned, active-minutes, active-zone-minutes, activity-level, altitude, calories-in-heart-rate-zone, daily-vo2-max, distance, exercise, floors, run-vo2-max, sedentary-period, steps, swim-lengths-data, time-in-heart-rate-zone, total-calories, vo2-max |
.ecg.readonly |
électrocardiogramme |
.health_metrics_and_measurements.readonly |
blood-glucose, body-fat, core-body-temperature, daily-heart-rate-variability, daily-heart-rate-zones, daily-oxygen-saturation, daily-respiratory-rate, daily-resting-heart-rate, daily-sleep-temperature-derivations, heart-rate, heart-rate-variability, height, oxygen-saturation, respiratory-rate-sleep-summary, skin-temperature-sensors, weight |
.irn.readonly |
irregular-rhythm-notification |
.nutrition.readonly |
food, food-measurement-unit, hydration-log, nutrition-log |
.sleep.readonly |
sommeil |
Si votre client ne dispose que d'un champ d'application d'écriture (tel que .activity_and_fitness.writeonly) pour un type de données demandé, vous pouvez toujours interroger les points de données écrits par votre propre client. Dans ce cas, les demandes sont implicitement limitées à la famille de sources de données self-sources. Pour en savoir plus et connaître les limites liées aux types de données, consultez Filtrer par famille de sources de données.
Cas d'utilisation et exemples
Les exemples suivants montrent comment créer des filtres pour des scénarios courants :
Interroger les étapes par plage de temps physique
Étapes de la requête enregistrées entre 2026-03-01T00:00:00Z (inclus) et 2026-03-02T00:00:00Z (exclus) :
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.start_time >= "2026-03-01T00:00:00Z" AND steps.interval.start_time < "2026-03-02T00:00:00Z"
Étapes de la requête par plage de temps civil
Requête des pas pour une journée entière, le 4 mars 2026, par rapport à l'horloge locale de l'utilisateur :
GET https://health.googleapis.com/v4/users/me/dataTypes/steps/dataPoints ?filter=steps.interval.civil_start_time >= "2026-03-04" AND steps.interval.civil_start_time < "2026-03-05"
Interroger la masse grasse par heure de prélèvement physique
Interrogez les mesures de masse grasse enregistrées à partir de mars 2026 (en UTC) :
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z"
Pondération des requêtes par heure d'échantillon civil
Journaux de pondération des requêtes enregistrés après une heure locale spécifique :
GET https://health.googleapis.com/v4/users/me/dataTypes/weight/dataPoints ?filter=weight.sample_time.civil_time >= "2026-03-01T08:00:00"
Interroger les récapitulatifs quotidiens de la variabilité de la fréquence cardiaque
Interrogez les récapitulatifs quotidiens de la variabilité de la fréquence cardiaque (VFC) enregistrés avant une date spécifique :
GET https://health.googleapis.com/v4/users/me/dataTypes/daily-heart-rate-variability/dataPoints ?filter=daily_heart_rate_variability.date < "2026-08-15"
Interroger les sessions d'exercice par heure de début civile
Interroger les séances d'exercice qui ont eu lieu au cours d'une semaine spécifique dans le fuseau horaire local de l'utilisateur :
GET https://health.googleapis.com/v4/users/me/dataTypes/exercise/dataPoints ?filter=exercise.interval.civil_start_time >= "2026-03-01" AND exercise.interval.civil_start_time < "2026-03-08"
Interroger les périodes de sommeil par heure de fin civile
Interrogez les enregistrements de sommeil par heure de fin de la période :
GET https://health.googleapis.com/v4/users/me/dataTypes/sleep/dataPoints ?filter=sleep.interval.civil_end_time >= "2026-03-04T05:00:00" AND sleep.interval.civil_end_time < "2026-03-04T12:00:00"
Interroger les électrocardiogrammes par heure de début
Interrogez les enregistrements ECG à partir d'un point temporel UTC physique. Notez que les requêtes ECG ne sont compatibles qu'avec une comparaison >= sur start_time :
GET https://health.googleapis.com/v4/users/me/dataTypes/electrocardiogram/dataPoints ?filter=electrocardiogram.interval.start_time >= "2026-03-10T12:00:00Z"
Filtrer par famille de sources de données
Une famille de sources de données est un regroupement logique de sources de données (comme les montres connectées, les applications mobiles ou les saisies manuelles). Il vous permet d'isoler ou d'agréger les données de types de sources spécifiques (par exemple, les appareils portables physiques, les saisies manuelles ou les données écrites par votre propre client).
Les points de terminaison list, reconcile, rollUp et dailyRollUp sont tous compatibles avec le paramètre dataSourceFamily. Le mécanisme de transmission dépend du point de terminaison :
| Point de terminaison (méthode HTTP) | Mécanisme |
|---|---|
list (GET) |
Transmettez dataSourceFamily en tant que paramètre de requête d'URL. |
reconcile (GET) |
Transmettez dataSourceFamily en tant que paramètre de requête d'URL. |
rollUp (POST) |
Transmettez dataSourceFamily en tant que champ dans le corps de la requête JSON. |
dailyRollUp (POST) |
Transmettez dataSourceFamily en tant que champ dans le corps de la requête JSON. |
Familles de sources de données compatibles
Le tableau suivant décrit les valeurs dataSourceFamily acceptées :
| Option | Description |
|---|---|
users/me/dataSourceFamilies/all-sources |
Valeur par défaut (lorsqu'un champ d'application de lecture est accordé). Inclut des points de données provenant de toutes les sources de données first party (1P) et tierces (3P) disponibles. Les données des applications tierces sont renvoyées avec cette option (par exemple, les pas enregistrés par une montre connectée + les pas enregistrés par une application tierce + les pas enregistrés par un téléphone mobile + les pas enregistrés manuellement). |
users/me/dataSourceFamilies/google-wearables |
Inclut les données enregistrées par les appareils de suivi Google et Fitbit (comme les bracelets d'activité Fitbit et la Pixel Watch). Exclut les données enregistrées manuellement et les données estimées par le téléphone. Utilisez cette option lorsque votre intégration nécessite des données de télémétrie brutes des capteurs enregistrées directement par le matériel wearable. |
users/me/dataSourceFamilies/google-sources |
Inclut des sources Google et Fitbit first party. Cela inclut les enregistrements des bracelets d'activité, les données de Santé Connect et toutes les saisies manuelles enregistrées dans des applications propriétaires (comme l'application Fitbit ou Google Fit). |
users/me/dataSourceFamilies/self-sources |
Inclut uniquement les données que le client appelant a écrites via l'API Google Health (points de données dont la source de données a été enregistrée via l'API avec le même ID client OAuth que l'appelant). |
Si aucun point de données ne correspond à la famille de sources de données demandée, la réponse est une liste vide plutôt qu'une erreur.
Sources internes et accès en écriture seule
Les appelants qui n'ont accès qu'aux niveaux d'accès en écriture (comme .activity_and_fitness.writeonly) pour les types de données demandés peuvent lire les données qu'ils ont écrites eux-mêmes, et uniquement ces données.
- Les requêtes sans paramètre
dataSourceFamilyexplicite ou avecdataSourceFamilydéfini surusers/me/dataSourceFamilies/self-sourcessont implicitement limitées àself-sources. - Si vous demandez une autre famille de sources de données (comme
all-sources,google-wearablesougoogle-sources) avec un champ d'application d'écriture uniquement, une erreur403 Forbidden(PERMISSION_DENIED) se produit.
Limites des types de données sur le point de terminaison de la liste
Sur le point de terminaison list (users.dataTypes.dataPoints.list), le filtrage par dataSourceFamily n'est pas compatible avec les types de données sleep, food et food-measurement-unit :
- La définition explicite de
dataSourceFamilysurlistpoursleep,foodoufood-measurement-unitéchoue et génère une erreur400 Bad Request(INVALID_ARGUMENT). - L'appel de
listpour ces types de données lorsque seul un champ d'application d'écriture est accordé (où la restriction àself-sourcesest implicite dans les champs d'application de l'appelant) échoue avec une erreur403 Forbidden(PERMISSION_DENIED). - Pour filtrer les points de données
sleeppardataSourceFamily, utilisez plutôt le point de terminaisonreconcile.
Exemples de familles de sources de données
Pour lister les points de données brutes qu'un client que vous avez écrit pour un utilisateur, appelez le point de terminaison list avec le paramètre de requête dataSourceFamily défini sur users/me/dataSourceFamilies/self-sources.
Par exemple, la requête GET suivante liste les mesures body-fat brutes écrites par le client appelant à partir du 1er mars 2026 :
Requête
GET https://health.googleapis.com/v4/users/me/dataTypes/body-fat/dataPoints ?dataSourceFamily=users/me/dataSourceFamilies/self-sources &filter=body_fat.sample_time.physical_time >= "2026-03-01T00:00:00Z" Authorization: Bearer access-token Accept: application/json
Réponse
{
"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": ""
}Pour obtenir un flux de données réconciliées à partir d'une famille de sources de données spécifique, appelez le point de terminaison reconcile avec le paramètre de requête dataSourceFamily.
Par exemple, la requête GET suivante récupère le sommeil enregistré par le bracelet d'activité pour le lendemain du 3 mars 2026 :
Requête
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
Réponse
{
"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": ""
}Pour agréger des points de données sur une taille de fenêtre spécifique limitée à une famille de sources de données particulière, appelez le point de terminaison rollUp et transmettez le champ dataSourceFamily dans le corps de la requête JSON.
La requête POST suivante interroge le nombre de pas intrajournalier par intervalles horaires (3600s), agrégés exclusivement à partir d'appareils connectés :
Requête
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"
}Réponse
{
"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"
}
}
]
}Pour agréger les points de données quotidiens d'une famille de sources spécifique, appelez le point de terminaison dailyRollUp et transmettez le champ dataSourceFamily dans le corps de la requête.
Par exemple, la requête suivante calcule les cumuls quotidiens des pas de l'utilisateur, y compris toutes les sources Google et Fitbit propriétaires (wearables + saisies manuelles) :
Requête
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"
}Réponse
{
"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"
}
}
]
}