Webhook-Abos

Mit der Google Health API kann Ihre Anwendung Echtzeitbenachrichtigungen erhalten, wenn sich die Gesundheitsdaten eines Nutzers ändern. Anstatt nach Änderungen zu suchen, empfängt Ihr Server einen HTTPS-POST-Anfrage-Webhook, sobald Daten in der Google Health API verfügbar sind.

Unterstützte Datentypen

Webhook-Benachrichtigungen werden für die folgenden Datentypen unterstützt:

Tabelle: Google Health API-Datentypen mit Webhook-Unterstützung
Datentyp Verfügbare
-Vorgänge
Bereich
Aktive Minuten
dataType: active-minutes
filter parameter: active_minutes
Eintragstyp: Intervall
Speicherauflösung: 1 Minute

Kompatible Geräte

  • Fitbit Air
  • Fitbit Alta
  • Fitbit Alta HR
  • Fitbit Blaze
  • Fitbit Charge 2
  • Fitbit Charge 3
  • Fitbit Flex 2
  • Fitbit Inspire
  • Fitbit Inspire HR
  • Pixel Watch 4
list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Aktivzonenminuten
dataType: active-zone-minutes
filter parameter: active_zone_minutes
Eintragstyp: Intervall
Speicherauflösung: 1 Minute

Kompatible Geräte

list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Aktivitätsniveau
dataType: activity-level
filter parameter: activity_level
Eintragstyp: Intervall
list, reconcile .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Altitude
dataType: altitude
filter parameter: altitude
Eintragstyp: Intervall
Speicherauflösung: 1 Minute
list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Blutzucker
dataType: blood-glucose
filter parameter: blood_glucose
Eintragstyp: Beispiel
list, get, reconcile, rollup, dailyRollup .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Körperfett
dataType: body-fat
filter parameter: body_fat
Eintragstyp: Beispiel

Kompatible Geräte

list, get, reconcile, rollup, dailyRollup, create, update, batchDelete .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Kalorien in Herzfrequenzzone
dataType: calories-in-heart-rate-zone
filter parameter: calories_in_heart_rate_zone
Eintragstyp: Intervall
Speicherauflösung: 1 Minute
rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Tägliche Herzfrequenzvariabilität
dataType: daily-heart-rate-variability
filter parameter: daily_heart_rate_variability
Eintragstyp: Täglich

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Tägliche Herzfrequenzzonen
dataType: daily-heart-rate-zones
filter parameter: daily_heart_rate_zones
Eintragstyp: Täglich
list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Tägliche Sauerstoffsättigung
dataType: daily-oxygen-saturation
filter parameter: daily_oxygen_saturation
Eintragstyp: Täglich

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Tägliche Atemfrequenz
dataType: daily-respiratory-rate
filter parameter: daily_respiratory_rate
Eintragstyp: Täglich

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Tägliche Ruheherzfrequenz
dataType: daily-resting-heart-rate
filter parameter: daily_resting_heart_rate
Eintragstyp: Täglich

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Tägliche Abweichungen der Schlaftemperatur
dataType: daily-sleep-temperature-derivations
filter parameter: daily_sleep_temperature_derivations
Eintragstyp: Täglich

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Entfernung
dataType: distance
filter parameter: distance
Eintragstyp: Intervall
Speicherauflösung: 1 Minute

Kompatible Geräte

list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Training
dataType: exercise
filter parameter: exercise
Eintragstyp: Sitzung

Kompatible Geräte

list, get, reconcile, create, update, batchDelete .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Stockwerke
dataType: floors
filter parameter: floors
Eintragstyp: Intervall
Speicherauflösung: 1 Minute
reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Herzfrequenz
dataType: heart-rate
filter parameter: heart_rate
Eintragstyp: Beispiel
Speicherauflösung: 1 Sekunde

Kompatible Geräte

list, reconcile, rollup, dailyRollup .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Herzfrequenzvariabilität
dataType: heart-rate-variability
filter parameter: heart_rate_variability
Eintragstyp: Beispiel

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Höhe
dataType: height
filter parameter: height
Eintragstyp: Beispiel
list, get, reconcile, create, update, batchDelete .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Flüssigkeitszufuhr-Protokoll
dataType: hydration-log
filter parameter: hydration_log
Eintragstyp: Sitzung
list, get, reconcile, rollup, dailyRollup, create, update, batchDelete .nutrition.readonly
.nutrition.writeonly
Ernährungsprotokoll
dataType: nutrition-log
filter parameter: nutrition_log
Eintragstyp: Sitzung

