Abbonamenti webhook

L'API Google Health consente alla tua applicazione di ricevere notifiche in tempo reale quando i dati sulla salute di un utente cambiano. Anziché eseguire il polling per verificare la presenza di modifiche, il server riceve una richiesta HTTPS POST (webhook){:target="_blank" class="external"} non appena i dati sono disponibili nell'API Google Health.

Tipi di dati supportati

Le notifiche webhook sono supportate per i seguenti tipi di dati:

  • Minuti in zona attiva
  • Livello di attività
  • Altitudine
  • Glicemia
  • Grasso corporeo
  • Calorie nella zona cardio
  • Variabilità del battito cardiaco giornaliera
  • Zone cardio giornaliere
  • Saturazione di ossigeno giornaliera
  • Frequenza respiratoria giornaliera
  • Battito cardiaco a riposo giornaliero
  • Derivazioni della temperatura durante il sonno giornaliere
  • Distanza
  • Esercizio
  • Piani
  • Frequenza cardiaca
  • Variabilità del battito cardiaco
  • Altezza
  • Diario dell'idratazione
  • Diario alimentare
  • Riepilogo della frequenza respiratoria durante il sonno
  • VO2 max corsa
  • Periodo di sedentarietà
  • Sonno
  • Passaggi
  • Tempo nella zona cardio
  • Calorie totali
  • Peso

Le notifiche vengono inviate per questi tipi di dati solo quando un utente ha concesso il consenso per uno degli ambiti corrispondenti:

  • Attività, che copre i tipi di dati relativi a passi, altitudine, distanza e piani:
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly
    • https://www.googleapis.com/auth/googlehealth.activity_and_fitness.writeonly
  • Metriche di salute, che copre il tipo di dati relativi al peso:
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly
    • https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.writeonly
  • Sonno, che copre il tipo di dati relativi al sonno:
    • https://www.googleapis.com/auth/googlehealth.sleep.readonly
    • https://www.googleapis.com/auth/googlehealth.sleep.writeonly

Service account IAM

Sebbene non sia obbligatorio, ti consigliamo di utilizzare un service account IAM quando configuri gli abbonati per l'API Google Health. I service account offrono una maggiore sicurezza per i carichi di lavoro delle applicazioni rispetto agli account utente standard tramite le seguenti funzionalità:

  • Credenziali di breve durata automatizzate: quando sono collegati a un ambiente di esecuzione di Google Cloud (ad esempio Compute Engine, Cloud Run o Google Kubernetes Engine), i service account ottengono e ruotano automaticamente le credenziali sicure di breve durata. In questo modo si eliminano i rischi di gestione e archiviazione delle chiavi statiche persistenti.
  • Principio del privilegio minimo: i service account forniscono identità dedicate per i carichi di lavoro. Puoi concedere loro solo le autorizzazioni specifiche necessarie per gestire gli endpoint degli abbonati, evitando un accesso più ampio alle risorse Google Cloud.
  • Indipendenza del ciclo di vita: i service account operano indipendentemente dall'account di un singolo utente, garantendo che le modifiche del personale non influiscano sulla stabilità dell'autenticazione a lungo termine.

Configura un service account

Per configurare l'applicazione abbonata in modo che esegua l'autenticazione utilizzando un service account:

  1. Crea un service account: nella console Google Cloud, vai alla pagina IAM e amministrazione del tuo progetto per creare un nuovo service account gestito dall'utente.
  2. Concedi i ruoli IAM necessari: assegna al service account i ruoli appropriati necessari per gestire gli abbonati nel tuo progetto Google Cloud.
  3. Collega il service account al tuo carico di lavoro: configura l'ambiente che ospita la logica dell'abbonato in modo che venga eseguito come il nuovo service account. In questo modo, il codice dell'applicazione (ad esempio le librerie client delle API di Google) può rilevare e utilizzare automaticamente le credenziali di breve durata del service account quando chiama l'API REST projects.subscribers.

