應用程式可透過 Google Health API,在使用者健康資料變更時收到即時通知。伺服器不必輪詢變更,只要 Google Health API 中有可用資料,就會收到 HTTPS POST 要求 (Webhook){:target="_blank" class="external"}。
支援的資料類型
Webhook 通知支援下列資料類型:
- 活動區間分鐘數
- 活動程度
- 海拔高度
- 血糖
- 體脂肪
- 心率區間內的卡路里
- 每日心率變異
- 每日心率區間
- 每日血氧濃度
- 每日呼吸速率
- 每日靜止心率
- 每日睡眠溫度變化
- 距離
- 運動
- 樓層數
- 心跳速率
- 心率變異
- 高度
- 飲水量記錄
- 營養記錄
- 睡眠呼吸速率摘要
- 跑步最大攝氧量
- 不活動時間
- 睡眠
- 步驟
- 處於心率區間的時間
- 總卡路里
- 重量
只有在使用者同意下列其中一個對應範圍時,系統才會傳送這些資料類型的通知:
- 活動,涵蓋步數、海拔高度、距離和樓層資料類型:
https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonlyhttps://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
- 健康指標,涵蓋體重資料類型:
https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonlyhttps://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
- 睡眠,涵蓋睡眠資料類型:
https://www.googleapis.com/auth/googlehealth.sleep.readonlyhttps://www.googleapis.com/auth/googlehealth.sleep.writeonly
IAM 服務帳戶
雖然不一定要使用 IAM 服務帳戶,但我們建議您在為 Google Health API 設定訂閱者時使用。與標準使用者帳戶相比,服務帳戶可透過下列功能,為應用程式工作負載提供更完善的安全性:
- 自動產生短期憑證:附加至 Google Cloud 執行環境 (例如 Compute Engine、Cloud Run 或 Google Kubernetes Engine) 時,服務帳戶會自動取得並輪替安全、短期憑證。這樣就不必管理及儲存永久靜態金鑰,可避免相關風險。
- 最小權限原則:服務帳戶會為工作負載提供專屬身分。您可以只授予管理訂閱端點所需的特定權限,避免他們取得更廣泛的 Google Cloud 資源存取權。
- 生命週期獨立性:服務帳戶的運作與任何個別使用者的帳戶無關,因此人員異動不會影響長期驗證穩定性。
設定服務帳戶
如要將訂閱者應用程式設定為使用服務帳戶進行驗證,請按照下列步驟操作:
- 建立服務帳戶:在 Google Cloud 控制台中,前往專案的「IAM 與管理」頁面,建立新的使用者管理服務帳戶。
- 授予必要的 IAM 角色: 為服務帳戶指派適當的角色,以便管理 Google Cloud 雲端專案中的訂閱者。
- 將服務帳戶附加至工作負載: 將代管訂閱端邏輯的環境設定為以新的服務帳戶執行。
這樣一來,應用程式程式碼 (例如 Google API 用戶端程式庫) 就能在呼叫
projects.subscribersREST API 時,自動偵測及使用服務帳戶的短期憑證。
CPE 角色
如要管理 Google Health API 訂閱者或訂閱項目,您必須將適當角色授予發出 API 呼叫的模擬服務帳戶。請根據所需存取層級指派下列其中一個角色:
- Google Health API Read
- Google Health API 編輯者
- Google Health API 管理員
進一步瞭解 Google Health API IAM 角色和權限。
管理訂閱者
如要接收通知,您必須先註冊 Subscriber,這代表應用程式的通知端點。您可以使用 projects.subscribers 提供的 REST API 管理訂閱者。
訂閱者端點必須使用 HTTPS (TLSv1.2 以上版本),且可公開存取。
建立及更新訂閱者時,Google Health API 會執行驗證挑戰,確保您擁有端點 URI。如果驗證失敗,訂閱者建立和更新作業就會失敗,並顯示 FailedPreconditionException。
建立訂閱者
如要為專案註冊新訂閱者,請使用 create 端點。請提供下列資訊:
project-id:建立 Webhook 服務帳戶的專案編號。subscriberId:您為訂閱者提供的專屬 ID。這個 ID 的長度必須介於 4 到 36 個字元之間,且符合規則運算式 ([a-z]([a-z0-9-]{2,34}[a-z0-9]))。endpointUri:Webhook 通知的目標網址。subscriberConfigs:要接收通知的資料類型,以及每種資料類型的訂閱政策。endpointAuthorization:端點的授權機制。其中必須包含您提供的secret。系統會在每個通知訊息的Authorization標頭中傳送secret的值。您可以使用這個權杖,確認傳入要求是否來自 Google Health API。舉例來說,您可以將secret設為 Bearer 驗證的Bearer R4nd0m5tr1ng123,或是 Basic 驗證的Basic dXNlcjpwYXNzd29yZA==。
在 subscriberConfigs 中,您必須為每種資料類型設定 subscriptionCreatePolicy。如要使用自動訂閱功能,請設為 AUTOMATIC;如要自行管理使用者訂閱項目,請設為 MANUAL。如要進一步瞭解各個選項,請參閱自動訂閱和手動訂閱。
要求
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"
}
}回應
{
"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"
}
]
}列出訂閱者
使用 list 端點,即可擷取專案註冊的所有訂閱者。
要求
GET https://health.googleapis.com/v4/projects/project-id/subscribers
回應
{
"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
}更新訂閱者
使用 patch 端點更新專案中的訂閱者。可更新的欄位包括 endpointUri、subscriberConfigs 和 endpointAuthorization。
如要更新欄位,請提供 updateMask 查詢參數和要求主體。updateMask 必須包含以逗號分隔的欄位名稱清單,並使用駝峰式大小寫 (例如 endpointUri)。要求主體必須包含部分 Subscriber 物件,其中包含要更新的欄位新值。系統只會更新 updateMask 中指定的欄位。如果您在要求主體中提供的欄位不在 updateMask 中,系統會略過這些欄位。
如果您更新 endpointUri 或 endpointAuthorization,系統會執行端點驗證。詳情請參閱「端點驗證」。
更新 subscriberConfigs 時,請注意這是「完整取代」,而非合併。如果 subscriberConfigs 包含在 updateMask 中,系統會以要求主體中提供的清單,覆寫該訂閱者的所有已儲存設定。如要新增或移除設定,您必須提供完整的設定組合。如要更新其他欄位並保留目前的設定,請從 updateMask 中省略 subscriberConfigs。
要求
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id?updateMask=endpointUri
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}回應
{
"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"
}
]
}刪除訂閱者
使用 delete 端點從專案中移除訂閱者。刪除後,訂閱者就不會再收到通知。
要求
DELETE https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
回應
如果刪除作業成功,系統會傳回 HTTP 狀態為 `200 OK` 的空白回應主體。{}端點驗證
為確保通知傳送的安全性與可靠性,每當您建立訂閱者或更新其端點設定 (endpointUri 或 endpointAuthorization) 時,Google Health API 都會執行強制性的兩步驟驗證握手程序。這項程序會在 API 呼叫期間同步執行。服務會使用 User-Agent Google-Health-API-Webhooks-Verifier,向端點 URI 自動傳送兩項 POST 要求,並附上 JSON 內文 {"type": "verification"}。
- 授權握手:系統會傳送第一個要求,並附上您設定的
Authorization標頭。伺服器必須傳回200 OK或201 Created狀態。 - 未經授權的驗證:第二個要求是在沒有憑證的情況下傳送。伺服器必須傳回
401 Unauthorized或403 Forbidden狀態。
這項信號交換程序可確認端點處於啟用狀態,並正確執行安全性措施。如果任一步驟失敗,API 要求就會失敗並傳回 FAILED_PRECONDITION 錯誤。只有在握手程序成功後,系統才會儲存及啟用訂閱者,以便接收健康資料通知。
金鑰輪替
如要輪替 endpointAuthorization 的金鑰,請按照下列步驟操作:
- 設定端點,同時接受新舊
endpointAuthorization值。 - 使用
patch要求和?updateMask=endpointAuthorization,以新的endpointAuthorization值更新訂閱者設定。 - 確認步驟 2 成功後,請設定端點,只接受新的
endpointAuthorization值。
使用者訂閱
Google Health API 可協助您有效管理使用者訂閱項目,減少使用者加入時的手動註冊需求。
自動訂閱
建議使用自動訂閱功能。如要啟用這項功能,請在 subscriberConfigs 中將特定資料類型的 subscriptionCreatePolicy 設為 AUTOMATIC。您透過 AUTOMATIC 政策指定的 dataTypes,與 Google Health API 傳送通知的資料類型相同,前提是使用者也同意存取這些資料類型。
如果使用者同意應用程式存取與 AUTOMATIC 政策相關的資料類型,Google Health API 就會自動追蹤並傳送通知,告知使用者同意提供的資料類型與該使用者的自動訂閱者設定資料類型之間的交集。每當該使用者產生這些類型的新資料時,系統就會將通知傳送至端點。無論使用者是在您建立訂閱者之前或之後授予同意聲明,這項功能都適用。系統不會為訂閱者建立前產生的資料補充通知。
如果使用者撤銷同意聲明,系統就會停止傳送相應資料類型的通知。自動訂閱項目由 Google 管理,無法個別列出或刪除,只有在刪除父項訂閱者時才會移除。
手動訂閱
如果訂閱者已針對特定資料類型設定 MANUAL subscription_create_policy,您必須為每位使用者明確建立及管理訂閱項目。訂閱會將特定使用者連結至訂閱者端點,以取得一組已定義的資料類型。開發人員可使用特定 API 執行下列操作:
- 建立 (手動) 訂閱項目 (每個
healthUserId) - 為特定使用者建立新的訂閱項目。使用這個方法時,訂閱者必須將所要求資料類型的SubscriptionCreatePolicy設為MANUAL。 - 更新 (手動) 訂閱項目 - 更新現有使用者訂閱項目的資料類型。
- 刪除 (手動) 訂閱方案 - 刪除特定使用者的訂閱方案。刪除後,訂閱端點就不會再收到與這個使用者相關的資料類型通知。
- 列出 (手動) 訂閱項目 - 列出特定訂閱者的所有有效訂閱項目。您可以依使用者或資料類型篩選結果。
通知
當訂閱資料類型的使用者資料有異動時,Google Health API 會向訂閱端點網址傳送 HTTPS POST 要求。
通知格式
通知酬載是 JSON 物件,內含資料變更的詳細資料。包括使用者 ID、資料類型和時間間隔,可用於查詢更新的資料。
{
"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"
}
}
]
}
}
「operation」欄位會指出觸發通知的變更類型:
UPSERT:在新增或修改任何資料時傳送。DELETE:使用者刪除資料時傳送。
建議您讓通知處理邏輯成為冪等,尤其是 UPSERT 作業,因為重試可能會導致系統傳送重複通知。
clientProvidedSubscriptionName 欄位是專屬 ID。如果是採用 MANUAL 政策的訂閱項目,這個欄位會包含訂閱項目建立時指定的永久性開發人員提供訂閱項目名稱。這個 ID 可用於管理手動訂閱項目。如果是使用 AUTOMATIC 政策建立的訂閱項目,Google Health API 會自動為每則通知產生專屬 ID (隨機 UUID),並指派給這個欄位。包括手動和自動政策,可確保所有訂閱類型都採用一致的通知酬載格式。clientProvidedSubscriptionName
healthUserId 是 Google Health API 的使用者 ID,用於識別資料已變更的使用者。如果應用程式支援多位使用者,您可能會收到已授予應用程式同意聲明的使用者通知。收到通知時,請使用 healthUserId 找出資料異動的使用者,然後使用他們的 OAuth 憑證查詢資料。
如要將使用者的 OAuth 憑證對應至 healthUserId,請使用 getIdentity 端點。在使用者加入時,使用者的憑證呼叫這個端點,即可擷取 healthUserId 並儲存這個對應。這項對應不會隨時間改變,因此可以無限期快取。如需範例,請參閱「取得使用者 ID」。這樣一來,您就能在根據通知中的 healthUserId 查詢資料時,選取正確的使用者憑證。
回應通知
伺服器必須立即以 HTTP 204 No Content 狀態碼回應通知。為避免逾時,請在傳送回應後,以非同步方式處理通知酬載。如果 Google Health API 收到任何其他狀態碼或要求逾時,系統稍後會重試傳送通知。
Node.js (Express) 範例:
app.post('/webhook-receiver', (req, res) => {
// 1. Immediately acknowledge the notification
res.status(204).send();
// 2. Process the data asynchronously in the background
const notification = req.body;
setImmediate(() => {
console.log(`Update for user ${notification.data.healthUserId} of type ${notification.data.dataType}`);
// Trigger your data retrieval logic here
});
});
驗證簽章
為確保 Webhook 通知的真實性,每則外寄 Webhook 通知的原始 JSON 酬載都會使用 Tink 的 PublicKeySign,以私密金鑰簽署,並在要求中的 GOOGLE-HEALTH-API-SIGNATURE HTTP 標頭提供 Base64 編碼簽章。這些簽署金鑰每 30 天會自動輪替,對應的官方公開金鑰集會以 JSON 檔案的形式,發布在永久網址 https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json。
如何驗證簽章
使用 Tink (建議):開發人員可以使用 Tink 的 PublicKeyVerify 原始類型驗證簽名。從永久網址擷取公開金鑰集,使用金鑰集例項化 PublicKeyVerify 基本類型,並根據原始 Webhook JSON 酬載驗證解碼的 GOOGLE-HEALTH-API-SIGNATURE 標頭。
手動驗證 (不使用 Tink):如果開發人員選擇不使用 Tink,可以按照下列步驟手動驗證簽章:
- 將
GOOGLE-HEALTH-API-SIGNATURE標頭進行 Base64 解碼,從實際的 DER 編碼簽章中,分離出 5 位元組的 Tink 前置字元 (其中包含 1 位元組的版本前置字元和 4 位元組的 keyId)。 - 從 https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json 擷取 JSON 金鑰組。
- 找出與已剖析 keyId 相符的金鑰,並對其值欄位進行 Base64 解碼,其中包含序列化的 EcdsaPublicKey 通訊協定緩衝區。
- 從這個二進位有效負載中,擷取大端序的 x 和 y 座標 (Protobuf 標記 3 和 4)。
- 使用擷取的 x 和 y 座標,在內建密碼編譯程式庫中,例項化標準 ECDSA P-256 公開金鑰。
- 使用 SHA-256 演算法,根據擷取的 DER 簽章驗證原始 Webhook JSON 酬載。
訂閱者狀態和復原
如果訂閱端點無法使用或傳回錯誤狀態碼 (204 以外的任何狀態碼),Google Health API 最多會儲存待處理通知 7 天,並以指數輪詢重試傳送通知。
端點恢復連線並以 204 回應後,API 就會自動傳送儲存的待處理訊息。系統會捨棄超過 7 天的通知,且無法復原。
常見錯誤
| 錯誤代碼 | 訊息 | 說明 | 建議 |
|---|---|---|---|
| 400 錯誤的要求 | 資源名稱中的專案編號無效 | 使用要求網址中的 Google Cloud 雲端專案 ID 刪除或更新訂閱者,而非專案編號。這適用於使用 projects.subscribers 端點的 Webhook 訂閱項目。 |
請在要求網址中使用 Google Cloud 專案編號,而非專案 ID。 |
| 403 Forbidden | 呼叫者沒有權限 | 使用 Google Cloud 雲端專案 ID 建立或列出訂閱端時,請在要求網址中加入專案 ID,而非專案編號。這適用於使用 projects.subscribers 端點的 Webhook 訂閱項目。 |
請在要求網址中使用 Google Cloud 專案編號,而非專案 ID。 |