Google Health API memungkinkan aplikasi Anda menerima notifikasi real-time saat data kesehatan pengguna berubah. Alih-alih melakukan polling untuk perubahan, server Anda menerima webhook permintaan POST HTTPS segera setelah data tersedia di Google Health API.
Jenis data yang didukung
Notifikasi webhook didukung untuk jenis data berikut:
| Jenis data | Operasi yang tersedia |
Cakupan |
|---|---|---|
|
Menit Aktif
dataType:
active-minutesfilter parameter: active_minutes
Jenis data: Interval
Resolusi penyimpanan: 1 menit
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Menit Zona Aktif
dataType:
active-zone-minutesfilter parameter: active_zone_minutes
Jenis data: Interval
Resolusi penyimpanan: 1 menit
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Tingkat Aktivitas
|
daftar, rekonsiliasi | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Altitude
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Glukosa Darah
dataType:
blood-glucosefilter parameter: blood_glucose
Jenis data: Sample
|
list, get, reconcile, rollup, dailyRollup | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Lemak Tubuh
dataType:
body-fatfilter parameter: body_fat
Jenis data: Sample
Perangkat yang kompatibel
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Kalori dalam Zona Detak Jantung
dataType:
calories-in-heart-rate-zonefilter parameter: calories_in_heart_rate_zone
Jenis data: Interval
Resolusi penyimpanan: 1 menit
|
rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Variabilitas Detak Jantung Harian
dataType:
daily-heart-rate-variabilityfilter parameter: daily_heart_rate_variability
Jenis data: Harian
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Zona Detak Jantung Harian
dataType:
daily-heart-rate-zonesfilter parameter: daily_heart_rate_zones
Jenis data: Harian
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Saturasi Oksigen Harian
dataType:
daily-oxygen-saturationfilter parameter: daily_oxygen_saturation
Jenis data: Harian
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Laju Pernapasan Harian
dataType:
daily-respiratory-ratefilter parameter: daily_respiratory_rate
Jenis data: Harian
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Detak Jantung Saat Istirahat Harian
dataType:
daily-resting-heart-ratefilter parameter: daily_resting_heart_rate
Jenis data: Harian
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Deviasi Suhu Tidur Harian
dataType:
daily-sleep-temperature-derivationsfilter parameter: daily_sleep_temperature_derivations
Jenis data: Harian
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Jarak
dataType:
distancefilter parameter: distance
Jenis data: Interval
Resolusi penyimpanan: 1 menit
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Latihan
dataType:
exercisefilter parameter: exercise
Jenis data: Sesi
Perangkat yang kompatibel
|
list, get, reconcile, create, update, batchDelete | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Lantai
|
reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Detak Jantung
dataType:
heart-ratefilter parameter: heart_rate
Jenis data: Sample
Resolusi penyimpanan: 1 detik
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Variabilitas Detak Jantung
dataType:
heart-rate-variabilityfilter parameter: heart_rate_variability
Jenis data: Sample
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Tinggi
|
list, get, reconcile, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Catatan Hidrasi
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .nutrition.readonly.nutrition.writeonly |
|
Catatan Gizi
dataType:
nutrition-logfilter parameter: nutrition_log
Jenis data: Sesi
Perangkat yang kompatibel
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .nutrition.readonly.nutrition.writeonly |
|
Ringkasan data tidur laju pernapasan
dataType:
respiratory-rate-sleep-summaryfilter parameter: respiratory_rate_sleep_summary
Jenis data: Sample
Perangkat yang kompatibel
|
daftar, rekonsiliasi | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
VO2 Maks Lari
dataType:
run-vo2-maxfilter parameter: run_vo2_max
Jenis data: Sample
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Periode Tidak Bergerak
dataType:
sedentary-periodfilter parameter: sedentary_period
Jenis data: Interval
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Tidur
dataType:
sleepfilter parameter: sleep
Jenis data: Sesi
Perangkat yang kompatibel
|
list, get, reconcile, create, update, batchDelete | .sleep.readonly.sleep.writeonly |
|
Langkah
dataType:
stepsfilter parameter: steps
Jenis data: Interval
Resolusi penyimpanan: 1 menit
Perangkat yang kompatibel
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Waktu di Zona Detak Jantung
dataType:
time-in-heart-rate-zonefilter parameter: time_in_heart_rate_zone
Jenis data: Interval
Resolusi penyimpanan: 1 menit
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Berat
dataType:
weightfilter parameter: weight
Jenis data: Sample
Perangkat yang kompatibel
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
Cakupan notifikasi
Notifikasi dikirim untuk jenis data ini hanya jika pengguna telah memberikan izin untuk salah satu cakupan yang sesuai:
- Aktivitas, yang mencakup jenis data menit aktif, langkah, ketinggian, jarak, dan
lantai:
https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonlyhttps://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
- Metrik Kesehatan, yang mencakup jenis data berat:
https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonlyhttps://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
- Tidur, yang mencakup jenis data tidur:
https://www.googleapis.com/auth/googlehealth.sleep.readonlyhttps://www.googleapis.com/auth/googlehealth.sleep.writeonly
Akun Layanan IAM
Meskipun tidak wajib, sebaiknya gunakan Akun Layanan IAM saat mengonfigurasi pelanggan untuk Google Health API. Akun layanan memberikan keamanan yang lebih baik untuk workload aplikasi dibandingkan dengan akun pengguna standar melalui fitur berikut:
- Kredensial berjangka pendek otomatis: Saat dilampirkan ke lingkungan eksekusi Google Cloud (seperti Compute Engine, Cloud Run, atau Google Kubernetes Engine), akun layanan akan otomatis mendapatkan dan merotasi kredensial berjangka pendek yang aman. Hal ini menghilangkan risiko pengelolaan dan penyimpanan kunci statis persisten.
- Prinsip hak istimewa terendah: Akun layanan menyediakan identitas khusus untuk workload. Anda dapat memberi mereka hanya izin khusus yang diperlukan untuk mengelola endpoint pelanggan, sehingga menghindari akses yang lebih luas ke resource Google Cloud Anda.
- Kemandirian siklus proses: Akun layanan beroperasi secara independen dari akun pengguna perorangan, sehingga memastikan bahwa perubahan personel tidak memengaruhi stabilitas autentikasi jangka panjang.
Menyiapkan akun layanan
Untuk mengonfigurasi aplikasi pelanggan agar melakukan autentikasi menggunakan akun layanan:
- Buat akun layanan: Di konsol Google Cloud, buka halaman IAM & Admin project Anda untuk membuat akun layanan terkelola pengguna baru.
- Berikan peran IAM yang diperlukan: Tetapkan peran yang sesuai ke akun layanan yang diperlukan untuk mengelola pelanggan di project Google Cloud Anda.
- Lampirkan akun layanan ke workload Anda: Konfigurasikan lingkungan yang menghosting logika pelanggan Anda untuk dijalankan sebagai akun layanan baru.
Hal ini memungkinkan kode aplikasi Anda (seperti library klien Google API) untuk
otomatis mendeteksi dan menggunakan kredensial akun layanan yang berumur singkat
saat memanggil
projects.subscribersREST API.
Peran CPE
Untuk mengelola Pelanggan atau Langganan Google Health API, Anda harus memberikan peran yang sesuai kepada Akun Layanan yang ditiru identitasnya yang melakukan panggilan API. Bergantung pada tingkat akses yang diperlukan, tetapkan salah satu peran berikut:
- Google Health API Read
- Editor Google Health API
- Admin Google Health API
Pelajari lebih lanjut peran dan izin IAM Google Health API.
Mengelola subscriber
Sebelum dapat menerima notifikasi, Anda harus mendaftarkan Subscriber, yang
mewakili endpoint notifikasi aplikasi Anda. Anda dapat mengelola pelanggan
menggunakan REST API yang tersedia di
projects.subscribers.
Endpoint pelanggan Anda harus menggunakan HTTPS (TLSv1.2+) dan dapat diakses secara publik.
Selama pembuatan dan pembaruan pelanggan, Google Health API melakukan
tantangan verifikasi untuk memastikan Anda memiliki URI endpoint. Jika verifikasi gagal, operasi pembuatan dan pembaruan pelanggan akan gagal dengan FailedPreconditionException.
Membuat pelanggan
Untuk mendaftarkan pelanggan baru untuk project Anda, gunakan endpoint
create. Anda harus memberikan:
project-id: Nomor project tempat akun layanan webhook dibuat.subscriberId: ID unik yang Anda berikan untuk pelanggan. ID ini harus terdiri dari 4 hingga 36 karakter, dan cocok dengan ekspresi reguler ([a-z]([a-z0-9-]{2,34}[a-z0-9])).endpointUri: URL tujuan untuk notifikasi webhook.subscriberConfigs: Jenis data yang ingin Anda terima notifikasinya, dan kebijakan langganan untuk masing-masing jenis data.endpointAuthorization: Mekanisme otorisasi untuk endpoint Anda. Ini harus berisisecretyang Anda berikan. Nilaisecretdikirim di headerAuthorizationdengan setiap pesan notifikasi. Anda dapat menggunakan token ini untuk memverifikasi bahwa permintaan masuk berasal dari Google Health API. Misalnya, Anda dapat menetapkansecretkeBearer R4nd0m5tr1ng123untuk autentikasi Bearer, atauBasic dXNlcjpwYXNzd29yZA==untuk autentikasi Basic.
Di subscriberConfigs, Anda harus menetapkan subscriptionCreatePolicy untuk setiap jenis data. Tetapkan ke AUTOMATIC untuk menggunakan langganan otomatis, atau MANUAL jika Anda
bermaksud mengelola langganan pengguna sendiri. Lihat
langganan otomatis dan
langganan manual untuk mengetahui detail selengkapnya tentang setiap opsi.
Permintaan
POST https://health.googleapis.com/v4/projects/project-id/subscribers?subscriberId=subscriber-id
{
"endpointUri": "https://myapp.com/webhooks/health",
"subscriberConfigs": [
{
"dataTypes": ["steps", "altitude", "distance", "floors", "weight"],
"subscriptionCreatePolicy": "AUTOMATIC"
},
{
"dataTypes": ["sleep"],
"subscriptionCreatePolicy": "MANUAL"
}
],
"endpointAuthorization": {
"secret": "Bearer example-secret-token"
}
}Respons
{
"name": "projects/project-id/subscribers/subscriber-id",
"endpointUri": "https://myapp.com/webhooks/health",
"subscriberConfigs": [
{
"dataTypes": ["steps", "altitude", "distance", "floors", "weight"],
"subscriptionCreatePolicy": "AUTOMATIC"
},
{
"dataTypes": ["sleep"],
"subscriptionCreatePolicy": "MANUAL"
}
]
}Mencantumkan pelanggan
Gunakan endpoint list untuk mengambil semua pelanggan yang terdaftar untuk project Anda.
Permintaan
GET https://health.googleapis.com/v4/projects/project-id/subscribers
Respons
{
"subscribers": [
{
"name": "projects/project-id/subscribers/subscriber-id",
"endpointUri": "https://myapp.com/webhooks/health",
"subscriberConfigs": [
{
"dataTypes": ["steps", "altitude", "distance", "floors", "weight"],
"subscriptionCreatePolicy": "AUTOMATIC"
},
{
"dataTypes": ["sleep"],
"subscriptionCreatePolicy": "MANUAL"
}
],
"endpointAuthorization": {
"authorizationTokenSet": true
}
}
],
"totalSize": 1
}Memperbarui pelanggan
Gunakan endpoint patch
untuk memperbarui pelanggan di project Anda. Kolom yang dapat diperbarui adalah
endpointUri, subscriberConfigs, dan endpointAuthorization.
Anda memperbarui kolom dengan memberikan parameter kueri updateMask dan isi permintaan. updateMask harus berisi daftar nama kolom yang dipisahkan koma yang
ingin Anda perbarui, menggunakan camel case untuk nama kolom
(misalnya, endpointUri). Isi permintaan harus berisi objek Subscriber
parsial dengan nilai baru untuk kolom yang ingin Anda perbarui. Hanya kolom yang ditentukan
di updateMask yang diperbarui. Jika Anda memberikan kolom dalam isi permintaan yang tidak ada di updateMask, kolom tersebut akan diabaikan.
Jika Anda memperbarui endpointUri atau endpointAuthorization, verifikasi endpoint akan dilakukan. Lihat Verifikasi endpoint untuk mengetahui detailnya.
Saat memperbarui subscriberConfigs, perhatikan bahwa ini adalah penggantian penuh, bukan
penggabungan. Jika subscriberConfigs disertakan dalam updateMask, semua konfigurasi yang disimpan untuk pelanggan tersebut akan ditimpa dengan daftar yang disediakan dalam isi permintaan. Untuk menambahkan atau menghapus konfigurasi, Anda harus menyediakan kumpulan konfigurasi lengkap. Jika Anda mengupdate kolom lain dan ingin mempertahankan konfigurasi saat ini, hapus subscriberConfigs dari updateMask.
Permintaan
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id?updateMask=endpointUri
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}Respons
{
"name": "projects/project-id/subscribers/subscriber-id",
"endpointUri": "https://myapp.com/new-webhooks/health",
"subscriberConfigs": [
{
"dataTypes": ["steps", "altitude", "distance", "floors", "weight"],
"subscriptionCreatePolicy": "AUTOMATIC"
},
{
"dataTypes": ["sleep"],
"subscriptionCreatePolicy": "MANUAL"
}
]
}Menghapus pelanggan
Gunakan endpoint delete
untuk menghapus pelanggan dari project Anda. Setelah dihapus, pelanggan
tidak akan lagi menerima notifikasi.
Permintaan
DELETE https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
Respons
Isi respons kosong dengan status HTTP `200 OK` akan ditampilkan jika penghapusan berhasil.{}Verifikasi endpoint
Untuk memastikan keamanan dan keandalan pengiriman notifikasi, Google Health API melakukan handshake verifikasi dua langkah wajib setiap kali Anda membuat pelanggan atau memperbarui konfigurasi endpoint-nya (endpointUri atau endpointAuthorization). Proses ini dilakukan secara sinkron selama panggilan API. Layanan ini mengirimkan dua permintaan POST otomatis ke URI endpoint Anda,
menggunakan Agen Pengguna Google-Health-API-Webhooks, dengan isi JSON
{"type": "verification"}.
- Handshake yang Diotorisasi: Permintaan pertama dikirim dengan header
Authorizationyang Anda konfigurasi. Server Anda harus merespons dengan status200 OKatau201 Created. - Unauthorized Challenge: Permintaan kedua dikirim tanpa kredensial.
Server Anda harus merespons dengan status
401 Unauthorizedatau403 Forbidden.
Handshake ini mengonfirmasi bahwa endpoint Anda aktif dan menerapkan keamanan dengan benar. Jika salah satu langkah gagal, permintaan API akan gagal dengan error FAILED_PRECONDITION. Hanya setelah handshake ini berhasil, pelanggan Anda akan disimpan dan diaktifkan untuk menerima notifikasi data kesehatan.
Rotasi kunci
Jika Anda perlu merotasi kunci untuk endpointAuthorization, ikuti langkah-langkah berikut:
- Konfigurasikan endpoint Anda untuk menerima nilai
endpointAuthorizationlama dan baru. - Perbarui konfigurasi pelanggan dengan nilai
endpointAuthorizationbaru menggunakan permintaanpatchdengan?updateMask=endpointAuthorization. - Konfigurasikan endpoint Anda agar hanya menerima nilai
endpointAuthorizationbaru setelah mengonfirmasi bahwa langkah 2 berhasil.
Langganan pengguna
Google Health API membantu Anda mengelola langganan pengguna secara efisien, sehingga mengurangi kebutuhan pendaftaran manual selama orientasi pengguna.
Langganan otomatis
Sebaiknya gunakan langganan otomatis. Untuk mengaktifkan fitur ini, tetapkan
subscriptionCreatePolicy ke AUTOMATIC di subscriberConfigs untuk
jenis data tertentu. dataTypes yang Anda tentukan dengan kebijakan AUTOMATIC adalah
jenis data yang sama dengan yang dikirimi notifikasi oleh Google Health API,
asalkan izin pengguna juga diberikan untuk jenis data tersebut.
Saat pengguna memberikan izin aplikasi untuk cakupan yang sesuai dengan jenis data
dengan kebijakan AUTOMATIC, Google Health API akan otomatis melacak dan
mengirimkan notifikasi untuk jenis data yang dihasilkan dari persimpangan
antara jenis data yang diizinkan pengguna dan jenis data konfigurasi pelanggan otomatis
untuk pengguna tersebut. Notifikasi kemudian dikirim ke endpoint Anda
setiap kali pengguna tersebut membuat data baru untuk jenis tersebut. Hal ini berlaku untuk pengguna yang
memberikan izin sebelum atau setelah Anda membuat pelanggan. Notifikasi tidak diisi ulang untuk data yang dihasilkan sebelum pelanggan dibuat.
Jika pengguna mencabut izin, notifikasi untuk jenis data yang sesuai akan berhenti. Langganan otomatis dikelola oleh Google dan tidak dapat dicantumkan atau dihapus satu per satu; langganan tersebut hanya dihapus jika pelanggan induk dihapus.
Langganan manual
Jika pelanggan Anda dikonfigurasi dengan subscription_create_policy MANUAL
untuk jenis data tertentu, Anda harus membuat dan mengelola langganan secara eksplisit
untuk setiap pengguna. Langganan menautkan pengguna tertentu ke endpoint pelanggan Anda untuk kumpulan jenis data yang ditentukan. Developer dapat menggunakan API tertentu untuk:
- Buat langganan (manual) per
healthUserId- Membuat langganan baru untuk pengguna tertentu. Metode ini mengharuskan pelanggan memilikiSubscriptionCreatePolicyyang ditetapkan keMANUALuntuk jenis data yang diminta. - Memperbarui langganan (manual) - Memperbarui jenis data untuk langganan pengguna yang ada.
- Menghapus langganan (manual) - Menghapus langganan pengguna tertentu. Setelah dihapus, endpoint pelanggan Anda tidak akan lagi menerima notifikasi untuk pengguna ini untuk jenis data terkait.
- Mencantumkan langganan (manual) - Mencantumkan semua langganan aktif untuk pelanggan tertentu. Anda dapat memfilter hasil menurut pengguna atau jenis data.
Notifikasi
Saat data pengguna berubah untuk jenis data yang berlangganan, Google Health API akan mengirimkan permintaan POST HTTPS ke URL endpoint pelanggan.
Format notifikasi
Payload notifikasi berisi detail tentang perubahan data, termasuk ID pengguna, jenis data, dan interval waktu, yang dapat Anda gunakan untuk mengkueri data yang diperbarui. Jika beberapa update terjadi atau update digabungkan, notifikasi akan dikelompokkan dan dikirim sebagai array JSON objek notifikasi.
Saat notifikasi webhook dipicu, Google Health API akan mengirimkan permintaan POST HTTPS ke endpoint pelanggan Anda dengan format berikut:
Upsert (data deret waktu)
POST https://your-endpoint-uri
Authorization: Bearer example-secret-token
GOOGLE-HEALTH-API-SIGNATURE: signature-value
Content-Type: application/json
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "subscription-name",
"healthUserId": "health-user-id",
"operation": "UPSERT",
"dataType": "steps",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-03-08T01:29:00Z",
"endTime": "2026-03-08T01:34:00Z"
},
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 17,
"minutes": 29
}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 17,
"minutes": 34
}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-03-07T17:29:00",
"endTime": "2026-03-07T17:34:00"
}
}
]
}
}Menghapus (data deret waktu)
POST https://your-endpoint-uri
Authorization: Bearer example-secret-token
GOOGLE-HEALTH-API-SIGNATURE: signature-value
Content-Type: application/json
[
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "subscription-name",
"healthUserId": "health-user-id",
"operation": "DELETE",
"dataType": "steps",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-08-12T12:00:00Z",
"endTime": "2026-08-12T12:30:00Z"
},
"civilIso8601TimeInterval": {
"startTime": "2026-08-12T12:00:00",
"endTime": "2026-08-12T12:30:00"
}
}
]
}
}
]Menghapus (data yang dapat diidentifikasi)
POST https://your-endpoint-uri
Authorization: Bearer example-secret-token
GOOGLE-HEALTH-API-SIGNATURE: signature-value
Content-Type: application/json
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "subscription-name",
"healthUserId": "health-user-id",
"operation": "DELETE",
"dataType": "sleep",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-08-12T22:00:00Z",
"endTime": "2026-08-13T06:00:00Z"
},
"civilIso8601TimeInterval": {
"startTime": "2026-08-12T22:00:00",
"endTime": "2026-08-13T06:00:00"
}
}
],
"recordId": "9875412"
}
}Batch (multi-pengguna dan jenis data)
POST https://your-endpoint-uri
Authorization: Bearer example-secret-token
GOOGLE-HEALTH-API-SIGNATURE: signature-value
Content-Type: application/json
[
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "auto-project-number-subscriber-id-WEBHOOK_DATA_TYPE_STEPS",
"healthUserId": "health-user-id-1",
"operation": "UPSERT",
"dataType": "steps",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-03-08T01:29:00Z",
"endTime": "2026-03-08T01:34:00Z"
},
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 17,
"minutes": 29
}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 17,
"minutes": 34
}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-03-07T17:29:00",
"endTime": "2026-03-07T17:34:00"
}
}
]
}
},
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "auto-project-number-subscriber-id-WEBHOOK_DATA_TYPE_WEIGHT",
"healthUserId": "health-user-id-1",
"operation": "UPSERT",
"dataType": "weight",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-03-07T15:14:00Z",
"endTime": "2026-03-07T15:16:00Z"
},
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 7,
"minutes": 14
}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 3,
"day": 7
},
"time": {
"hours": 7,
"minutes": 16
}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-03-07T07:14:00",
"endTime": "2026-03-07T07:16:00"
}
}
]
}
},
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "auto-project-number-subscriber-id-WEBHOOK_DATA_TYPE_STEPS",
"healthUserId": "health-user-id-2",
"operation": "UPSERT",
"dataType": "steps",
"intervals": [
{
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 8,
"day": 20
},
"time": {
"hours": 0,
"minutes": 0
}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 8,
"day": 21
},
"time": {
"hours": 0,
"minutes": 0
}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-08-20T00:00:00",
"endTime": "2026-08-21T00:00:00"
}
}
]
}
},
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "subscription-name",
"healthUserId": "health-user-id-2",
"operation": "UPSERT",
"dataType": "sleep",
"intervals": [
{
"physicalTimeInterval": {
"startTime": "2026-08-12T22:00:00Z",
"endTime": "2026-08-13T06:00:00Z"
},
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 8,
"day": 12
},
"time": {
"hours": 22,
"minutes": 0
}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 8,
"day": 13
},
"time": {
"hours": 6,
"minutes": 0
}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-08-12T22:00:00",
"endTime": "2026-08-13T06:00:00"
}
}
],
"recordId": "9875412"
}
}
]Kolom operation menunjukkan jenis perubahan yang memicu notifikasi:
UPSERT: Dikirim untuk setiap penambahan atau modifikasi data.DELETE: Dikirim saat pengguna secara eksplisit menghapus data (seperti menghapusdataPointsmenggunakan aplikasi Fitbit atau melakukan penghapusan batch menggunakan API). Notifikasi webhook tidak dikirim untuk peristiwa penghapusan tingkat sistem, seperti pengguna yang mencabut izin aplikasi atau menghapus akun Fitbit mereka.
Sebaiknya buat logika penanganan notifikasi Anda idempoten, terutama untuk operasi UPSERT, karena percobaan ulang dapat menyebabkan notifikasi duplikat dikirim.
Kolom clientProvidedSubscriptionName adalah ID unik:
- Untuk langganan dengan kebijakan
MANUAL, kolom ini berisi nama langganan persisten yang disediakan developer dan ditentukan saat langganan dibuat. Hal ini memberikan ID yang stabil untuk mengelola langganan manual. - Untuk langganan yang dibuat dengan kebijakan
AUTOMATIC, Google Health API akan otomatis membuat dan menetapkan ID dalam format:auto-<project-number>-<subscriber-id>-<WEBHOOK_DATA_TYPE_TOKEN>, dengan:<project-number>adalah nomor project Google Cloud developer (misalnya,362978535920).<subscriber-id>adalah ID pendaftaran pelanggan / nama pelanggan (misalnya,google-health-sync).<WEBHOOK_DATA_TYPE_TOKEN>adalah token yang mewakili jenis data tertentu. Lihat Kosakata token jenis data webhook untuk semua token yang memungkinkan.
Menyertakan clientProvidedSubscriptionName untuk kebijakan manual dan
otomatis akan memastikan format payload notifikasi yang konsisten di semua
jenis langganan.
Pemetaan ID pengguna
healthUserId adalah ID Google Health API untuk pengguna yang datanya telah berubah. Jika aplikasi Anda mendukung beberapa pengguna, Anda dapat menerima
notifikasi untuk setiap pengguna yang telah memberikan izin kepada aplikasi Anda. Saat
Anda menerima notifikasi, gunakan healthUserId untuk mengidentifikasi data pengguna mana yang
telah berubah, sehingga Anda dapat menggunakan kredensial OAuth mereka untuk mengkueri data mereka.
Untuk memetakan kredensial OAuth pengguna ke healthUserId-nya, gunakan endpoint getIdentity. Panggil endpoint ini dengan kredensial pengguna selama orientasi pengguna untuk mengambil healthUserId mereka, dan simpan pemetaan ini. Pemetaan ini tidak berubah seiring waktu, sehingga dapat di-cache tanpa batas waktu. Misalnya, lihat
Mendapatkan ID pengguna. Dengan begitu, Anda dapat memilih kredensial pengguna yang benar saat mengkueri data berdasarkan healthUserId dalam notifikasi.
Interval waktu
Array intervals berisi satu atau beberapa objek yang mewakili interval waktu untuk data yang diubah:
| Kolom | Jenis | Wajib diisi | Deskripsi |
|---|---|---|---|
physicalTimeInterval |
object |
Tidak | Interval waktu fisik UTC dari data yang diubah (format YYYY-MM-DDTHH:MM:SSZ). Diisi untuk metrik intrahari; dihilangkan untuk rollup harian dan aktivitas sepanjang hari. |
civilDateTimeInterval |
object |
Ya | Interval tanggal dan waktu kalender sipil (lokal) dari data yang diubah, tanpa offset UTC atau zona waktu. |
civilIso8601TimeInterval |
object |
Ya | Interval waktu sipil (lokal) yang direpresentasikan sebagai string ISO 8601 (format YYYY-MM-DDTHH:MM:SS) tanpa offset UTC atau zona waktu. |
Untuk aktivitas sepanjang hari dan agregat harian, kolom physicalTimeInterval
sengaja dihilangkan dari payload notifikasi. Hal ini karena
peristiwa sepanjang hari dikelompokkan berdasarkan tanggal sipil nominalnya, dan durasi waktu fisik
bisa jadi tidak akurat saat melintasi zona waktu. Saat memproses acara sepanjang hari, sebaiknya Anda mengandalkan kolom civilDateTimeInterval atau civilIso8601TimeInterval sebagai praktik terbaik. Untuk mengetahui detail tentang cara
membuat kueri titik data ini menggunakan filter waktu sipil, lihat
Memfilter data berdasarkan waktu mulai sipil interval.
Berikut adalah contoh payload notifikasi untuk aktivitas sepanjang hari dengan kolom physicalTimeInterval dihilangkan:
{
"data": {
"version": "1",
"clientProvidedSubscriptionName": "auto-503461148219-lindasubscriber-WEBHOOK_DATA_TYPE_STEPS",
"healthUserId": "343864966078399341",
"operation": "UPSERT",
"dataType": "steps",
"intervals": [
{
"civilDateTimeInterval": {
"startDateTime": {
"date": {
"year": 2026,
"month": 7,
"day": 14
},
"time": {}
},
"endDateTime": {
"date": {
"year": 2026,
"month": 7,
"day": 15
},
"time": {}
}
},
"civilIso8601TimeInterval": {
"startTime": "2026-07-14T00:00:00",
"endTime": "2026-07-15T00:00:00"
}
}
]
}
}Kosakata token jenis data webhook
Saat menggunakan kebijakan AUTOMATIC, clientProvidedSubscriptionName yang dihasilkan
berisi salah satu token akhiran WEBHOOK_DATA_TYPE_* yang menggunakan huruf kapital berikut,
bergantung pada jenis datanya:
| Token Jenis Data Webhook | Jenis Data Terkait |
|---|---|
WEBHOOK_DATA_TYPE_ACTIVE_MINUTES |
active-minutes |
WEBHOOK_DATA_TYPE_ACTIVE_ZONE_MINUTES |
active-zone-minutes |
WEBHOOK_DATA_TYPE_ACTIVITY_LEVEL |
activity-level |
WEBHOOK_DATA_TYPE_ALTITUDE |
altitude |
WEBHOOK_DATA_TYPE_BLOOD_GLUCOSE |
blood-glucose |
WEBHOOK_DATA_TYPE_BODY_FAT |
body-fat |
WEBHOOK_DATA_TYPE_CALORIES_IN_HEART_RATE_ZONE |
calories-in-heart-rate-zone |
WEBHOOK_DATA_TYPE_DAILY_HEART_RATE_VARIABILITY |
daily-heart-rate-variability |
WEBHOOK_DATA_TYPE_DAILY_HEART_RATE_ZONES |
daily-heart-rate-zones |
WEBHOOK_DATA_TYPE_DAILY_OXYGEN_SATURATION |
daily-oxygen-saturation |
WEBHOOK_DATA_TYPE_DAILY_RESPIRATORY_RATE |
daily-respiratory-rate |
WEBHOOK_DATA_TYPE_DAILY_RESTING_HEART_RATE |
daily-resting-heart-rate |
WEBHOOK_DATA_TYPE_DAILY_SLEEP_TEMPERATURE_DERIVATIONS |
daily-sleep-temperature-derivations |
WEBHOOK_DATA_TYPE_DISTANCE |
distance |
WEBHOOK_DATA_TYPE_EXERCISE |
exercise |
WEBHOOK_DATA_TYPE_FLOORS |
floors |
WEBHOOK_DATA_TYPE_HEART_RATE |
heart-rate |
WEBHOOK_DATA_TYPE_HEART_RATE_VARIABILITY |
heart-rate-variability |
WEBHOOK_DATA_TYPE_HEIGHT |
height |
WEBHOOK_DATA_TYPE_HYDRATION_LOG |
hydration-log |
WEBHOOK_DATA_TYPE_NUTRITION_LOG |
nutrition-log |
WEBHOOK_DATA_TYPE_RESPIRATORY_RATE_SLEEP_SUMMARY |
respiratory-rate-sleep-summary |
WEBHOOK_DATA_TYPE_RUN_VO2_MAX |
run-vo2-max |
WEBHOOK_DATA_TYPE_SEDENTARY_PERIOD |
sedentary-period |
WEBHOOK_DATA_TYPE_SLEEP |
sleep |
WEBHOOK_DATA_TYPE_STEPS |
steps |
WEBHOOK_DATA_TYPE_TIME_IN_HEART_RATE_ZONE |
time-in-heart-rate-zone |
WEBHOOK_DATA_TYPE_WEIGHT |
weight |
WEBHOOK_DATA_TYPE_USER_DELETED |
user-deleted (peristiwa sistem) |
WEBHOOK_DATA_TYPE_USER_REVOKED_ACCESS |
user-revoked-access (peristiwa sistem) |
Agregasi update
Untuk meminimalkan traffic jaringan, Google Health API mengelompokkan pesan. Sistem dikonfigurasi untuk mengirim maksimum 99 pesan per batch, yang otomatis dikirim saat tersedia.
Saat pesan dikelompokkan, payload dikirim sebagai array JSON yang berisi beberapa objek notifikasi. Satu batch dapat menyertakan update untuk beberapa pengguna di beberapa jenis data yang berlangganan. Untuk contoh payload, lihat contoh Batch (multi-pengguna dan jenis data) di bagian Format notifikasi.
Merespons notifikasi
Server Anda harus memvalidasi header Authorization, menangani handshake verifikasi endpoint sinkron, dan segera merespons notifikasi perubahan data dengan kode status HTTP 204 No Content. Untuk menghindari waktu tunggu habis, proses payload notifikasi secara asinkron setelah mengirim respons. Jika Google Health API menerima kode status lain atau waktu permintaan habis, Google Health API akan mencoba mengirim ulang notifikasi nanti.
Contoh Node.js (Express):
app.post('/webhook-receiver', (req, res) => {
if (req.headers.authorization !== EXPECTED_SECRET) {
return res.status(401).send();
}
if (req.body && !Array.isArray(req.body) && req.body.type === 'verification') {
return res.status(200).send();
}
// 1. Immediately acknowledge the notification batch
res.status(204).send();
// 2. Normalize single-object or batched array notifications and reconcile asynchronously
const notifications = Array.isArray(req.body) ? req.body : [req.body];
setImmediate(async () => {
for (const notification of notifications) {
const { healthUserId, dataType, intervals = [] } = notification.data || {};
console.log(`Update for user ${healthUserId} of type ${dataType}`);
// Query /v4/users/${healthUserId}/dataTypes/${dataType}/dataPoints:reconcile?filter=...
// for each interval in `intervals` (using >= and < comparators; for sleep, filter on
// sleep.interval.end_time or sleep.interval.civil_end_time).
}
});
});
Untuk mengambil data yang diperbarui untuk setiap interval yang diberi tahu, panggil endpoint
reconcile
dengan filter untuk rentang waktu interval. Tindakan ini akan otomatis menghapus duplikat interval yang tumpang-tindih dari perangkat terhubung. Untuk mengetahui detail dan contohnya, lihat Mendapatkan tampilan data interval yang direkonsiliasi.
Ada tiga strategi umum untuk mengupdate database setelah menerima notifikasi perubahan data:
- Antrean (direkomendasikan): Tempatkan notifikasi yang masuk ke dalam antrean pesan dan proses dari antrean berdasarkan resource sistem.
- Pengambilan langsung: Arahkan backend Anda untuk segera memanggil Google Health API guna mengambil data yang diperbarui dan meng-commit-nya ke database Anda.
- Update lambat: Tandai data database lokal pengguna sebagai kotor dan hanya ambil data yang diperbarui dari Google Health API saat pengguna mengunjungi aplikasi Anda lagi.
Strategi antrean memungkinkan Anda memproses data hampir real-time sekaligus tetap tangguh terhadap banjir notifikasi (misalnya, jika pemadaman layanan menyebabkan backlog notifikasi dikirim sekaligus). Meskipun Anda dapat memilih untuk memproses antrean ini pada jadwal batch interval panjang (misalnya, setiap 3 jam) untuk menghemat resource, kelemahannya adalah pengguna biasanya berharap melihat data mereka diperbarui hampir secara real-time.
Praktik terbaik
Ikuti praktik terbaik berikut untuk memastikan penanganan update data yang andal dan efisien:
- Gunakan Subscription API: Gunakan Subscription API untuk mendapatkan notifikasi saat pengguna memiliki data baru untuk didownload, bukan melakukan polling endpoint.
- Antrekan dan proses notifikasi secara terpisah: Saat menerima notifikasi langganan, tempatkan notifikasi tersebut ke dalam antrean dan proses secara terpisah berdasarkan resource sistem Anda. Buat endpoint webhook tetap ringan dengan segera mengonfirmasi permintaan.
Verifikasi tanda tangan
Untuk memastikan keaslian notifikasi Webhook, payload JSON mentah dari
setiap notifikasi webhook keluar ditandatangani dengan kunci pribadi menggunakan PublicKeySign
Tink,
yang memberikan tanda tangan berenkode Base64 di header HTTP
GOOGLE-HEALTH-API-SIGNATURE dalam permintaan. Kunci penandatanganan ini dirotasi secara otomatis setiap 30 hari, dan keyset publik resmi yang sesuai didistribusikan sebagai file JSON di URL permanen https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.
Cara memverifikasi tanda tangan
Menggunakan Tink (Direkomendasikan): Developer dapat memverifikasi tanda tangan menggunakan primitif
PublicKeyVerify
Tink. Ambil keyset publik dari URL permanen, buat instance primitif PublicKeyVerify dengan keyset, dan verifikasi header GOOGLE-HEALTH-API-SIGNATURE yang didekode terhadap payload JSON webhook mentah.
Verifikasi Manual (Tanpa Tink): Jika developer memilih untuk tidak menggunakan Tink, mereka dapat memverifikasi tanda tangan secara manual dengan mengikuti langkah-langkah berikut:
- Mendekode header
GOOGLE-HEALTH-API-SIGNATUREdengan Base64 untuk memisahkan awalan Tink 5 byte (yang berisi awalan versi 1 byte dan keyId 4 byte) dari tanda tangan berenkode DER yang sebenarnya. - Ambil keyset JSON dari https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.
- Temukan kunci yang cocok dengan keyId yang diuraikan dan dekode Base64 kolom nilainya, yang berisi buffering protokol EcdsaPublicKey yang diserialisasi.
- Ekstrak koordinat x dan y big-endian (tag Protobuf 3 dan 4) dari payload biner ini.
- Buat instance kunci publik ECDSA P-256 standar di library kriptografi bawaan menggunakan koordinat x dan y yang diekstrak.
- Verifikasi payload JSON webhook mentah terhadap tanda tangan DER yang diekstrak menggunakan algoritma SHA-256.
Status dan pemulihan pelanggan
Jika endpoint pelanggan Anda tidak tersedia atau menampilkan kode status error
(apa pun selain 204), Google Health API akan menyimpan notifikasi
yang tertunda hingga 7 hari dan mencoba kembali pengiriman dengan backoff eksponensial.
Setelah endpoint Anda kembali online dan merespons dengan 204, API akan otomatis mengirimkan backlog pesan yang disimpan. Notifikasi yang sudah lebih dari
7 hari akan dihapus dan tidak dapat dipulihkan.
Error yang biasa terjadi
| Kode error | Pesan | Deskripsi | Rekomendasi |
|---|---|---|---|
| 400 Bad Request (400 Permintaan Tidak Valid) | Nomor project tidak valid dalam nama resource | Saat menghapus atau memperbarui pelanggan menggunakan ID project Google Cloud Anda di URL permintaan, bukan nomor project. Hal ini berlaku untuk langganan webhook yang menggunakan endpoint projects.subscribers. |
Gunakan nomor project Google Cloud Anda di URL permintaan, bukan project ID. |
| 403 Forbidden | Pemanggil tidak memiliki izin | Saat membuat atau mencantumkan pelanggan menggunakan project ID Google Cloud Anda di URL permintaan, bukan nomor project. Hal ini berlaku untuk langganan webhook yang menggunakan endpoint projects.subscribers. |
Gunakan nomor project Google Cloud Anda di URL permintaan, bukan project ID. |