Webhook サブスクリプション

Google Health API を使用すると、ユーザーの健康に関するデータが変更されたときに、アプリケーションでリアルタイム通知を受け取ることができます。変更をポーリングする代わりに、 Google Health API でデータが利用可能になるとすぐに、サーバーが HTTPS POST リクエスト(Webhook) を受信します。

サポートされるデータタイプ

Webhook 通知は、次のデータタイプでサポートされています。

  • アクティブ ゾーン時間
  • 高度
  • 体脂肪率
  • 心拍ゾーンのカロリー
  • 1 日の心拍変動
  • 1 日の心拍ゾーン
  • 1 日の酸素飽和度
  • 1 日の安静時の心拍数
  • 1 日の睡眠時の体温の変動
  • 距離
  • 運動
  • 階数
  • 心拍数
  • 睡眠
  • 歩数
  • 総カロリー
  • 体重

これらのデータタイプの通知は、ユーザーが対応するスコープのいずれかに同意した場合にのみ送信されます。

  • アクティビティ(歩数、高度、距離、階数のデータタイプをカバー):
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
  • 健康指標(体重のデータタイプをカバー):
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly
  • 睡眠(睡眠データタイプをカバー):
    • https://www.googleapis.com/auth/googlehealth.sleep
    • https://www.googleapis.com/auth/googlehealth.sleep.readonly

CPE のロール

Google Health API のサブスクライバーまたはサブスクリプションを管理するには、API 呼び出しを行う偽装されたサービス アカウントに適切なロールを付与する必要があります。 必要なアクセスレベルに応じて、次のいずれかのロールを割り当てます。

  • Google Health API 閲覧者
  • Google Health API 編集者
  • Google Health API 管理者

詳しくは、Google Health API の IAM ロールと権限をご覧ください

サブスクライバーを管理する

通知を受信するには、アプリケーションの通知エンドポイントを表すサブスクライバーを登録する必要があります。サブスクライバーは、 利用可能な REST API を使用して管理できます projects.subscribers

サブスクライバー エンドポイントは HTTPS(TLSv1.2 以降)を使用し、一般公開されている必要があります。 サブスクライバーの作成と更新の際に、Google Health API は検証チャレンジを実行して、エンドポイント URI を所有していることを確認します。検証に失敗すると、サブスクライバーの作成と更新のオペレーションは FailedPreconditionException で失敗します。

サブスクライバーを作成する

プロジェクトの新しいサブスクライバーを登録するには、 create エンドポイントを使用します。以下の情報を提供する必要があります。

  • project-id: Webhook サービス アカウントが作成されたプロジェクト番号。
  • subscriberId: サブスクライバーに指定する一意の識別子。この ID は 4 ~ 36 文字で、正規表現([a-z]([a-z0-9-]{2,34}[a-z0-9]))に一致する必要があります。
  • endpointUri: Webhook 通知のリンク先 URL。
  • subscriberConfigs: 通知を受信するデータタイプと、それぞれのサブスクリプション ポリシー。
  • endpointAuthorization: エンドポイントの認証メカニズム。これには、指定した secret が含まれている必要があります。secret の値は、各通知メッセージの Authorization ヘッダーで送信されます。このトークンを使用して、受信リクエストが Google Health API からのものであることを確認できます。たとえば、Bearer 認証の場合は secretBearer R4nd0m5tr1ng123 に設定し、基本認証の場合は 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 エンドポイント を使用して、プロジェクトのサブスクライバーを更新します。更新できるフィールドは、endpointUrisubscriberConfigsendpointAuthorization です。

フィールドを更新するには、updateMask クエリ パラメータとリクエスト本文を指定します。updateMask には、更新するフィールド名のカンマ区切りのリストを指定します。フィールド名にはキャメルケースを使用します(例: endpointUri)。リクエスト本文には、更新するフィールドの新しい値を含む部分的な Subscriber オブジェクトを指定する必要があります。updateMask で指定されたフィールドのみが更新されます。リクエスト本文に updateMask にないフィールドを指定すると、無視されます。