Kompatible Geräte

list, get, reconcile, rollup, dailyRollup, create, update, batchDelete .nutrition.readonly
.nutrition.writeonly
Atemfrequenz-Schlafanalyse
dataType: respiratory-rate-sleep-summary
filter parameter: respiratory_rate_sleep_summary
Eintragstyp: Beispiel

Kompatible Geräte

list, reconcile .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly
Maximale Sauerstoffaufnahme bei Lauf
dataType: run-vo2-max
filter parameter: run_vo2_max
Eintragstyp: Beispiel

Kompatible Geräte

list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Inaktive Zeit
dataType: sedentary-period
filter parameter: sedentary_period
Eintragstyp: Intervall

Kompatible Geräte

list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Schlaf
dataType: sleep
filter parameter: sleep
Eintragstyp: Sitzung

Kompatible Geräte

list, get, reconcile, create, update, batchDelete .sleep.readonly
.sleep.writeonly
Schritte
dataType: steps
filter parameter: steps
Eintragstyp: Intervall
Speicherauflösung: 1 Minute

Kompatible Geräte

list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Zeit in Herzfrequenzzone
dataType: time-in-heart-rate-zone
filter parameter: time_in_heart_rate_zone
Eintragstyp: Intervall
Speicherauflösung: 1 Minute
list, reconcile, rollup, dailyRollup .activity_and_fitness.readonly
.activity_and_fitness.writeonly
Gewicht
dataType: weight
filter parameter: weight
Eintragstyp: Beispiel

Kompatible Geräte

list, get, reconcile, rollup, dailyRollup, create, update, batchDelete .health_metrics_and_measurements.readonly
.health_metrics_and_measurements.writeonly

Benachrichtigungsbereiche

Benachrichtigungen werden für diese Datentypen nur gesendet, wenn ein Nutzer seine Einwilligung für einen der entsprechenden Bereiche erteilt hat:

  • Aktivität: umfasst die Datentypen „Aktive Minuten“, „Schritte“, „Höhe“, „Strecke“ und „Etagen“:
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
  • Gesundheitsmesswerte, die den Datentyp „Gewicht“ umfassen:
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
  • Schlaf, der den Datentyp „Schlaf“ umfasst:
    • https://www.googleapis.com/auth/googlehealth.sleep.readonly
    • https://www.googleapis.com/auth/googlehealth.sleep.writeonly

IAM-Dienstkonten

Wir empfehlen, ein IAM-Dienstkonto zu verwenden, wenn Sie Abonnenten für die Google Health API konfigurieren. Dies ist jedoch nicht erforderlich. Dienstkonten bieten im Vergleich zu Standardnutzerkonten eine bessere Sicherheit für Anwendungsworkloads. Das liegt an den folgenden Funktionen:

  • Automatisierte kurzlebige Anmeldedaten: Wenn Dienstkonten an eine Google Cloud-Ausführungsumgebung (z. B. Compute Engine, Cloud Run oder Google Kubernetes Engine) angehängt sind, rufen sie automatisch sichere, kurzlebige Anmeldedaten ab und rotieren diese. Dadurch werden die Risiken der Verwaltung und Speicherung persistenter statischer Schlüssel beseitigt.
  • Prinzip der geringsten Berechtigung: Dienstkonten bieten dedizierte Identitäten für Arbeitslasten. Sie können ihnen nur die spezifischen Berechtigungen gewähren, die zum Verwalten von Abonnentenendpunkten erforderlich sind, und so einen umfassenderen Zugriff auf Ihre Google Cloud-Ressourcen vermeiden.
  • Unabhängigkeit des Lebenszyklus: Dienstkonten funktionieren unabhängig vom Konto eines einzelnen Nutzers. So wird sichergestellt, dass sich personelle Veränderungen nicht auf die langfristige Authentifizierungsstabilität auswirken.

Dienstkonto einrichten

So konfigurieren Sie Ihre Abonnentenanwendung für die Authentifizierung mit einem Dienstkonto:

  1. Dienstkonto erstellen: Rufen Sie in der Google Cloud Console die Seite „IAM & Verwaltung“ Ihres Projekts auf, um ein neues nutzerverwaltetes Dienstkonto zu erstellen.
  2. Erforderliche IAM-Rollen zuweisen: Weisen Sie dem Dienstkonto die entsprechenden Rollen zu, die zum Verwalten von Abonnenten in Ihrem Google Cloud-Projekt erforderlich sind.
  3. Dienstkonto an Ihre Arbeitslast anhängen: Konfigurieren Sie die Umgebung, in der Ihre Abonnentenlogik gehostet wird, so, dass sie als das neue Dienstkonto ausgeführt wird. Dadurch kann Ihr Anwendungscode (z. B. Google API-Clientbibliotheken) die kurzlebigen Anmeldedaten des Dienstkontos beim Aufrufen der projects.subscribers REST API automatisch erkennen und verwenden.