Ruoli CPE

Per gestire gli abbonati o gli abbonamenti all'API Google Health, devi concedere il ruolo appropriato al service account impersonato che effettua le chiamate API. A seconda del livello di accesso necessario, assegna uno dei seguenti ruoli:

  • Lettore API Google Health
  • Editor API Google Health
  • Amministratore API Google Health

Scopri di più sui ruoli e sulle autorizzazioni IAM dell'API Google Health.

Gestire gli abbonati

Prima di poter ricevere le notifiche, devi registrare un abbonato, che rappresenta l'endpoint di notifica della tua applicazione. Puoi gestire gli abbonati utilizzando l'API REST disponibile all'indirizzo projects.subscribers.

L'endpoint dell'abbonato deve utilizzare HTTPS (TLSv1.2+) ed essere accessibile pubblicamente. Durante la creazione e gli aggiornamenti degli abbonati, l'API Google Health esegue una verifica per assicurarsi che tu sia il proprietario dell'URI dell'endpoint. Se la verifica non va a buon fine, le operazioni di creazione e aggiornamento degli abbonati non vanno a buon fine e viene generata un'eccezione FailedPreconditionException.

Creare un abbonato

Per registrare un nuovo abbonato per il tuo progetto, utilizza l' create endpoint. Devi fornire:

  • project-id: il numero di progetto in cui è stato creato il service account webhook.
  • subscriberId: un identificatore univoco che fornisci per l'abbonato. Questo ID deve essere compreso tra 4 e 36 caratteri e corrispondere all'espressione regolare ([a-z]([a-z0-9-]{2,34}[a-z0-9])).
  • endpointUri: l'URL di destinazione per le notifiche webhook.
  • subscriberConfigs: i tipi di dati per cui vuoi ricevere le notifiche e la policy di abbonamento per ciascuno.
  • endpointAuthorization: il meccanismo di autorizzazione per l'endpoint. Deve contenere un secret che fornisci. Il valore di secret viene inviato nell'intestazione Authorization con ogni messaggio di notifica. Puoi utilizzare questo token per verificare che le richieste in entrata provengano dall'API Google Health. Ad esempio, puoi impostare secret su Bearer R4nd0m5tr1ng123 per l'autenticazione con token di autenticazione o Basic dXNlcjpwYXNzd29yZA== per l'autenticazione di base.

In subscriberConfigs devi impostare subscriptionCreatePolicy per ogni tipo di dati. Imposta AUTOMATIC per utilizzare gli abbonamenti automatici o MANUAL se intendi gestire tu stesso gli abbonamenti degli utenti. Per ulteriori dettagli su ogni opzione, consulta Abbonamenti automatici e Abbonamenti manuali.

Richiesta

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

Risposta

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

Elencare gli abbonati

Utilizza l'endpoint list per recuperare tutti gli abbonati registrati per il tuo progetto.

Richiesta

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

Risposta

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

Aggiornare un abbonato

Utilizza l'endpoint patch per aggiornare un abbonato nel tuo progetto. I campi che possono essere aggiornati sono endpointUri, subscriberConfigs e endpointAuthorization.

Per aggiornare i campi, fornisci un parametro di query updateMask e un corpo della richiesta. updateMask deve contenere un elenco di nomi di campi separato da virgole che vuoi aggiornare, utilizzando la notazione camel case per i nomi dei campi (ad esempio, endpointUri). Il corpo della richiesta deve contenere un oggetto Subscriber parziale con i nuovi valori per i campi che vuoi aggiornare. Vengono aggiornati solo i campi specificati in updateMask. Se fornisci campi nel corpo della richiesta che non sono presenti in updateMask, questi vengono ignorati.

Se aggiorni endpointUri o endpointAuthorization, viene eseguita la verifica dell'endpoint. Per maggiori dettagli, consulta Verifica dell'endpoint.

