Webhook サブスクリプション

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

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

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

  • アクティブ ゾーン時間
  • アクティビティ レベル
  • 高度
  • 血糖値
  • 体脂肪率
  • 心拍ゾーンの消費カロリー
  • 1 日の心拍変動
  • 1 日の心拍ゾーン
  • 毎日の酸素飽和度
  • 1 日の呼吸数
  • 1 日の安静時の心拍数
  • 毎日の睡眠時の体温の変動
  • 距離
  • 演習
  • 階数
  • 心拍数
  • 心拍変動
  • 高さ
  • 水分摂取量の記録
  • 栄養摂取量の記録
  • 呼吸数の睡眠の概要
  • ランニング時の最大酸素摂取量
  • 座りがち期間
  • 睡眠
  • 手順
  • 心拍ゾーンの時間
  • 総カロリー
  • 重量

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

  • アクティビティ: 歩数、高度、距離、階数のデータ型をカバーします。
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
  • 健康指標(体重データ型を含む):
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
  • 睡眠。睡眠データ型を対象とします。
    • https://www.googleapis.com/auth/googlehealth.sleep.readonly
    • https://www.googleapis.com/auth/googlehealth.sleep.writeonly

IAM サービス アカウント

必須ではありませんが、Google Health API のサブスクライバーを構成する際は、IAM サービス アカウントを使用することをおすすめします。サービス アカウントは、次の機能により、標準のユーザー アカウントよりもアプリケーション ワークロードのセキュリティを強化します。

  • 有効期間の短い認証情報の自動化: Google Cloud 実行環境(Compute Engine、Cloud Run、Google Kubernetes Engine など)に接続すると、サービス アカウントは安全で有効期間の短い認証情報を自動的に取得してローテーションします。これにより、永続的な静的キーの管理と保存のリスクがなくなります。
  • 最小権限の原則: サービス アカウントは、ワークロード専用の ID を提供します。サブスクライバー エンドポイントの管理に必要な特定の権限のみを付与できるため、Google Cloud リソースへの広範なアクセスを回避できます。
  • ライフサイクルの独立性: サービス アカウントは個々のユーザーのアカウントとは独立して動作するため、人事異動が長期的な認証の安定性に影響することはありません。

サービス アカウントを設定する

サービス アカウントを使用して認証するようにサブスクライバー アプリケーションを構成するには:

  1. サービス アカウントを作成する: Google Cloud コンソールで、プロジェクトの [IAM と管理] ページに移動して、新しいユーザー管理サービス アカウントを作成します。
  2. 必要な IAM ロールを付与する: サービス アカウントに、Google Cloud プロジェクトでサブスクライバーを管理するために必要な適切なロールを割り当てます。
  3. サービス アカウントをワークロードに接続します。 新しいサービス アカウントとして実行するようにサブスクライバー ロジックをホストする環境を構成します。これにより、アプリケーション コード(Google API クライアント ライブラリなど)は、projects.subscribers REST API を呼び出すときに、サービス アカウントの有効期間の短い認証情報を自動的に検出して使用できます。

CPE のロール

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

  • Google Health API 読み取り
  • 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: ウェブフック サービス アカウントが作成されたプロジェクト番号。
  • 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 認証の場合は 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` の空のレスポンス本文が返されます。
{}

エンドポイントの確認

通知配信のセキュリティと信頼性を確保するため、Google Health API は、サブスクライバーを作成するたび、またはエンドポイント構成(endpointUri または endpointAuthorization)を更新するたびに、必須の 2 段階認証プロセス ハンドシェイクを実行します。このプロセスは、API 呼び出し中に同期的に実行されます。サービスは、User-Agent Google-Health-API-Webhooks-Verifier を使用して、エンドポイント URI に 2 つの自動 POST リクエストを送信します。JSON 本文は {"type": "verification"} です。

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

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

鍵のローテーション

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

  1. 古い endpointAuthorization 値と新しい endpointAuthorization 値の両方を受け入れるようにエンドポイントを構成します。
  2. ?updateMask=endpointAuthorization を含む patch リクエストを使用して、新しい 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 に設定されている必要があります。
  • Update(手動)サブスクリプション - 既存のユーザー サブスクリプションのデータ型を更新します。
  • Delete (manual) subscription(サブスクリプションの削除(手動)) - 特定のユーザーのサブスクリプションを削除します。削除すると、サブスクライバー エンドポイントは、関連付けられたデータタイプについて、このユーザーの通知を受信しなくなります。
  • List (manual) subscriptions - 特定の購読者のアクティブな定期購入をすべて一覧表示します。結果をユーザーまたはデータタイプでフィルタできます。

通知

ユーザーのデータが登録されたデータ型で変更されると、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 の 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 を含む)を 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 日以上前の通知は破棄され、復元できません。

一般的なエラー

エラーコード メッセージ 説明 推奨事項
400 不正なリクエスト リソース名に無効なプロジェクト番号が含まれています リクエスト URL でプロジェクト番号の代わりに Google Cloud プロジェクト ID を使用してサブスクライバーを削除または更新する場合。これは、projects.subscribers エンドポイントを使用する Webhook サブスクリプションに適用されます。 リクエスト URL には、プロジェクト ID ではなく Google Cloud プロジェクト番号を使用します。
403 Forbidden(アクセス拒否) The caller does not have permission リクエスト URL でプロジェクト番号の代わりに Google Cloud プロジェクト ID を使用してサブスクライバーを作成または一覧表示する場合。これは、projects.subscribers エンドポイントを使用する Webhook サブスクリプションに適用されます。 リクエスト URL には、プロジェクト ID ではなく Google Cloud プロジェクト番号を使用します。