API Google Health cho phép ứng dụng của bạn nhận thông báo theo thời gian thực khi dữ liệu sức khoẻ của người dùng thay đổi. Thay vì thăm dò ý kiến về các thay đổi, máy chủ của bạn sẽ nhận được webhook yêu cầu HTTPS POST ngay khi có dữ liệu trong Google Health API.
Các loại dữ liệu được hỗ trợ
Thông báo webhook được hỗ trợ cho các loại dữ liệu sau:
| Loại dữ liệu | Các thao tác có thể thực hiện |
Phạm vi |
|---|---|---|
|
Số phút hoạt động
dataType:
active-minutesfilter parameter: active_minutes
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Số phút hoạt động cho vùng nhịp tim
dataType:
active-zone-minutesfilter parameter: active_zone_minutes
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Mức độ hoạt động
dataType:
activity-levelfilter parameter: activity_level
Loại bản ghi: Khoảng thời gian
|
liệt kê, đối chiếu | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Altitude
dataType:
altitudefilter parameter: altitude
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Đường huyết
dataType:
blood-glucosefilter parameter: blood_glucose
Loại bản ghi: Mẫu
|
list, get, reconcile, rollup, dailyRollup | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Lượng mỡ trong cơ thể
dataType:
body-fatfilter parameter: body_fat
Loại bản ghi: Mẫu
Thiết bị tương thích
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Lượng calo trong vùng tần số tim
dataType:
calories-in-heart-rate-zonefilter parameter: calories_in_heart_rate_zone
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
|
rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Sự thay đổi tần số tim hằng ngày
dataType:
daily-heart-rate-variabilityfilter parameter: daily_heart_rate_variability
Loại bản ghi: Hằng ngày
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Vùng tần số tim hằng ngày
dataType:
daily-heart-rate-zonesfilter parameter: daily_heart_rate_zones
Loại bản ghi: Hằng ngày
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Độ bão hòa oxy hằng ngày
dataType:
daily-oxygen-saturationfilter parameter: daily_oxygen_saturation
Loại bản ghi: Hằng ngày
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Nhịp thở hằng ngày
dataType:
daily-respiratory-ratefilter parameter: daily_respiratory_rate
Loại bản ghi: Hằng ngày
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Tần số tim lúc nghỉ ngơi hằng ngày
dataType:
daily-resting-heart-ratefilter parameter: daily_resting_heart_rate
Loại bản ghi: Hằng ngày
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Độ lệch nhiệt độ khi ngủ hằng ngày
dataType:
daily-sleep-temperature-derivationsfilter parameter: daily_sleep_temperature_derivations
Loại bản ghi: Hằng ngày
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Khoảng cách
dataType:
distancefilter parameter: distance
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Tập thể dục
dataType:
exercisefilter parameter: exercise
Loại bản ghi: Phiên
Thiết bị tương thích
|
list, get, reconcile, create, update, batchDelete | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Tầng
dataType:
floorsfilter parameter: floors
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
|
reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Tần số tim
dataType:
heart-ratefilter parameter: heart_rate
Loại bản ghi: Mẫu
Độ phân giải của bộ nhớ: 1 giây
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Sự thay đổi tần số tim
dataType:
heart-rate-variabilityfilter parameter: heart_rate_variability
Loại bản ghi: Mẫu
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Chiều cao
|
list, get, reconcile, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Nhật ký về lượng nước uống
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .nutrition.readonly.nutrition.writeonly |
|
Nhật ký dinh dưỡng
dataType:
nutrition-logfilter parameter: nutrition_log
Loại bản ghi: Phiên
Thiết bị tương thích
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .nutrition.readonly.nutrition.writeonly |
|
Bản tóm tắt về nhịp thở khi ngủ
dataType:
respiratory-rate-sleep-summaryfilter parameter: respiratory_rate_sleep_summary
Loại bản ghi: Mẫu
Thiết bị tương thích
|
liệt kê, đối chiếu | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
|
Lượng oxy tối đa khi chạy
dataType:
run-vo2-maxfilter parameter: run_vo2_max
Loại bản ghi: Mẫu
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Thời gian ít vận động
dataType:
sedentary-periodfilter parameter: sedentary_period
Loại bản ghi: Khoảng thời gian
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Ngủ
dataType:
sleepfilter parameter: sleep
Loại bản ghi: Phiên
Thiết bị tương thích
|
list, get, reconcile, create, update, batchDelete | .sleep.readonly.sleep.writeonly |
|
Các bước
dataType:
stepsfilter parameter: steps
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
Thiết bị tương thích
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Thời gian ở vùng tần số tim
dataType:
time-in-heart-rate-zonefilter parameter: time_in_heart_rate_zone
Loại bản ghi: Khoảng thời gian
Giải pháp về bộ nhớ: 1 phút
|
list, reconcile, rollup, dailyRollup | .activity_and_fitness.readonly.activity_and_fitness.writeonly |
|
Trọng lượng
dataType:
weightfilter parameter: weight
Loại bản ghi: Mẫu
Thiết bị tương thích
|
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete | .health_metrics_and_measurements.readonly.health_metrics_and_measurements.writeonly |
Phạm vi thông báo
Thông báo chỉ được gửi cho các loại dữ liệu này khi người dùng đã đồng ý cho một trong các phạm vi tương ứng:
- Hoạt động, bao gồm các loại dữ liệu về số phút hoạt động, số bước, độ cao, khoảng cách và số tầng:
https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonlyhttps://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
- Chỉ số sức khoẻ, bao gồm loại dữ liệu cân nặng:
https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonlyhttps://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
- Giấc ngủ, bao gồm loại dữ liệu về giấc ngủ:
https://www.googleapis.com/auth/googlehealth.sleep.readonlyhttps://www.googleapis.com/auth/googlehealth.sleep.writeonly
Tài khoản dịch vụ IAM
Mặc dù không bắt buộc, nhưng bạn nên sử dụng Tài khoản dịch vụ IAM khi định cấu hình người đăng ký cho Google Health API. Tài khoản dịch vụ cung cấp khả năng bảo mật tốt hơn cho khối lượng công việc của ứng dụng so với tài khoản người dùng thông thường thông qua các tính năng sau:
- Thông tin xác thực ngắn hạn tự động: Khi được đính kèm vào một môi trường thực thi Google Cloud (chẳng hạn như Compute Engine, Cloud Run hoặc Google Kubernetes Engine), tài khoản dịch vụ sẽ tự động lấy và xoay vòng thông tin xác thực ngắn hạn, an toàn. Điều này giúp loại bỏ rủi ro khi quản lý và lưu trữ các khoá tĩnh cố định.
- Nguyên tắc về đặc quyền tối thiểu: Tài khoản dịch vụ cung cấp danh tính chuyên biệt cho khối lượng công việc. Bạn chỉ có thể cấp cho họ những quyền cụ thể cần thiết để quản lý điểm cuối của người đăng ký, tránh cấp quyền truy cập rộng hơn vào tài nguyên Google Cloud của bạn.
- Vòng đời độc lập: Tài khoản dịch vụ hoạt động độc lập với tài khoản của bất kỳ người dùng cá nhân nào, đảm bảo rằng những thay đổi về nhân sự không ảnh hưởng đến độ ổn định lâu dài của quy trình xác thực.
Thiết lập tài khoản dịch vụ
Cách định cấu hình ứng dụng của người đăng ký để xác thực bằng tài khoản dịch vụ:
- Tạo tài khoản dịch vụ: Trong Google Cloud Console, hãy chuyển đến trang IAM và Quản trị của dự án để tạo tài khoản dịch vụ mới do người dùng quản lý.
- Cấp các vai trò IAM cần thiết: Chỉ định cho tài khoản dịch vụ các vai trò phù hợp cần thiết để quản lý người đăng ký trong dự án trên đám mây của bạn.
- Đính kèm tài khoản dịch vụ vào khối lượng công việc: Định cấu hình môi trường lưu trữ logic của người đăng ký để chạy dưới dạng tài khoản dịch vụ mới.
Điều này cho phép mã xử lý ứng dụng (chẳng hạn như thư viện ứng dụng API của Google) tự động phát hiện và sử dụng thông tin xác thực tạm thời của tài khoản dịch vụ khi gọi API REST
projects.subscribers.
Vai trò CPE
Để quản lý Người đăng ký hoặc Gói thuê bao của Google Health API, bạn phải cấp vai trò thích hợp cho Tài khoản dịch vụ mạo danh thực hiện lệnh gọi API. Tuỳ thuộc vào cấp truy cập cần thiết, hãy chỉ định một trong các vai trò sau:
- Đọc Google Health API
- Trình chỉnh sửa Google Health API
- Quản trị viên Google Health API
Tìm hiểu thêm về vai trò và quyền của IAM trong Google Health API.
Quản lý người đăng ký
Trước khi có thể nhận thông báo, bạn phải đăng ký một Người đăng ký, đại diện cho điểm cuối thông báo của ứng dụng. Bạn có thể quản lý người đăng ký bằng API REST có tại projects.subscribers.
Điểm cuối của người đăng ký phải sử dụng HTTPS (TLSv1.2+) và có thể truy cập công khai.
Trong quá trình tạo và cập nhật người đăng ký, API Google Health sẽ thực hiện một thử thách xác minh để đảm bảo bạn sở hữu URI điểm cuối. Nếu quy trình xác minh không thành công, thì thao tác tạo và cập nhật người đăng ký sẽ không thành công và trả về lỗi FailedPreconditionException.
Tạo người đăng ký
Để đăng ký một người đăng ký mới cho dự án, hãy sử dụng điểm cuối create. Bạn cần cung cấp:
project-id: Số dự án nơi tài khoản dịch vụ webhook được tạo.subscriberId: Giá trị nhận dạng riêng biệt mà bạn cung cấp cho người đăng ký. Mã nhận dạng này phải có từ 4 đến 36 ký tự và khớp với biểu thức chính quy ([a-z]([a-z0-9-]{2,34}[a-z0-9])).endpointUri: URL đích cho thông báo webhook.subscriberConfigs: Các loại dữ liệu mà bạn muốn nhận thông báo và chính sách về gói thuê bao cho từng loại dữ liệu.endpointAuthorization: Cơ chế uỷ quyền cho điểm cuối của bạn. Tệp này phải chứa mộtsecretdo bạn cung cấp. Giá trị củasecretđược gửi trong tiêu đềAuthorizationcùng với mỗi thông báo. Bạn có thể sử dụng mã thông báo này để xác minh rằng các yêu cầu đến là từ Google Health API. Ví dụ: bạn có thể đặtsecretthànhBearer R4nd0m5tr1ng123cho phương thức xác thực Bearer hoặcBasic dXNlcjpwYXNzd29yZA==cho phương thức xác thực Cơ bản.
Trong subscriberConfigs, bạn phải đặt subscriptionCreatePolicy cho mỗi loại dữ liệu. Đặt thành AUTOMATIC để sử dụng gói thuê bao tự động hoặc MANUAL nếu bạn dự định tự quản lý gói thuê bao của người dùng. Hãy xem phần đăng ký tự động và đăng ký thủ công để biết thêm thông tin chi tiết về từng lựa chọn.
Yêu cầu
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"
}
}Phản hồi
{
"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"
}
]
}Người đăng ký danh sách
Sử dụng điểm cuối list để truy xuất tất cả người đăng ký đã đăng ký cho dự án của bạn.
Yêu cầu
GET https://health.googleapis.com/v4/projects/project-id/subscribers
Phản hồi
{
"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
}Cập nhật người đăng ký
Sử dụng điểm cuối patch để cập nhật người đăng ký trong dự án của bạn. Các trường có thể cập nhật là
endpointUri, subscriberConfigs và endpointAuthorization.
Bạn cập nhật các trường bằng cách cung cấp tham số truy vấn updateMask và nội dung yêu cầu. updateMask phải chứa danh sách được phân tách bằng dấu phẩy gồm tên trường mà bạn muốn cập nhật, sử dụng kiểu viết lạc đà cho tên trường (ví dụ: endpointUri). Nội dung yêu cầu phải chứa một phần đối tượng Người đăng ký có các giá trị mới cho những trường mà bạn muốn cập nhật. Chỉ những trường được chỉ định
trong updateMask mới được cập nhật. Nếu bạn cung cấp các trường trong nội dung yêu cầu không có trong updateMask, thì các trường đó sẽ bị bỏ qua.
Nếu bạn cập nhật endpointUri hoặc endpointAuthorization, thì quy trình xác minh điểm cuối sẽ được thực hiện. Hãy xem bài viết Xác minh điểm cuối để biết thông tin chi tiết.
Khi cập nhật subscriberConfigs, xin lưu ý rằng đây là thay thế toàn bộ, chứ không phải hợp nhất. Nếu subscriberConfigs có trong updateMask, thì tất cả cấu hình được lưu trữ cho người đăng ký đó sẽ được ghi đè bằng danh sách được cung cấp trong nội dung yêu cầu. Để thêm hoặc xoá một cấu hình, bạn phải cung cấp toàn bộ
cấu hình. Nếu bạn đang cập nhật các trường khác và muốn giữ nguyên cấu hình hiện tại, hãy bỏ qua subscriberConfigs khỏi updateMask.
Yêu cầu
PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id?updateMask=endpointUri
{
"endpointUri": "https://myapp.com/new-webhooks/health"
}Phản hồi
{
"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"
}
]
}Xoá người đăng ký
Sử dụng điểm cuối delete để xoá người đăng ký khỏi dự án của bạn. Sau khi bị xoá, người đăng ký
sẽ không nhận được thông báo nữa.
Yêu cầu
DELETE https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id
Phản hồi
Nội dung phản hồi trống có trạng thái HTTP "200 OK" sẽ được trả về nếu xoá thành công.{}Xác minh điểm cuối
Để đảm bảo tính bảo mật và độ tin cậy của việc gửi thông báo, Google Health API sẽ thực hiện quy trình bắt tay xác minh hai bước bắt buộc bất cứ khi nào bạn tạo người đăng ký hoặc cập nhật cấu hình điểm cuối (endpointUri hoặc endpointAuthorization). Quá trình này được thực hiện đồng bộ trong lệnh gọi API. Dịch vụ này gửi hai yêu cầu POST tự động đến URI điểm cuối của bạn,
sử dụng Tác nhân người dùng Google-Health-API-Webhooks, với nội dung JSON
{"type": "verification"}.
- Bắt tay được uỷ quyền: Yêu cầu đầu tiên được gửi cùng với tiêu đề
Authorizationmà bạn đã định cấu hình. Máy chủ của bạn phải phản hồi bằng trạng thái200 OKhoặc201 Created. - Thử thách không được uỷ quyền: Yêu cầu thứ hai được gửi mà không có thông tin xác thực.
Máy chủ của bạn phải phản hồi bằng trạng thái
401 Unauthorizedhoặc403 Forbidden.
Quá trình bắt tay này xác nhận rằng điểm cuối của bạn đang hoạt động và thực thi đúng cách
bảo mật. Nếu một trong hai bước không thành công, thì yêu cầu API sẽ không thành công và trả về lỗi FAILED_PRECONDITION. Chỉ sau khi quá trình bắt tay này thành công,
người đăng ký của bạn mới được lưu và kích hoạt để nhận thông báo về dữ liệu sức khoẻ.
Xoay vòng khoá
Nếu bạn cần xoay vòng khoá cho endpointAuthorization, hãy làm theo các bước sau:
- Định cấu hình điểm cuối để chấp nhận cả giá trị
endpointAuthorizationcũ và mới. - Cập nhật cấu hình người đăng ký bằng giá trị
endpointAuthorizationmới bằng cách sử dụng yêu cầupatchcó?updateMask=endpointAuthorization. - Định cấu hình điểm cuối để chỉ chấp nhận giá trị
endpointAuthorizationmới sau khi xác nhận bước 2 đã thành công.
Gói thuê bao của người dùng
Google Health API giúp bạn quản lý gói thuê bao của người dùng một cách hiệu quả, giảm nhu cầu đăng ký thủ công trong quá trình làm quen với người dùng.
Gói thuê bao tự động
Bạn nên sử dụng gói thuê bao tự động. Để bật tính năng này, hãy đặt subscriptionCreatePolicy thành AUTOMATIC trong subscriberConfigs cho các loại dữ liệu cụ thể. dataTypes mà bạn chỉ định bằng chính sách AUTOMATIC là cùng loại dữ liệu mà Google Health API gửi thông báo, miễn là sự đồng ý của người dùng cũng được cấp cho các loại dữ liệu đó.
Khi người dùng cấp quyền đồng ý cho ứng dụng đối với các phạm vi tương ứng với các loại dữ liệu có chính sách AUTOMATIC, API Google Health sẽ tự động theo dõi và gửi thông báo cho các loại dữ liệu là kết quả của giao điểm giữa các loại dữ liệu mà người dùng đồng ý và các loại dữ liệu cấu hình người đăng ký tự động cho người dùng đó. Sau đó, thông báo sẽ được gửi đến điểm cuối của bạn bất cứ khi nào người dùng đó tạo dữ liệu mới cho các loại dữ liệu đó. Cách này áp dụng cho những người dùng
đồng ý trước hoặc sau khi bạn tạo người đăng ký. Thông báo không được điền sẵn cho dữ liệu được tạo trước khi người đăng ký được tạo.
Nếu người dùng thu hồi sự đồng ý, thì thông báo cho các loại dữ liệu tương ứng sẽ dừng lại. Các gói thuê bao tự động do Google quản lý và không thể liệt kê hoặc xoá riêng lẻ; các gói thuê bao này chỉ bị xoá khi người đăng ký chính bị xoá.
Gói thuê bao thủ công
Nếu người đăng ký của bạn được định cấu hình bằng subscription_create_policy THỦ CÔNG cho các loại dữ liệu cụ thể, thì bạn phải tạo và quản lý gói thuê bao cho từng người dùng một cách rõ ràng. Gói thuê bao liên kết một người dùng cụ thể với điểm cuối của người đăng ký cho một nhóm loại dữ liệu đã xác định. Nhà phát triển có thể sử dụng các API cụ thể để:
- Tạo gói thuê bao (thủ công) cho mỗi
healthUserId– Tạo một gói thuê bao mới cho một người dùng cụ thể. Phương thức này yêu cầu người đăng ký phải cóSubscriptionCreatePolicyđược đặt thànhMANUALcho các loại dữ liệu được yêu cầu. - Cập nhật gói thuê bao (thủ công) – Cập nhật các loại dữ liệu cho gói thuê bao hiện có của người dùng.
- Xoá gói thuê bao (thủ công) – Xoá một gói thuê bao cụ thể của người dùng. Sau khi bị xoá, điểm cuối của người đăng ký sẽ không còn nhận được thông báo cho người dùng này về các loại dữ liệu liên quan.
- Liệt kê gói thuê bao (thủ công) – Liệt kê tất cả gói thuê bao đang hoạt động của một người đăng ký nhất định. Bạn có thể lọc kết quả theo người dùng hoặc loại dữ liệu.
Thông báo
Khi dữ liệu của người dùng thay đổi đối với một loại dữ liệu đã đăng ký, Google Health API sẽ gửi một yêu cầu POST qua HTTPS đến URL điểm cuối của người đăng ký.
Định dạng thông báo
Nội dung thông báo chứa thông tin chi tiết về thay đổi dữ liệu, bao gồm cả mã nhận dạng người dùng, loại dữ liệu và khoảng thời gian mà bạn có thể dùng để truy vấn dữ liệu đã cập nhật. Khi có nhiều thông tin cập nhật hoặc thông tin cập nhật được tổng hợp, các thông báo sẽ được gộp lại với nhau và được phân phối dưới dạng một mảng JSON gồm các đối tượng thông báo.
Khi một thông báo webhook được kích hoạt, API Google Health sẽ gửi một yêu cầu HTTPS POST đến điểm cuối của người đăng ký theo định dạng sau:
Upsert (dữ liệu chuỗi thời gian)
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"
}
}
]
}
}Xoá (dữ liệu chuỗi thời gian)
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"
}
}
]
}
}
]Xoá (dữ liệu nhận dạng)
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"
}
}Hàng loạt (nhiều người dùng và loại dữ liệu)
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"
}
}
]Trường operation cho biết loại thay đổi đã kích hoạt thông báo:
UPSERT: Được gửi cho mọi hoạt động bổ sung hoặc sửa đổi dữ liệu.DELETE: Được gửi khi người dùng xoá dữ liệu một cách rõ ràng (chẳng hạn như xoádataPointsbằng ứng dụng Fitbit hoặc xoá hàng loạt bằng API). Thông báo webhook không được gửi cho các sự kiện xoá ở cấp hệ thống, chẳng hạn như người dùng thu hồi quyền của ứng dụng hoặc xoá tài khoản Fitbit của họ.
Bạn nên đặt logic xử lý thông báo thành idempotent, đặc biệt là đối với các thao tác UPSERT, vì việc thử lại có thể khiến thông báo trùng lặp được gửi đi.
Trường clientProvidedSubscriptionName là một giá trị nhận dạng riêng biệt:
- Đối với các gói thuê bao có chính sách
MANUAL, trường này chứa tên gói thuê bao cố định do nhà phát triển cung cấp, được chỉ định khi tạo gói thuê bao. Điều này cung cấp một mã nhận dạng ổn định để quản lý các gói thuê bao thủ công. - Đối với các gói thuê bao được tạo bằng chính sách
AUTOMATIC, API Google Health sẽ tự động tạo và chỉ định một giá trị nhận dạng theo định dạng:auto-<project-number>-<subscriber-id>-<WEBHOOK_DATA_TYPE_TOKEN>, trong đó:<project-number>là số dự án trên Google Cloud của nhà phát triển (ví dụ:362978535920).<subscriber-id>là mã đăng ký / tên của người đăng ký (ví dụ:google-health-sync).<WEBHOOK_DATA_TYPE_TOKEN>là mã thông báo đại diện cho loại dữ liệu cụ thể. Xem Từ vựng về mã thông báo loại dữ liệu webhook để biết tất cả mã thông báo có thể có.
Việc đưa clientProvidedSubscriptionName vào cả chính sách thủ công và tự động sẽ đảm bảo định dạng tải trọng thông báo nhất quán trên tất cả các loại gói thuê bao.
Liên kết mã nhận dạng người dùng
healthUserId là giá trị nhận dạng API của Google Health cho người dùng có dữ liệu đã thay đổi. Nếu ứng dụng của bạn hỗ trợ nhiều người dùng, bạn có thể nhận
thông báo cho bất kỳ người dùng nào đã cấp sự đồng ý cho ứng dụng của bạn. Khi
bạn nhận được thông báo, hãy sử dụng healthUserId để xác định dữ liệu của người dùng nào
đã thay đổi, nhờ đó, bạn có thể sử dụng thông tin đăng nhập OAuth của họ để truy vấn dữ liệu của họ.
Để liên kết thông tin đăng nhập OAuth của người dùng với healthUserId của họ, hãy sử dụng điểm cuối getIdentity. Gọi điểm cuối này bằng thông tin đăng nhập của người dùng trong quá trình làm quen với người dùng để truy xuất healthUserId của họ và lưu trữ mối liên kết này. Ánh xạ này không thay đổi theo thời gian, vì vậy, bạn có thể lưu vào bộ nhớ đệm vô thời hạn. Để biết ví dụ, hãy xem phần Lấy mã nhận dạng người dùng. Điều này cho phép bạn chọn thông tin xác thực chính xác của người dùng khi truy vấn dữ liệu dựa trên healthUserId trong thông báo.
Khoảng thời gian
Mảng intervals chứa một hoặc nhiều đối tượng đại diện cho khoảng thời gian của dữ liệu đã sửa đổi:
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
physicalTimeInterval |
object |
Không | Khoảng thời gian thực tế theo giờ UTC của dữ liệu đã sửa đổi (định dạng YYYY-MM-DDTHH:MM:SSZ). Được điền sẵn cho các chỉ số trong ngày; bị bỏ qua đối với các bản tổng hợp hằng ngày và hoạt động cả ngày. |
civilDateTimeInterval |
object |
Có | Khoảng thời gian và ngày theo lịch dân sự (địa phương) của dữ liệu đã sửa đổi, không có độ lệch UTC hoặc múi giờ. |
civilIso8601TimeInterval |
object |
Có | Khoảng thời gian dân sự (địa phương) được biểu thị dưới dạng chuỗi ISO 8601 (định dạng YYYY-MM-DDTHH:MM:SS) không có độ lệch UTC hoặc múi giờ. |
Đối với các hoạt động cả ngày và dữ liệu tổng hợp hằng ngày, trường physicalTimeInterval sẽ được cố ý bỏ qua khỏi tải trọng thông báo. Điều này là do
các sự kiện cả ngày được nhóm theo ngày dân sự danh nghĩa và
khoảng thời gian thực tế có thể không chính xác khi vượt qua các múi giờ. Khi xử lý các sự kiện cả ngày, bạn nên dựa vào các trường civilDateTimeInterval hoặc civilIso8601TimeInterval theo phương pháp hay nhất. Để biết thông tin chi tiết về cách truy vấn các điểm dữ liệu này bằng bộ lọc thời gian dân sự, hãy xem bài viết Lọc dữ liệu theo thời gian bắt đầu dân sự của khoảng thời gian.
Sau đây là ví dụ về tải trọng thông báo cho một hoạt động cả ngày, trong đó trường physicalTimeInterval bị bỏ qua:
{
"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"
}
}
]
}
}Từ vựng về mã thông báo loại dữ liệu webhook
Khi sử dụng chính sách AUTOMATIC, clientProvidedSubscriptionName được tạo sẽ chứa một trong các mã thông báo hậu tố WEBHOOK_DATA_TYPE_* viết hoa sau đây, tuỳ thuộc vào loại dữ liệu:
| Mã thông báo loại dữ liệu webhook | Kiểu dữ liệu tương ứng |
|---|---|
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 (sự kiện hệ thống) |
WEBHOOK_DATA_TYPE_USER_REVOKED_ACCESS |
user-revoked-access (sự kiện hệ thống) |
Tổng hợp thông tin cập nhật
Để giảm thiểu lưu lượng truy cập mạng, Google Health API sẽ gộp các thông báo lại với nhau. Hệ thống được định cấu hình để gửi tối đa 99 thông báo mỗi lô, được tự động đẩy khi có sẵn.
Khi các thông báo được gửi theo lô, tải trọng sẽ được phân phối dưới dạng một mảng JSON chứa nhiều đối tượng thông báo. Một lô có thể bao gồm thông tin cập nhật cho nhiều người dùng trên nhiều loại dữ liệu đã đăng ký. Để xem tải trọng mẫu, hãy xem ví dụ về Hàng loạt (nhiều người dùng và loại dữ liệu) trong phần Định dạng thông báo.
Phản hồi thông báo
Máy chủ của bạn phải xác thực tiêu đề Authorization, xử lý quá trình bắt tay xác minh điểm cuối đồng bộ và phản hồi ngay lập tức các thông báo thay đổi dữ liệu bằng mã trạng thái HTTP 204 No Content. Để tránh hết thời gian chờ, hãy xử lý tải trọng thông báo không đồng bộ sau khi gửi phản hồi. Nếu Google Health API nhận được bất kỳ mã trạng thái nào khác hoặc yêu cầu hết thời gian chờ, thì API này sẽ thử gửi lại thông báo sau.
Ví dụ về 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).
}
});
});
Để tìm nạp dữ liệu đã cập nhật cho từng khoảng thời gian được thông báo, hãy gọi điểm cuối reconcile bằng một bộ lọc cho phạm vi thời gian của khoảng thời gian đó. Thao tác này sẽ tự động loại bỏ các khoảng thời gian trùng lặp trên các thiết bị thông minh đã kết nối. Để biết thông tin chi tiết và ví dụ, hãy xem bài viết Xem dữ liệu khoảng thời gian đã điều chỉnh.
Có 3 chiến lược phổ biến để cập nhật cơ sở dữ liệu sau khi nhận được thông báo thay đổi dữ liệu:
- Xếp hàng đợi (nên dùng): Đặt thông báo đến vào hàng đợi thông báo và xử lý thông báo đó dựa trên tài nguyên hệ thống.
- Truy xuất ngay lập tức: Chỉ dẫn phần phụ trợ của bạn gọi ngay Google Health API để tìm nạp dữ liệu đã cập nhật và đưa dữ liệu đó vào cơ sở dữ liệu của bạn.
- Cập nhật từng phần: Đánh dấu bản ghi cơ sở dữ liệu cục bộ của người dùng là không hợp lệ và chỉ tìm nạp dữ liệu đã cập nhật từ Google Health API khi người dùng truy cập vào ứng dụng của bạn vào lần tiếp theo.
Chiến lược xếp hàng đợi cho phép bạn xử lý dữ liệu gần như theo thời gian thực trong khi vẫn có khả năng phục hồi trước một loạt thông báo (ví dụ: nếu sự cố ngừng dịch vụ khiến một loạt thông báo tồn đọng được gửi cùng một lúc). Mặc dù bạn có thể chọn xử lý các hàng đợi này theo lịch trình theo lô có khoảng thời gian dài (ví dụ: mỗi 3 giờ) để tiết kiệm tài nguyên, nhưng nhược điểm là người dùng thường mong đợi thấy dữ liệu của họ được cập nhật gần như theo thời gian thực.
Các phương pháp hay nhất
Hãy làm theo các phương pháp hay nhất sau đây để đảm bảo việc xử lý các bản cập nhật dữ liệu một cách đáng tin cậy và hiệu quả:
- Sử dụng Subscription API: Sử dụng Subscription API để nhận thông báo khi người dùng có dữ liệu mới để tải xuống thay vì thăm dò ý kiến về các điểm cuối.
- Xếp hàng đợi và xử lý thông báo riêng biệt: Khi nhận được thông báo về gói thuê bao, hãy đưa thông báo vào hàng đợi và xử lý riêng biệt dựa trên tài nguyên của hệ thống. Giữ cho điểm cuối webhook gọn nhẹ bằng cách xác nhận yêu cầu ngay lập tức.
Xác minh chữ ký
Để đảm bảo tính xác thực của thông báo Webhook, tải trọng JSON thô của mọi thông báo webhook gửi đi đều được ký bằng khoá riêng tư bằng cách sử dụng PublicKeySign của Tink, cung cấp chữ ký được mã hoá Base64 trong tiêu đề HTTP GOOGLE-HEALTH-API-SIGNATURE trong yêu cầu. Các khoá ký này được tự động xoay vòng sau mỗi 30 ngày và tập hợp khoá công khai chính thức tương ứng được phân phối dưới dạng tệp JSON tại URL cố định https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.
Cách xác minh chữ ký
Sử dụng Tink (Nên dùng): Nhà phát triển có thể xác minh chữ ký bằng cách sử dụng dữ liệu gốc PublicKeyVerify của Tink. Tìm nạp bộ khoá công khai từ URL cố định, tạo thực thể cho dữ liệu gốc PublicKeyVerify bằng bộ khoá và xác minh tiêu đề GOOGLE-HEALTH-API-SIGNATURE đã giải mã dựa trên tải trọng JSON thô của webhook.
Xác minh thủ công (Không có Tink): Nếu chọn không sử dụng Tink, nhà phát triển có thể xác minh chữ ký theo cách thủ công bằng cách làm theo các bước sau:
- Giải mã Base64 cho tiêu đề
GOOGLE-HEALTH-API-SIGNATUREđể tách tiền tố Tink 5 byte (chứa tiền tố phiên bản 1 byte và keyId 4 byte) khỏi chữ ký được mã hoá DER thực tế. - Tìm nạp tập hợp khoá JSON từ https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.
- Tìm khoá khớp với keyId đã phân tích cú pháp và giải mã Base64 trường giá trị của khoá đó, chứa vùng đệm giao thức EcdsaPublicKey được chuyển đổi tuần tự.
- Trích xuất toạ độ x và y big-endian (thẻ Protobuf 3 và 4) từ tải trọng nhị phân này.
- Tạo thực thể cho khoá công khai ECDSA P-256 tiêu chuẩn trong thư viện mật mã tích hợp sẵn bằng cách sử dụng toạ độ x và y đã trích xuất.
- Xác minh tải trọng JSON thô của webhook dựa trên chữ ký DER đã trích xuất bằng thuật toán SHA-256.
Trạng thái người đăng ký và khôi phục
Nếu điểm cuối của người đăng ký không hoạt động hoặc trả về mã trạng thái lỗi (bất kỳ mã nào khác ngoài 204), thì Google Health API sẽ lưu trữ các thông báo đang chờ xử lý trong tối đa 7 ngày và thử gửi lại theo thuật toán thời gian đợi luỹ thừa.
Sau khi điểm cuối của bạn hoạt động trở lại và phản hồi bằng 204, API sẽ tự động phân phối các tin nhắn tồn đọng đã lưu trữ. Thông báo cũ hơn 7 ngày sẽ bị loại bỏ và không thể khôi phục.
Lỗi thường gặp
| Mã lỗi | Nhắn tin | Mô tả | Nội dung đề xuất |
|---|---|---|---|
| 400 Yêu cầu không hợp lệ | Số dự án không hợp lệ trong tên tài nguyên | Khi xoá hoặc cập nhật một người đăng ký bằng mã dự án trên Google Cloud trong URL yêu cầu thay vì số dự án. Điều này áp dụng cho các gói thuê bao webhook sử dụng điểm cuối projects.subscribers. |
Sử dụng số dự án trên đám mây của Google trong URL yêu cầu, chứ không phải mã dự án. |
| 403 Bị cấm | Phương thức gọi không có quyền | Khi tạo hoặc liệt kê người đăng ký bằng mã dự án Google Cloud trong URL yêu cầu thay vì số dự án. Điều này áp dụng cho các gói thuê bao webhook sử dụng điểm cuối projects.subscribers. |
Sử dụng số dự án trên đám mây của Google trong URL yêu cầu, chứ không phải mã dự án. |