CPE-Rollen

Wenn Sie Google Health API-Abonnenten oder -Abos verwalten möchten, müssen Sie dem Dienstkonto, dessen Identität übernommen wird und das die API-Aufrufe ausführt, die entsprechende Rolle zuweisen. Weisen Sie je nach erforderlicher Zugriffsebene eine der folgenden Rollen zu:

  • Google Health API Read
  • Google Health API Editor
  • Google Health API Admin

Weitere Informationen zu IAM-Rollen und ‑Berechtigungen für die Google Health API

Abonnenten verwalten

Bevor Sie Benachrichtigungen erhalten können, müssen Sie einen Abonnenten registrieren, der den Benachrichtigungsendpunkt Ihrer Anwendung darstellt. Sie können Abonnenten mit der REST API unter projects.subscribers verwalten.

Der Abonnentenendpunkt muss HTTPS (TLSv1.2+) verwenden und öffentlich zugänglich sein. Beim Erstellen und Aktualisieren von Abonnenten führt die Google Health API eine Bestätigungsprüfung durch, um sicherzustellen, dass Sie der Inhaber des Endpunkt-URI sind. Wenn die Überprüfung fehlschlägt, schlagen die Vorgänge zum Erstellen und Aktualisieren von Abonnenten mit einem FailedPreconditionException fehl.

Abonnenten erstellen

Verwenden Sie den Endpunkt create, um einen neuen Abonnenten für Ihr Projekt zu registrieren. Sie müssen Folgendes angeben:

  • project-id: Die Projektnummer, unter der das Webhook-Dienstkonto erstellt wurde.
  • subscriberId: Eine eindeutige Kennung, die Sie für den Abonnenten angeben. Diese ID muss zwischen 4 und 36 Zeichen lang sein und dem regulären Ausdruck ([a-z]([a-z0-9-]{2,34}[a-z0-9])) entsprechen.
  • endpointUri: Die Ziel-URL für Webhook-Benachrichtigungen.
  • subscriberConfigs: Die Datentypen, für die Sie Benachrichtigungen erhalten möchten, und die jeweilige Aborichtlinie.
  • endpointAuthorization: Der Autorisierungsmechanismus für Ihren Endpunkt. Diese muss einen von Ihnen bereitgestellten secret enthalten. Der Wert von secret wird mit jeder Benachrichtigung im Header Authorization gesendet. Mit diesem Token können Sie prüfen, ob eingehende Anfragen von der Google Health API stammen. Sie können beispielsweise secret für die Bearer-Authentifizierung auf Bearer R4nd0m5tr1ng123 oder für die Basisauthentifizierung auf Basic dXNlcjpwYXNzd29yZA== festlegen.

In subscriberConfigs müssen Sie für jeden Datentyp subscriptionCreatePolicy festlegen. Legen Sie AUTOMATIC fest, um automatische Abos zu verwenden, oder MANUAL, wenn Sie Nutzerabos selbst verwalten möchten. Weitere Informationen zu den einzelnen Optionen finden Sie unter Automatische Abos und Manuelle Abos.

Anfrage

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"
  }
}

Antwort

{
  "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"
    }
  ]
}

Abonnenten auflisten

Verwenden Sie den Endpunkt list, um alle für Ihr Projekt registrierten Abonnenten abzurufen.

Anfrage

GET https://health.googleapis.com/v4/projects/project-id/subscribers

Antwort

{
  "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
}

Abonnenten aktualisieren

Verwenden Sie den Endpunkt patch, um einen Abonnenten in Ihrem Projekt zu aktualisieren. Die Felder, die aktualisiert werden können, sind endpointUri, subscriberConfigs und endpointAuthorization.

Sie aktualisieren Felder, indem Sie einen updateMask-Abfrageparameter und einen Anfragetext angeben. Die updateMask muss eine durch Kommas getrennte Liste von Feldnamen enthalten, die Sie aktualisieren möchten. Verwenden Sie für Feldnamen die Camel-Case-Schreibweise (z. B. endpointUri). Der Anfragetext muss ein partielles Subscriber-Objekt mit den neuen Werten für die Felder enthalten, die Sie aktualisieren möchten. Nur in updateMask angegebene Felder werden aktualisiert. Wenn Sie im Anfragetext Felder angeben, die nicht in updateMask enthalten sind, werden sie ignoriert.

