웹훅 구독

Google Health API를 사용하면 사용자의 건강 데이터가 변경될 때 애플리케이션에서 실시간 알림을 수신할 수 있습니다. 서버는 변경사항을 폴링하는 대신 Google Health API에서 데이터를 사용할 수 있게 되면 즉시 HTTPS POST 요청 (웹훅)을 수신합니다.

지원되는 데이터 유형

웹훅 알림은 다음 데이터 유형에 지원됩니다.

  • 액티브존 미닛
  • 고도
  • 체지방
  • 심박수 구간별 칼로리
  • 일일 심박 변이도
  • 일일 심박수 구간
  • 일일 산소 포화도
  • 일일 안정 시 심박수
  • 일일 수면 온도 파생
  • 거리
  • 운동
  • 층수
  • 심박수
  • 수면
  • 단계
  • 총 칼로리
  • 무게

알림은 사용자가 다음 중 하나에 해당하는 범위에 동의한 경우에만 이러한 데이터 유형에 전송됩니다.

  • 활동, 단계, 고도, 거리, 층수 데이터 유형을 포함하는:
    • 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

구독자 관리

알림을 받으려면 애플리케이션의 알림 엔드포인트를 나타내는 구독자를 등록해야 합니다. `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: 웹훅 알림의 도착 URL입니다.
  • subscriberConfigs: 알림을 수신하려는 데이터 유형과 각 데이터 유형의 구독 정책입니다.
  • endpointAuthorization: 엔드포인트의 인증 메커니즘입니다. 여기에는 제공하는 secret이 포함되어야 합니다. secret의 값은 각 알림 메시지와 함께 Authorization 헤더에 전송됩니다. 이 토큰을 사용하여 수신 요청이 Google Health API에서 전송된 것인지 확인할 수 있습니다. 예를 들어 전달자 인증의 경우 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 엔드포인트 를 사용하여 프로젝트의 구독자를 업데이트합니다. 업데이트할 수 있는 필드는 endpointUri, subscriberConfigs, endpointAuthorization입니다.

updateMask 쿼리 매개변수와 요청 본문을 제공하여 필드를 업데이트합니다. updateMask에는 업데이트하려는 필드 이름의 쉼표로 구분된 목록이 포함되어야 하며 필드 이름에는 카멜 케이스를 사용해야 합니다(예: endpointUri). 요청 본문에는 업데이트하려는 필드의 새 값이 포함된 부분 구독자 객체가 포함되어야 합니다. updateMask에 지정된 필드만 업데이트됩니다. 요청 본문에 updateMask에 없는 필드를 제공하면 무시됩니다.

endpointUri 또는 endpointAuthorization을 업데이트하면 엔드포인트 확인 기능이 실행됩니다. 자세한 내용은 엔드포인트 확인 기능을 참고하세요.

subscriberConfigs를 업데이트할 때는 병101}병합이 아닌 전체 대체입니다. 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 호출 중에 동기식으로 실행됩니다. 서비스는 엔드포인트 URI로 자동화된 POST 요청 두 개를 전송합니다. 사용자 에이전트 Google-Health-API-Webhooks-Verifier를 사용하며 JSON 본문은 {"type": "verification"}입니다.

  • 승인된 핸드셰이크: 첫 번째 요청은 구성된 Authorization 헤더와 함께 전송됩니다. 서버는 200 OK 또는 201 Created 상태로 응답해야 합니다.
  • 승인되지 않은 보안 질문: 두 번째 요청은 사용자 인증 정보 없이 전송됩니다. 서버는 401 Unauthorized 또는 403 Forbidden 상태로 응답해야 합니다.

이 핸드셰이크는 엔드포인트가 활성 상태이고 보안을 올바르게 적용하고 있음을 확인합니다. 두 단계 중 하나라도 실패하면 API 요청이 FAILED_PRECONDITION 오류와 함께 실패합니다. 이 핸드셰이크가 성공한 후에만 구독자가 저장되고 건강 데이터 알림을 수신하도록 활성화됩니다.

키 순환

endpointAuthorization의 키를 순환해야 하는 경우 다음 단계를 따르세요.

  1. 이전 및 새 endpointAuthorization 값을 모두 허용하도록 엔드포인트를 구성합니다.
  2. endpointAuthorization 값으로 구독자 구성을 업데이트합니다. patch 요청과 함께 ?updateMask=endpointAuthorization를 사용합니다.
  3. 2단계가 성공했는지 확인한 후 새 endpointAuthorization 값만 허용하도록 엔드포인트를 구성합니다.

사용자 구독

Google Health API를 사용하면 사용자 구독을 효율적으로 관리하여 사용자 온보딩 중에 수동 등록이 필요하지 않습니다.

자동 구독

자동 구독을 사용하는 것이 좋습니다. 이 기능을 사용 설정하려면 특정 데이터 유형의 subscriberConfigs에서 subscriptionCreatePolicyAUTOMATIC으로 설정합니다. AUTOMATIC 정책으로 지정하는 dataTypes는 Google Health API에서 알림을 전송하는 데이터 유형과 동일하며, 이러한 데이터 유형에 대한 사용자 동의도 부여됩니다.

사용자가 AUTOMATIC 정책이 있는 데이터 유형에 해당하는 범위에 애플리케이션 동의를 부여하면 Google Health API는 사용자 동의 후 수집된 데이터 유형과 해당 사용자의 자동 구독자 구성 데이터 유형 간의 교집합에서 발생하는 데이터 유형을 자동으로 추적하고 알림을 전송합니다. 그러면 사용자가 이러한 유형의 새 데이터를 생성할 때마다 엔드포인트로 알림이 전송됩니다. 이는 구독자를 만들기 전이나 후에 동의를 부여하는 사용자에게 적용됩니다. 구독자가 생성되기 전에 생성된 데이터에 대해서는 알림이 백필되지 않습니다.

사용자가 동의를 철회하면 해당 데이터 유형의 알림이 중지됩니다. 자동 구독은 Google에서 관리하며 개별적으로 나열하거나 삭제할 수 없습니다. 상위 구독자가 삭제될 때만 삭제됩니다.

수동 구독

각 사용자의 구독을 수동으로 관리하려면 subscriberConfigs에서 subscriptionCreatePolicyMANUAL로 설정합니다. 이 정책을 사용하면 사용자 구독이 자동으로 생성되지 않습니다. 이 기능은 수동 구독을 관리하는 API가 제공될 때 향후에 사용됩니다. 이러한 API가 제공될 때까지 AUTOMATIC 구독을 사용하는 것이 좋습니다.

알림

사용자가 구독한 데이터 유형의 데이터가 변경되면 Google Health API는 구독자 엔드포인트 URL로 HTTPS POST 요청을 전송합니다.

알림 형식

알림 페이로드는 데이터 변경에 관한 세부정보가 포함된 JSON 객체입니다. 여기에는 업데이트된 데이터를 쿼리하는 데 사용할 수 있는 사용자 ID, 데이터 유형, 시간 간격이 포함됩니다.

{
  "data": {
    "version": "1",
    "clientProvidedSubscriptionName": "subscription-name",
    "healthUserId": "health-user-id",
    "operation": "UPSERT",
    "dataType": "steps",
    "intervals": [
      {
        "physicalTimeInterval": {
          "startTime": "2026-03-0B01: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
    });
});

구독자 상태 및 복구

구독자 엔드포인트를 사용할 수 없게 되거나 오류 상태 코드(204 이외의 코드)를 반환하면 Google Health API는 최대 7일 동안 대기 중인 알림을 저장하고 지수 백오프로 전송을 재시도합니다.

엔드포인트가 다시 온라인 상태가 되고 204로 응답하면 API는 저장된 메시지 백로그를 자동으로 전송합니다. 7일이 지난 알림은 삭제되며 복구할 수 없습니다.