Quando aggiorni subscriberConfigs, tieni presente che si tratta di una sostituzione completa, non di un' unione. Se subscriberConfigs è incluso in updateMask, tutte le configurazioni memorizzate per l'abbonato vengono sovrascritte con l'elenco fornito nel corpo della richiesta. Per aggiungere o rimuovere una configurazione, devi fornire l'insieme completo di configurazioni. Se stai aggiornando altri campi e vuoi mantenere le configurazioni attuali, ometti subscriberConfigs da updateMask.

Richiesta

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

Risposta

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

Eliminare un abbonato

Utilizza l'delete endpoint per rimuovere un abbonato dal tuo progetto. Una volta eliminato, l'abbonato non riceverà più le notifiche.

Richiesta

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

Risposta

Se l'eliminazione va a buon fine, viene restituito un corpo della risposta vuoto con lo stato HTTP `200 OK`.
{}

Verifica dell'endpoint

Per garantire la sicurezza e l'affidabilità della distribuzione delle notifiche, l'API Google Health esegue un handshake di verifica obbligatorio in due passaggi ogni volta che crei un abbonato o aggiorni la configurazione dell'endpoint (endpointUri o endpointAuthorization). Questa procedura viene eseguita in modo sincrono durante la chiamata API. Il servizio invia due richieste POST automatiche all'URI dell'endpoint, utilizzando lo user agent Google-Health-API-Webhooks-Verifier, con il corpo JSON {"type": "verification"}.

  • Handshake autorizzato: la prima richiesta viene inviata con l'intestazione configurata Authorization. Il server deve rispondere con lo stato 200 OK o 201 Created.
  • Verifica non autorizzata: la seconda richiesta viene inviata senza credenziali. Il server deve rispondere con lo stato 401 Unauthorized o 403 Forbidden.

Questo handshake conferma che l'endpoint è attivo e applica correttamente la sicurezza. Se uno dei passaggi non va a buon fine, la richiesta API non va a buon fine e viene generato un errore FAILED_PRECONDITION. Solo dopo che l'handshake va a buon fine, il sottoscrittore viene salvato e attivato per ricevere le notifiche dei dati sulla salute.

Rotazione della chiave

Se devi ruotare le chiavi per endpointAuthorization, segui questi passaggi:

  1. Configura l'endpoint in modo che accetti sia i valori endpointAuthorization vecchi che quelli nuovi.
  2. Aggiorna la configurazione dell'abbonato con il nuovo valore endpointAuthorization utilizzando una richiesta patch con ?updateMask=endpointAuthorization.
  3. Configura l'endpoint in modo che accetti solo il nuovo valore endpointAuthorization dopo aver confermato che il passaggio 2 è andato a buon fine.

Abbonamenti utente

L'API Google Health ti aiuta a gestire in modo efficiente gli abbonamenti degli utenti, riducendo la necessità di una registrazione manuale durante l'onboarding degli utenti.

Abbonamenti automatici

Ti consigliamo di utilizzare gli abbonamenti automatici. Per attivare questa funzionalità, imposta subscriptionCreatePolicy su AUTOMATIC in subscriberConfigs per i tipi di dati specifici. I dataTypes che specifichi con una policy AUTOMATIC sono gli stessi tipi di dati per cui l'API Google Health invia le notifiche, a condizione che l'utente abbia concesso il consenso anche per questi tipi di dati.

Quando un utente concede il consenso dell'applicazione per gli ambiti che corrispondono ai tipi di dati con una policy AUTOMATIC, l'API Google Health monitora e invia automaticamente le notifiche per i tipi di dati risultanti dall'intersezione tra i tipi di dati per i quali è stato dato il consenso dall'utente e i tipi di dati di configurazione dell'abbonato automatico per quell'utente. Le notifiche vengono quindi inviate all'endpoint ogni volta che l'utente genera nuovi dati per questi tipi. Questa funzionalità è disponibile per gli utenti che concedono il consenso prima o dopo la creazione dell'abbonato. Non viene eseguito il backfill delle notifiche per i dati generati prima della creazione dell'abbonato.