Wenn Sie endpointUri oder endpointAuthorization aktualisieren, wird die Endpunktprüfung durchgeführt. Weitere Informationen finden Sie unter Endpunktprüfung.

Beachten Sie beim Aktualisieren von subscriberConfigs, dass es sich um einen vollständigen Ersatz und nicht um eine Zusammenführung handelt. Wenn subscriberConfigs in updateMask enthalten ist, werden alle gespeicherten Konfigurationen für diesen Abonnenten mit der im Anfragetext angegebenen Liste überschrieben. Wenn Sie eine Konfiguration hinzufügen oder entfernen möchten, müssen Sie alle Konfigurationen angeben. Wenn Sie andere Felder aktualisieren und Ihre aktuellen Konfigurationen beibehalten möchten, lassen Sie subscriberConfigs in updateMask weg.

Anfrage

PATCH https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id?updateMask=endpointUri
{
  "endpointUri": "https://myapp.com/new-webhooks/health"
}

Antwort

{
  "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"
    }
  ]
}

Abonnenten löschen

Verwenden Sie den Endpunkt delete, um einen Abonnenten aus Ihrem Projekt zu entfernen. Nach dem Löschen erhält der Abonnent keine Benachrichtigungen mehr.

Anfrage

DELETE https://health.googleapis.com/v4/projects/project-id/subscribers/subscriber-id

Antwort

Wenn der Löschvorgang erfolgreich ist, wird ein leerer Antworttext mit dem HTTP-Status „200 OK“ zurückgegeben.
{}

Endpunktprüfung

Um die Sicherheit und Zuverlässigkeit der Benachrichtigungszustellung zu gewährleisten, führt die Google Health API bei der Erstellung eines Abonnenten oder der Aktualisierung seiner Endpunktkonfiguration (endpointUri oder endpointAuthorization) einen obligatorischen Handshake zur Bestätigung in zwei Schritten durch. Dieser Vorgang wird synchron während des API-Aufrufs ausgeführt. Der Dienst sendet zwei automatisierte POST-Anfragen an Ihren Endpunkt-URI. Dabei wird der User-Agent Google-Health-API-Webhooks mit dem JSON-Text {"type": "verification"} verwendet.

  • Autorisierter Handshake: Die erste Anfrage wird mit dem von Ihnen konfigurierten Authorization-Header gesendet. Ihr Server muss mit dem Status 200 OK oder 201 Created antworten.
  • Nicht autorisierte Anfrage: Die zweite Anfrage wird ohne Anmeldedaten gesendet. Ihr Server muss mit dem Status 401 Unauthorized oder 403 Forbidden antworten.

Dieser Handshake bestätigt, dass Ihr Endpunkt aktiv ist und die Sicherheit korrekt erzwingt. Wenn einer der Schritte fehlschlägt, schlägt die API-Anfrage mit dem Fehler FAILED_PRECONDITION fehl. Erst nach erfolgreichem Handshake wird Ihr Abonnent gespeichert und aktiviert, um Benachrichtigungen zu Gesundheitsdaten zu erhalten.

Schlüsselrotation

Wenn Sie Schlüssel für endpointAuthorization rotieren müssen, gehen Sie so vor:

  1. Konfigurieren Sie Ihren Endpunkt so, dass er sowohl alte als auch neue endpointAuthorization-Werte akzeptiert.
  2. Aktualisieren Sie die Abonnentenkonfiguration mit dem neuen endpointAuthorization-Wert. Verwenden Sie dazu eine patch-Anfrage mit ?updateMask=endpointAuthorization.
  3. Konfigurieren Sie Ihren Endpunkt so, dass er nur den neuen endpointAuthorization-Wert akzeptiert, nachdem Sie bestätigt haben, dass Schritt 2 erfolgreich war.

Nutzerabos

Mit der Google Health API können Sie Nutzerabos effizient verwalten und die Notwendigkeit einer manuellen Registrierung während des Onboardings von Nutzern reduzieren.

Automatische Abos

