@healthcloudai/hc-vitals-import
v0.4.1
Published
Healthcheck Vitals Import connector SDK with TypeScript
Downloads
599
Maintainers
Readme
Healthcheck Import Vitals Connector
SDK connector for importing vital signs, importing linked vendor readings, and retrieving stored vitals from the Healthcheck platform.
HCImportVitalsClient uses a configured HCLoginClient for environment resolution. Authenticated methods read auth headers from the login client, while logVitals does not require authorization. The base URL is derived from the login client so it stays in sync with the configured environment.
Installation
npm install @healthcloudai/hc-vitals-import \
@healthcloudai/hc-login-connector \
@healthcloudai/hc-httpImport
import { HCImportVitalsClient } from "@healthcloudai/hc-vitals-import";
import { HCLoginClient } from "@healthcloudai/hc-login-connector";
import { FetchClient } from "@healthcloudai/hc-http";
import type {
APIResponse,
ImportVitalsRequest,
ImportVitalDBRecord,
LogVitalsRequest,
} from "@healthcloudai/hc-vitals-import";Setup
const httpClient = new FetchClient();
const loginClient = new HCLoginClient(httpClient);
loginClient.configure("healthcheck", "dev");
await loginClient.login("[email protected]", "ExamplePassword123!");
const client = new HCImportVitalsClient(httpClient, loginClient);The constructor reads the base URL directly from loginClient.getBaseUrl() — no separate environment mapping is needed.
API Key
If the environment requires an API key, configure it once:
client.setApiKey("x-api-key", process.env.HEALTHCLOUD_API_KEY ?? "");Response Format
All methods return:
APIResponse<T>export interface APIResponse<T> {
Data: T | null;
IsOK: boolean;
ErrorMessage: string | null;
}Methods
listVitals(limit?)
Returns stored vital sign records for the authenticated patient.
limit— optional, default50, max500
await client.listVitals();
await client.listVitals(5);Returns Promise<APIResponse<ImportVitalDBRecord[]>>.
Example response:
{
"Data": [
{
"ID": "integration-hr-1780995281895",
"TenantID": "healthcheck",
"PatientID": "[email protected]",
"Type": "heartrate",
"Value": 72,
"Unit": "/min",
"TimeStamp": "2026-06-09T08:54:37.984Z",
"SourceName": "Integration Test",
"SourcePlatform": "node"
},
{
"ID": "integration-weight-1780995281895",
"TenantID": "healthcheck",
"PatientID": "[email protected]",
"Type": "weight",
"Value": 70,
"Unit": "kg",
"TimeStamp": "2026-06-09T08:54:37.984Z",
"SourceName": "Integration Test",
"SourcePlatform": "node"
}
],
"ErrorMessage": null,
"IsOK": true
}importVitals(vitals)
Imports vital sign records from a connected device. User.TenantID, User.Email, DevicePlatform, and at least one record are required. Each record must include Id, Type, Unit, StartDate, EndDate, SourceName, and SourcePlatform; Value may be null when the source does not provide a numeric value.
await client.importVitals({
User: {
TenantID: "healthcheck",
Email: "[email protected]",
},
Records: [
{
Id: "record-hr-001",
Type: "HeartRate",
Value: 72,
Unit: "bpm",
StartDate: "2026-06-09T08:00:00.000Z",
EndDate: "2026-06-09T08:00:00.000Z",
SourceName: "Apple Health",
SourcePlatform: "ios",
},
],
SyncTimestamp: "2026-06-09T08:00:00.000Z",
DevicePlatform: "ios",
});The request body is sent exactly as shown, without a Data wrapper.
Returns Promise<APIResponse<boolean>>.
Example response:
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}importVitalsImpilo(deviceType?)
Imports available readings from the authenticated patient's linked Impilo account. Patient identity is resolved from the authorization token.
deviceType is an optional Impilo device-type filter. Omit it or pass null to import all available streams.
The platform:
- Checks whether the authenticated patient has a valid Impilo registration.
- Retrieves all readings returned by Impilo across the supported reading streams.
- Normalizes those readings into the shared vitals format.
- Sends the normalized readings through the existing Healthcheck vitals import flow.
Supported reading categories include blood pressure, blood glucose, oxygen saturation, weight, temperature, and heart rate. Blood pressure readings are normalized into separate systolic and diastolic records.
const allReadings =
await client.importVitalsImpilo();
const bloodPressureReadings =
await client.importVitalsImpilo(
"blood_pressure"
);Returns Promise<APIResponse<boolean>>.
Example request for all streams:
{
"Data": {
"DeviceType": null
}
}Example filtered request:
{
"Data": {
"DeviceType": "blood_pressure"
}
}Data: true means that the import request was handled successfully. It does not always mean that new vital records were added. The operation is also considered successful when the patient does not have a linked Impilo account, a stored Impilo mapping is stale, or Impilo returns no readings.
Example response:
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}whoopAuth(redirectURL)
Returns the WHOOP authorization URL. Pass the page that WHOOP should redirect to after the patient grants consent.
const redirectURL = "https://app.example.com/oauth/callback";
const response = await client.whoopAuth(redirectURL);
console.log(response.Data);Returns Promise<APIResponse<string>>.
Example response:
{
"Data": "https://api.prod.whoop.com/oauth/oauth2/auth?response_type=code&client_id=...&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&scope=read%3Arecovery+read%3Acycles+read%3Asleep+read%3Aprofile+read%3Abody_measurement+offline",
"ErrorMessage": null,
"IsOK": true
}whoopSubmit(authCode, redirectURL)
Submits the WHOOP authorization code and redirect URL, then imports any available WHOOP vitals for the authenticated patient.
redirectURL must be exactly the same URL passed to whoopAuth(), including the protocol, path, query string, and trailing slash.
const redirectURL = "https://app.example.com/oauth/callback";
const authResponse = await client.whoopAuth(redirectURL);
const response = await client.whoopSubmit(
"whoop-authorization-code",
redirectURL
);Returns Promise<APIResponse<boolean>>.
Data: true means that the WHOOP sync request was handled successfully. It does not always mean that new vital records were added. The operation is also considered successful when WHOOP returns no scored cycles, sleep, recovery, or workout records for the current lookback window.
Example response:
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}ouraAuth(redirectURL)
Returns the Oura Ring authorization URL. Pass the page that Oura should redirect to after the patient grants consent.
const redirectURL = "https://app.example.com/oauth/callback";
const response = await client.ouraAuth(redirectURL);
console.log(response.Data);Returns Promise<APIResponse<string>>.
Example response:
{
"Data": "https://cloud.ouraring.com/oauth/authorize?response_type=code&client_id=...&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth%2Fcallback&scope=email+personal+daily+heartrate+workout+tag+session+spo2Daily+ring_configuration+daily_stress",
"ErrorMessage": null,
"IsOK": true
}ouraSubmit(authCode, redirectURL)
Exchanges the Oura Ring authorization code, stores the linked patient's Oura credentials, and starts the vitals import.
redirectURL must be exactly the same URL passed to ouraAuth(), including the protocol, path, query string, and trailing slash.
const redirectURL = "https://app.example.com/oauth/callback";
const authResponse = await client.ouraAuth(redirectURL);
const response = await client.ouraSubmit(
"oura-authorization-code",
redirectURL
);Returns Promise<APIResponse<boolean>>.
Data: true means that the Oura sync request was handled successfully. It does not always mean that new vital records were added.
Example response:
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}logVitals(logData)
Logs a vitals event. No authorization required — accepts any key-value data.
await client.logVitals({
event: "sync-complete",
source: "mobile-app",
timestamp: new Date().toISOString(),
email: "[email protected]",
});Returns Promise<APIResponse<boolean>>.
Example response:
{
"Data": true,
"ErrorMessage": null,
"IsOK": true
}Method Summary
| Method | Behavior | Auth required |
| --- | --- | --- |
| listVitals(limit?) | Returns stored vitals | Yes |
| importVitals(vitals) | Imports a supplied vitals payload | Yes |
| importVitalsImpilo(deviceType?) | Imports all or filtered readings from the linked Impilo account | Yes |
| whoopAuth(redirectURL) | Returns a WHOOP authorization URL | Yes |
| whoopSubmit(authCode, redirectURL) | Connects WHOOP and starts vitals import | Yes |
| ouraAuth(redirectURL) | Returns an Oura Ring authorization URL | Yes |
| ouraSubmit(authCode, redirectURL) | Connects Oura Ring and starts vitals import | Yes |
| logVitals(logData) | Logs a vitals event | No |
Notes
listVitals,importVitals,importVitalsImpilo, and the vendor OAuth methods require an authenticated patient token.logVitalsdoes not require authorization.importVitalsImpiloresolves the patient automatically and accepts an optional device-type string, not a vitals payload.importVitalsImpilodoes not create or link Impilo accounts. Registration must already exist.whoopSubmitresolves the authenticated patient automatically and does not accept a vitals payload.whoopSubmitreturns a successful no-op when WHOOP has no records available to import yet.- Use exactly the same redirect URL for a vendor's auth and submit calls. Differences in protocol, path, query string, or trailing slash can cause the OAuth exchange to fail.
Typevalues observed from live data:bloodpressuresystolic,bloodpressurediastolic,HeartRate— always send the type exactly as the source device provides it.SourcePlatformobserved values:ios,manual.
Prerequisites
HCLoginClient must be configured before creating this connector. The patient must be logged in before calling authenticated methods. logVitals does not require authorization.
import { HCLoginClient } from "@healthcloudai/hc-login-connector";
import { FetchClient } from "@healthcloudai/hc-http";
const httpClient = new FetchClient();
const loginClient = new HCLoginClient(httpClient);
loginClient.configure("healthcheck", "dev");
await loginClient.login("[email protected]", "ExamplePassword123!");See the hc-login-connector documentation for the full authentication flow.
Error Handling
Transport and local validation failures throw errors that extend APIError from @healthcloudai/hc-http. Backend responses, including responses with IsOK: false, are returned without transformation.
import { APIError } from "@healthcloudai/hc-http";
try {
const result = await client.someMethod();
} catch (err) {
if (err instanceof APIError) {
console.error("SDK error:", err.message, err.code);
}
}