endpointUri または endpointAuthorization を更新すると、エンドポイントの確認が実行されます。詳細については、エンドポイントの確認をご覧ください。

subscriberConfigs を更新する場合、マージではなく完全な置換 であることに注意してください。subscriberConfigsupdateMask に含まれている場合、そのサブスクライバーの保存されているすべての構成は、リクエスト本文で指定されたリストで上書きされます。構成を追加または削除するには、構成の完全なセットを指定する必要があります。他のフィールドを更新し、現在の構成を維持する場合は、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 で必須の 2 段階認証プロセス ハンドシェイクが実行されます。このプロセスは、API 呼び出し中に同期的に実行されます。サービスは、User-Agent Google-Health-API-Webhooks-Verifier を使用して、JSON 本文 {"type": "verification"} を含む 2 つの自動 POST リクエストをエンドポイント URI に送信します。

  • 承認されたハンドシェイク: 構成済みの Authorizationヘッダーとともに最初のリクエストが送信されます。サーバーは 200 OK または 201 Created ステータスで応答する必要があります。
  • 未承認のチャレンジ: 2 番目のリクエストは認証情報なしで送信されます。 サーバーは 401 Unauthorized または 403 Forbidden ステータスで応答する必要があります。

このハンドシェイクにより、エンドポイントがアクティブで、セキュリティが正しく適用されていることが確認されます。いずれかのステップが失敗すると、API リクエストは FAILED_PRECONDITION エラーで失敗します。このハンドシェイクが成功した後にのみ、サブスクライバーが保存され、健康に関するデータの通知を受信できるように有効になります。

鍵のローテーション

endpointAuthorization の鍵をローテーションする必要がある場合は、次の手順を行います。

  1. 古い endpointAuthorization 値と新しい endpointAuthorization 値の両方を受け入れるようにエンドポイントを構成します。
  2. 新しい endpointAuthorization 値を使用して、patch リクエストでサブスクライバー構成を更新します。?updateMask=endpointAuthorization
  3. ステップ 2 が成功したことを確認したら、新しい endpointAuthorization 値のみを受け入れるようにエンドポイントを構成します。

ユーザーの登録

Google Health API を使用すると、ユーザー サブスクリプションを効率的に管理できるため、ユーザーのオンボーディング時に手動で登録する必要がなくなります。

自動サブスクリプション

自動サブスクリプションを使用することをおすすめします。この機能を有効にするには、特定のデータタイプの subscriberConfigssubscriptionCreatePolicyAUTOMATIC に設定します。AUTOMATIC ポリシーで指定した dataTypes は、ユーザーの同意がそれらのデータタイプにも付与されている場合に、Google Health API が通知を送信するデータタイプと同じです。

ユーザーが AUTOMATIC ポリシーのデータタイプに対応するスコープのアプリケーションの同意を付与すると、Google Health API は、ユーザーが同意したデータタイプと、そのユーザーの自動サブスクライバー構成データタイプの共通部分から得られるデータタイプを自動的に追跡して通知を送信します。その後、ユーザーがこれらのタイプの新しいデータを生成すると、通知がエンドポイントに送信されます。これは、サブスクライバーを作成する前または後に同意を付与するユーザーに有効です。サブスクライバーが作成される前に生成されたデータについては、通知はバックフィルされません。

ユーザーが同意を取り消すと、対応するデータタイプの通知は停止します。自動サブスクリプションは Google によって管理され、個別に一覧表示または削除することはできません。親サブスクライバーが削除された場合にのみ削除されます。

手動サブスクリプション