Wir empfehlen, automatische Abos zu verwenden. Wenn Sie diese Funktion aktivieren möchten, setzen Sie subscriptionCreatePolicy in Ihrer subscriberConfigs für die jeweiligen Datentypen auf AUTOMATIC. Die dataTypes, die Sie mit einer AUTOMATIC-Richtlinie angeben, sind dieselben Datentypen, für die die Google Health API Benachrichtigungen sendet, sofern die Nutzereinwilligung auch für diese Datentypen erteilt wurde.

Wenn ein Nutzer die Nutzereinwilligung für Bereiche erteilt, die Datentypen mit einer AUTOMATIC-Richtlinie entsprechen, verfolgt die Google Health API automatisch die Datentypen, die sich aus der Schnittmenge der mit Einwilligung des Nutzers erhobenen Datentypen und der Datentypen der automatischen Abonnentenkonfiguration für diesen Nutzer ergeben, und sendet Benachrichtigungen dafür. Benachrichtigungen werden dann an deinen Endpunkt gesendet, wenn dieser Nutzer neue Daten für diese Typen generiert. Das funktioniert für Nutzer, die ihre Einwilligung entweder vor oder nach dem Erstellen des Abonnenten erteilen. Benachrichtigungen werden nicht für Daten nachgeholt, die vor dem Erstellen des Abonnenten generiert wurden.

Wenn ein Nutzer die Einwilligung widerruft, werden keine Benachrichtigungen mehr für die entsprechenden Datentypen gesendet. Automatische Abos werden von Google verwaltet und können nicht einzeln aufgelistet oder gelöscht werden. Sie werden nur entfernt, wenn der übergeordnete Abonnent gelöscht wird.

Manuelle Abos

Wenn Ihr Abonnent für bestimmte Datentypen mit einem MANUAL-subscription_create_policy konfiguriert ist, müssen Sie Abos für jeden Nutzer explizit erstellen und verwalten. Ein Abo verknüpft einen bestimmten Nutzer mit Ihrem Abonnenten-Endpunkt für eine definierte Gruppe von Datentypen. Entwickler können bestimmte APIs für Folgendes verwenden:

  • Abos pro healthUserId (manuell) erstellen: Erstellt ein neues Abo für einen bestimmten Nutzer. Bei dieser Methode muss der Abonnent für die angeforderten Datentypen ein SubscriptionCreatePolicy auf MANUAL festgelegt haben.
  • Abo aktualisieren (manuell): Aktualisiert die Datentypen für ein vorhandenes Nutzerabo.
  • Abo (manuell) löschen: Löscht ein bestimmtes Nutzerabo. Nach dem Löschen erhält der Abonnentenendpunkt für diesen Nutzer keine Benachrichtigungen mehr für die zugehörigen Datentypen.
  • Abos (manuell) auflisten: Listet alle aktiven Abos für einen bestimmten Abonnenten auf. Sie können die Ergebnisse nach Nutzer oder Datentyp filtern.

Benachrichtigungen

Wenn sich die Daten eines Nutzers für einen abonnierten Datentyp ändern, sendet die Google Health API eine HTTPS-POST-Anfrage an die URL des Abonnentenendpunkts.

Benachrichtigungsformat

Die Nutzlast der Benachrichtigung enthält Details zur Datenänderung, einschließlich Nutzer-ID, Datentyp und Zeitintervallen, mit denen Sie die aktualisierten Daten abfragen können. Wenn mehrere Aktualisierungen erfolgen oder Aktualisierungen zusammengefasst werden, werden die Benachrichtigungen zusammengefasst und als JSON-Array von Benachrichtigungsobjekten bereitgestellt.

Wenn eine Webhook-Benachrichtigung ausgelöst wird, sendet die Google Health API eine HTTPS-POST-Anfrage im folgenden Format an den Endpunkt des Abonnenten:

Upsert (Zeitreihendaten)

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"
        }
      }
    ]
  }
}

Löschen (Zeitreihendaten)

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"
          }
        }
      ]
    }
  }
]

Löschen (identifizierbare Daten)

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"
  }
}

Batch (mehrere Nutzer und Datentypen)

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"
    }
  }
]

Das Feld operation gibt die Art der Änderung an, die die Benachrichtigung ausgelöst hat:

  • UPSERT: Wird für alle Daten hinzugefügt oder geändert.
  • DELETE: Wird gesendet, wenn ein Nutzer Daten explizit löscht (z. B. dataPoints über die Fitbit App oder durch einen Batch-Löschvorgang über die API). Webhook-Benachrichtigungen werden nicht für Löschereignisse auf Systemebene gesendet, z. B. wenn ein Nutzer Anwendungsberechtigungen widerruft oder sein Fitbit-Konto löscht.