Se un utente revoca il consenso, le notifiche per i tipi di dati corrispondenti verranno interrotte. Gli abbonamenti automatici sono gestiti da Google e non possono essere elencati o eliminati singolarmente; vengono rimossi solo quando viene eliminato l'abbonato principale.

Abbonamenti manuali

Se l'abbonato è configurato con una subscription_create_policy MANUAL per tipi di dati specifici, devi creare e gestire esplicitamente gli abbonamenti per ogni utente. Un abbonamento collega un utente specifico all'endpoint dell'abbonato per un insieme definito di tipi di dati. Gli sviluppatori possono utilizzare API specifiche per:

  • Creare abbonamenti (manuali) per healthUserId : crea un nuovo abbonamento per un utente specifico. Questo metodo richiede che l'abbonato abbia una SubscriptionCreatePolicy impostata su MANUAL per i tipi di dati richiesti.
  • Aggiornare l'abbonamento (manuale): aggiorna i tipi di dati per un abbonamento utente esistente.
  • Eliminare l'abbonamento (manuale): elimina un abbonamento utente specifico. Una volta eliminato, l'endpoint dell'abbonato non riceverà più notifiche per questo utente per i tipi di dati associati.
  • Elencare gli abbonamenti (manuali): elenca tutti gli abbonamenti attivi per un determinato abbonato. Puoi filtrare i risultati per utente o tipo di dati.

Notifiche

Quando i dati di un utente cambiano per un tipo di dati a cui è abbonato, l'API Google Health invia una richiesta HTTPS POST all'URL dell'endpoint dell'abbonato.

Formato delle notifiche

Il payload della notifica è un oggetto JSON contenente dettagli sulla modifica dei dati. Include l'ID utente, il tipo di dati e gli intervalli di tempo, che puoi utilizzare per eseguire query sui dati aggiornati.

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

Il campo operation indica il tipo di modifica che ha attivato la notifica:

  • UPSERT: inviato per qualsiasi aggiunta o modifica dei dati.
  • DELETE: inviato quando un utente elimina i dati.

Ti consigliamo di rendere idempotente la logica di gestione delle notifiche, soprattutto per le operazioni UPSERT, poiché i tentativi possono causare l'invio di notifiche duplicate.

Il campo clientProvidedSubscriptionName è un identificatore univoco. Per gli abbonamenti con una policy MANUAL, questo campo contiene il nome dell'abbonamento persistente fornito dallo sviluppatore specificato al momento della creazione dell'abbonamento. Questo fornisce un ID stabile per la gestione degli abbonamenti manuali. Per gli abbonamenti creati con una policy AUTOMATIC, l'API Google Health genera e assegna automaticamente un identificatore univoco (un UUID casuale) a questo campo per ogni notifica. L'inclusione di clientProvidedSubscriptionName per le policy manuali e automatiche garantisce un formato del payload di notifica coerente per tutti i tipi di abbonamento.

healthUserId è un identificatore dell'API Google Health per l'utente i cui dati sono stati modificati. Se la tua applicazione supporta più utenti, potresti ricevere notifiche per qualsiasi utente che ha concesso il consenso alla tua applicazione. Quando ricevi una notifica, utilizza healthUserId per identificare i dati dell'utente che sono stati modificati, in modo da poter utilizzare le sue credenziali OAuth per eseguire query sui dati.

Per mappare le credenziali OAuth di un utente al suo healthUserId, utilizza l' getIdentity endpoint. Chiama questo endpoint con le credenziali di un utente durante l'onboarding dell'utente per recuperare il suo healthUserId e memorizzare questa mappatura. Questa mappatura non cambia nel tempo, quindi può essere memorizzata nella cache a tempo indeterminato. Per un esempio, vedi Recuperare l'ID utente. In questo modo puoi selezionare le credenziali utente corrette quando esegui query sui dati in base a healthUserId in una notifica.