特定のデータタイプに対してサブスクライバーが MANUAL subscription_create_policy で構成されている場合は、ユーザーごとにサブスクリプションを明示的に作成して管理する必要があります。サブスクリプションは、特定のユーザーを定義されたデータタイプのセットに対してサブスクライバー エンドポイントにリンクします。デベロッパーは、特定の API を使用して次のことができます。

  • healthUserId ごとに(手動で)サブスクリプションを作成する - 特定のユーザーの新しい サブスクリプションを作成します。このメソッドでは、リクエストされたデータタイプに対してサブスクライバーの SubscriptionCreatePolicyMANUAL に設定されている必要があります。
  • (手動で)サブスクリプションを更新する - 既存のユーザー サブスクリプションのデータタイプを更新します。
  • (手動で)サブスクリプションを削除する - 特定のユーザー サブスクリプションを削除します。削除すると、サブスクライバー エンドポイントは、関連付けられたデータタイプについて、このユーザーの通知を受信しなくなります。
  • (手動で)サブスクリプションを一覧表示する - 特定のサブスクライバーのアクティブなサブスクリプションをすべて一覧表示します。結果は、ユーザーまたはデータタイプでフィルタできます。

通知

ユーザーのデータがサブスクライブされたデータタイプで変更されると、Google Health API は HTTPS POST リクエストをサブスクライバー エンドポイント URL に送信します。

通知形式

通知ペイロードは、データの変更に関する詳細を含む 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 フィールドは一意の識別子です。MANUAL ポリシーのサブスクリプションの場合、このフィールドには、サブスクリプションの作成時に指定された、デベロッパーが指定した永続的なサブスクリプション名が含まれます。これにより、手動サブスクリプションを管理するための固定 ID が提供されます。AUTOMATIC ポリシーで作成されたサブスクリプションの場合、Google Health API は、通知ごとにこのフィールドに一意の識別子(ランダムな UUID)を自動的に生成して割り当てます。手動ポリシーと自動ポリシーの両方に clientProvidedSubscriptionName を含めることで、すべてのサブスクリプション タイプで通知ペイロードの形式が統一されます。

healthUserId は、データが変更されたユーザーの Google Health API 識別子です。アプリケーションが複数のユーザーをサポートしている場合は、アプリケーションの同意を付与したユーザーの通知を受信できます。通知を受信したら、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's PublicKeySignを使用して秘密鍵で署名され、リクエストの GOOGLE-HEALTH-API-SIGNATURE HTTP ヘッダーに Base64 エンコードされた署名が提供されます。これらの署名鍵は 30 日ごとに自動的にローテーションされ、対応する公式の公開鍵セットは、永続的な URL https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json で JSON ファイルとして配布されます。

署名を検証する方法

Tink を使用する(推奨): デベロッパーは、Tink の PublicKeyVerify プリミティブを使用して署名を検証できます。永続的な URL から公開鍵セットを取得し、鍵セットで PublicKeyVerify プリミティブをインスタンス化して、デコードされた GOOGLE-HEALTH-API-SIGNATURE ヘッダーを未加工の Webhook JSON ペイロードと照合して検証します。

手動検証(Tink を使用しない): デベロッパーが Tink を使用しない場合は、 次の手順で署名を手動で検証できます。

  1. GOOGLE-HEALTH-API-SIGNATURE ヘッダーを Base64 でデコードして、5 バイトの Tink プレフィックス(1 バイトのバージョン プレフィックスと 4 バイトの keyId を含む)を実際の DER エンコードされた署名から分離します。
  2. https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json から JSON 鍵セットを取得します。
  3. 解析された keyId に一致する鍵を見つけて、シリアル化された EcdsaPublicKey Protocol Buffer を含む value フィールドを Base64 でデコードします。
  4. このバイナリ ペイロードからビッグエンディアンの x 座標と y 座標(Protobuf タグ 3 と 4)を抽出します。
  5. 抽出した x 座標と y 座標を使用して、組み込みの暗号ライブラリに標準の ECDSA P-256 公開鍵をインスタンス化します。
  6. SHA-256 アルゴリズムを使用して、抽出した DER 署名に対して未加工の Webhook JSON ペイロードを検証します。

サブスクライバーのステータスと復元

サブスクライバー エンドポイントが使用できなくなった場合、またはエラー ステータス コード(204 以外)を返した場合、Google Health API は保留中の通知を最大 7 日間保存し、指数バックオフで配信を再試行します。

エンドポイントがオンラインに戻り、204 で応答すると、API は保存されているメッセージのバックログを自動的に配信します。7 日以上前の通知は破棄され、復元できません。