Wir empfehlen, die Logik für die Benachrichtigungsverarbeitung idempotent zu gestalten, insbesondere für UPSERT-Vorgänge, da Wiederholungen dazu führen können, dass doppelte Benachrichtigungen gesendet werden.

Das Feld clientProvidedSubscriptionName ist eine eindeutige Kennung:

  • Bei Abos mit einer MANUAL-Richtlinie enthält dieses Feld den dauerhaften, vom Entwickler bereitgestellten Abonamen, der beim Erstellen des Abos angegeben wurde. Dadurch wird eine stabile ID für die Verwaltung manueller Abos bereitgestellt.
  • Für Abos, die mit einer AUTOMATIC-Richtlinie erstellt wurden, generiert die Google Health API automatisch eine Kennung im folgenden Format und weist sie zu: auto-<project-number>-<subscriber-id>-<WEBHOOK_DATA_TYPE_TOKEN>, wobei:
    • <project-number> ist die Google Cloud-Projektnummer des Entwicklers (z. B. 362978535920).
    • <subscriber-id> ist die Registrierungs-ID / der Name des Abonnenten (z. B. google-health-sync).
    • <WEBHOOK_DATA_TYPE_TOKEN> ist das Token, das den spezifischen Datentyp darstellt. Eine Liste aller möglichen Tokens finden Sie unter Vokabular der Webhook-Datentyptokens.

Wenn Sie clientProvidedSubscriptionName sowohl für manuelle als auch für automatische Richtlinien angeben, wird ein einheitliches Format für die Benachrichtigungsnutzlast für alle Abotypen gewährleistet.

Zuordnung der Nutzer-ID

Die healthUserId ist eine Google Health API-ID für den Nutzer, dessen Daten sich geändert haben. Wenn Ihre Anwendung mehrere Nutzer unterstützt, können Sie Benachrichtigungen für jeden Nutzer erhalten, der Ihrer Anwendung die Einwilligung erteilt hat. Wenn Sie eine Benachrichtigung erhalten, können Sie anhand von healthUserId feststellen, welche Nutzerdaten sich geändert haben. So können Sie die OAuth-Anmeldedaten des Nutzers verwenden, um seine Daten abzufragen.

Wenn Sie die OAuth-Anmeldedaten eines Nutzers seinem healthUserId zuordnen möchten, verwenden Sie den Endpunkt getIdentity. Rufe diesen Endpunkt während des Onboardings mit den Anmeldedaten eines Nutzers auf, um seine healthUserId abzurufen, und speichere diese Zuordnung. Diese Zuordnung ändert sich im Laufe der Zeit nicht und kann daher unbegrenzt im Cache gespeichert werden. Ein Beispiel finden Sie unter Nutzer-ID abrufen. So können Sie die richtigen Nutzeranmeldedaten auswählen, wenn Sie Daten basierend auf der healthUserId in einer Benachrichtigung abfragen.

Zeitintervalle

Das intervals-Array enthält ein oder mehrere Objekte, die die Zeitintervalle für die geänderten Daten darstellen:

Feld Typ Erforderlich Beschreibung
physicalTimeInterval object Nein Das physische UTC-Zeitintervall der geänderten Daten (Format YYYY-MM-DDTHH:MM:SSZ). Wird für Messwerte im Tagesverlauf ausgefüllt; wird für tägliche Zusammenfassungen und ganztägige Aktivitäten weggelassen.
civilDateTimeInterval object Ja Das Datum und das Zeitintervall der geänderten Daten im bürgerlichen (lokalen) Kalender, ohne UTC- oder Zeitzonenabweichungen.
civilIso8601TimeInterval object Ja Das bürgerliche (lokale) Zeitintervall, dargestellt als ISO 8601-String (Format YYYY-MM-DDTHH:MM:SS) ohne UTC- oder Zeitzonenversatz.

Bei ganztägigen Aktivitäten und täglichen Aggregaten wird das Feld physicalTimeInterval absichtlich aus der Benachrichtigungsnutzlast weggelassen. Das liegt daran, dass ganztägige Ereignisse nach ihrem nominalen bürgerlichen Datum gruppiert werden und die physische Zeitdauer beim Überschreiten von Zeitzonen ungenau sein kann. Bei der Verarbeitung ganztägiger Termine sollten Sie sich am besten auf die Felder civilDateTimeInterval oder civilIso8601TimeInterval verlassen. Weitere Informationen zum Abfragen dieser Datenpunkte mit Filtern für die bürgerliche Zeit finden Sie unter Daten nach einem bürgerlichen Startzeitintervall filtern.