Rispondere a una notifica

Il server deve rispondere immediatamente alle notifiche con un codice di stato HTTP 204 No Content. Per evitare timeout, elabora il payload della notifica in modo asincrono dopo aver inviato la risposta. Se l'API Google Health riceve qualsiasi altro codice di stato o se la richiesta va in timeout, ritenta di inviare la notifica in un secondo momento.

Esempio di 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
    });
});

Verifica della firma

Per garantire l'autenticità delle notifiche webhook, il payload JSON non elaborato di ogni notifica webhook in uscita viene firmato con una chiave privata utilizzando PublicKeySign di Tink, fornendo la firma con codifica Base64 nell'intestazione HTTP GOOGLE-HEALTH-API-SIGNATURE nella richiesta. Queste chiavi di firma vengono ruotate automaticamente ogni 30 giorni e il keyset pubblico ufficiale corrispondente viene distribuito come file JSON all'URL permanente https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.

Come verificare la firma

Utilizzo di Tink (consigliato): gli sviluppatori possono verificare la firma utilizzando la primitiva PublicKeyVerify di Tink. Recupera il keyset pubblico dall'URL permanente, crea un'istanza della primitiva PublicKeyVerify con il keyset e verifica l'intestazione GOOGLE-HEALTH-API-SIGNATURE decodificata rispetto al payload JSON webhook non elaborato.

Verifica manuale (senza Tink): se gli sviluppatori scelgono di non utilizzare Tink, possono verificare manualmente la firma seguendo questi passaggi:

  1. Decodifica in Base64 l'intestazione GOOGLE-HEALTH-API-SIGNATURE per separare il prefisso Tink di 5 byte (che contiene un prefisso di versione di 1 byte e un keyId di 4 byte) dalla firma con codifica DER effettiva.
  2. Recupera il keyset JSON da https://www.gstatic.com/googlehealthapi/webhooks/webhooks_public_keyset.json.
  3. Individua la chiave corrispondente al keyId analizzato e decodifica in Base64 il relativo campo valore, che contiene un buffer di protocollo EcdsaPublicKey serializzato.
  4. Estrai le coordinate x e y big-endian (tag Protobuf 3 e 4) da questo payload binario.
  5. Crea un'istanza di una chiave pubblica ECDSA P-256 standard in una libreria di crittografia integrata utilizzando le coordinate x e y estratte.
  6. Verifica il payload JSON webhook non elaborato rispetto alla firma DER estratta utilizzando l'algoritmo SHA-256.

Stato e recupero dell'abbonato

Se l'endpoint dell'abbonato non è disponibile o restituisce un codice di stato di errore (diverso da 204), l'API Google Health memorizza le notifiche in attesa per un massimo di 7 giorni e ritenta la distribuzione con un backoff esponenziale.

Una volta che l'endpoint è di nuovo online e risponde con 204, l'API distribuisce automaticamente il backlog di messaggi memorizzati. Le notifiche più vecchie di 7 giorni vengono eliminate e non possono essere recuperate.

Errori comuni

Codice di errore Messaggio Descrizione Suggerimento
Richiesta non valida (400) Numero di progetto non valido nel nome della risorsa Quando elimini o aggiorni un abbonato utilizzando l'ID progetto Google Cloud nell'URL della richiesta anziché il numero di progetto. Questo vale per gli abbonamenti webhook che utilizzano l'endpoint projects.subscribers. Utilizza il numero di progetto Google Cloud nell'URL della richiesta, non l'ID progetto.
Richiesta vietata (403) Il chiamante non dispone dell'autorizzazione Quando crei o elenchi gli abbonati utilizzando l'ID progetto Google Cloud nell'URL della richiesta anziché il numero di progetto. Questo vale per gli abbonamenti webhook che utilizzano l'endpoint projects.subscribers. Utilizza il numero di progetto Google Cloud nell'URL della richiesta, non l'ID progetto.