Im Folgenden finden Sie ein Beispiel für eine Benachrichtigungsnutzlast für eine ganztägige Aktivität, bei der das Feld physicalTimeInterval weggelassen wird:

{
  "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"
        }
      }
    ]
  }
}

Vokabular der Webhook-Datentyptokens

Wenn Sie eine AUTOMATIC-Richtlinie verwenden, enthält die generierte clientProvidedSubscriptionName je nach Datentyp eines der folgenden großgeschriebenen WEBHOOK_DATA_TYPE_*-Suffix-Tokens:

Webhook-Datentyp-Token Zugehöriger Datentyp
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 (Systemereignis)
WEBHOOK_DATA_TYPE_USER_REVOKED_ACCESS user-revoked-access (Systemereignis)

Aggregation von Aktualisierungen

Um den Netzwerkverkehr zu minimieren, werden Nachrichten in der Google Health API zusammengefasst. Das System ist so konfiguriert, dass maximal 99 Nachrichten pro Batch gesendet werden. Diese werden automatisch per Push gesendet, sobald sie verfügbar sind.

Wenn Nachrichten im Batch gesendet werden, wird die Nutzlast als JSON-Array mit mehreren Benachrichtigungsobjekten bereitgestellt. Ein einzelner Batch kann Aktualisierungen für mehrere Nutzer für mehrere abonnierte Datentypen enthalten. Eine Beispielnutzlast finden Sie im Abschnitt „Benachrichtigungsformat“ unter Batch (mehrere Nutzer und Datentypen).

Reagieren auf eine Benachrichtigung

Ihr Server muss den Authorization-Header validieren, den synchronen Handshake zur Endpunktbestätigung verarbeiten und sofort mit einem HTTP-Statuscode 204 No Content auf Benachrichtigungen zu Datenänderungen reagieren. Verarbeiten Sie die Benachrichtigungsnutzlast asynchron, nachdem Sie die Antwort gesendet haben, um Zeitüberschreitungen zu vermeiden. Wenn die Google Health API einen anderen Statuscode empfängt oder die Anfrage das Zeitlimit überschreitet, wird die Benachrichtigung später noch einmal gesendet.

Beispiel für 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).
        }
    });
});

Wenn du die aktualisierten Daten für jedes benachrichtigte Intervall abrufen möchtest, rufe den Endpunkt reconcile mit einem Filter für den Zeitraum des Intervalls auf. Dadurch werden sich überschneidende Intervalle von verbundenen Geräten automatisch dedupliziert. Weitere Informationen und Beispiele finden Sie unter Abgeglichene Ansicht von Intervalldaten abrufen.

Es gibt drei gängige Strategien, um Ihre Datenbank nach Erhalt einer Benachrichtigung über eine Datenänderung zu aktualisieren:

  • Warteschlange (empfohlen): Platzieren Sie die eingehenden Benachrichtigungen in einer Nachrichtenwarteschlange und verarbeiten Sie sie basierend auf den Systemressourcen.
  • Sofortiger Abruf: Weisen Sie Ihr Backend an, die Google Health API sofort aufzurufen, um die aktualisierten Daten abzurufen und in Ihre Datenbank zu übertragen.
  • Verzögerte Aktualisierungen: Markieren Sie die lokalen Datenbankeinträge des Nutzers als veraltet und rufen Sie die aktualisierten Daten erst dann von der Google Health API ab, wenn der Nutzer Ihre Anwendung das nächste Mal besucht.

Mit der Warteschlangenstrategie können Sie Daten nahezu in Echtzeit verarbeiten und gleichzeitig eine Flut von Benachrichtigungen bewältigen (z. B. wenn ein Dienstausfall dazu führt, dass ein Rückstand an Benachrichtigungen auf einmal zugestellt wird). Sie können diese Warteschlangen zwar in einem Batch-Zeitplan mit langen Intervallen (z. B. alle 3 Stunden) verarbeiten, um Ressourcen zu sparen, aber der Nachteil ist, dass Nutzer in der Regel erwarten, dass ihre Daten nahezu in Echtzeit aktualisiert werden.

Best Practices

Befolgen Sie diese Best Practices, um eine zuverlässige und effiziente Verarbeitung von Datenaktualisierungen zu gewährleisten:

  • Subscription API verwenden: Verwende die Subscription API, um benachrichtigt zu werden, wenn ein Nutzer neue Daten zum Herunterladen hat, anstatt Endpunkte abzufragen.
  • Benachrichtigungen separat in die Warteschlange stellen und verarbeiten: Wenn du Abobenachrichtigungen erhältst, stelle sie in eine Warteschlange und verarbeite sie separat, je nach den Ressourcen deines Systems. Halten Sie den Webhook-Endpunkt schlank, indem Sie die Anfrage sofort bestätigen.

Signaturüberprüfung

Um die Authentizität von Webhook-Benachrichtigungen zu gewährleisten, wird die JSON-Nutzlast jeder ausgehenden Webhook-Benachrichtigung mit einem privaten Schlüssel signiert. Dazu wird PublicKeySign von Tink verwendet. Die Base64-codierte Signatur wird im HTTP-Header GOOGLE-HEALTH-API-SIGNATURE in der Anfrage bereitgestellt. Diese Signaturschlüssel werden alle 30 Tage automatisch rotiert. Der entsprechende offizielle öffentliche Schlüsselsatz wird als JSON-Datei unter der permanenten URL https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json verteilt.

Signatur überprüfen

Mit Tink (empfohlen): Entwickler können die Signatur mit dem Primitiv PublicKeyVerify von Tink verifizieren. Rufen Sie den öffentlichen Schlüsselsatz über die permanente URL ab, instanziieren Sie die PublicKeyVerify-Primitive mit dem Schlüsselsatz und prüfen Sie den decodierten GOOGLE-HEALTH-API-SIGNATURE-Header anhand der JSON-Rohdaten des Webhooks.

Manuelle Überprüfung (ohne Tink): Wenn Entwickler Tink nicht verwenden möchten, können sie die Signatur manuell überprüfen. Gehen Sie dazu so vor:

  1. Der Header GOOGLE-HEALTH-API-SIGNATURE wird Base64-decodiert, um das 5-Byte-Tink-Präfix (das ein 1-Byte-Versionspräfix und eine 4-Byte-keyId enthält) von der eigentlichen DER-codierten Signatur zu trennen.
  2. Rufen Sie den JSON-Schlüsselsatz von https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json ab.
  3. Suchen Sie den Schlüssel, der mit der geparsten keyId übereinstimmt, und decodieren Sie das Wertfeld mit Base64. Es enthält einen serialisierten EcdsaPublicKey-Protokollzwischenspeicher.
  4. Extrahieren Sie die Big-Endian-x- und -y-Koordinaten (Protobuf-Tags 3 und 4) aus dieser binären Nutzlast.
  5. Instanziieren Sie einen standardmäßigen öffentlichen ECDSA-P-256-Schlüssel in einer integrierten Kryptografiebibliothek mit den extrahierten x- und y-Koordinaten.
  6. Prüfen Sie die JSON-Rohdaten-Nutzlast des Webhooks anhand der extrahierten DER-Signatur mit dem SHA-256-Algorithmus.

Abonnentenstatus und Wiederherstellung

Wenn der Abonnentenendpunkt nicht verfügbar ist oder einen Fehlerstatuscode (alles außer 204) zurückgibt, speichert die Google Health API ausstehende Benachrichtigungen bis zu 7 Tage lang und versucht die Zustellung mit exponentiellem Backoff noch einmal.

Sobald der Endpunkt wieder online ist und mit 204 antwortet, liefert die API automatisch die gespeicherten Nachrichten aus. Benachrichtigungen, die älter als 7 Tage sind, werden verworfen und können nicht wiederhergestellt werden.

Häufige Fehler

Fehlercode Nachricht Beschreibung Empfehlung
400 Fehlerhafte Anfrage Ungültige Projektnummer im Ressourcennamen Wenn Sie einen Abonnenten löschen oder aktualisieren und dabei die Google Cloud-Projekt-ID anstelle der Projektnummer in der Anfrage-URL verwenden. Dies gilt für Webhook-Abos, die den Endpunkt projects.subscribers verwenden. Verwenden Sie in der Anfrage-URL Ihre Google Cloud-Projektnummer, nicht die Projekt-ID.
403 Verboten Das Dienstkonto hat keine Berechtigung. Wenn Sie Abonnenten erstellen oder auflisten und dabei die Google Cloud-Projekt-ID anstelle der Projektnummer in der Anfrage-URL verwenden. Dies gilt für Webhook-Abos, die den Endpunkt projects.subscribers verwenden. Verwenden Sie in der Anfrage-URL Ihre Google Cloud-Projektnummer, nicht die Projekt-ID.