Skip to content

Event Envelope

Every event emitted by HealthSync uses this envelope. The envelope handles classification, provenance, and delivery routing. Data items inside data[] are self-contained with their own identity, timestamps, and versioning.

HealthSync signs every outbound webhook POST with the tenant’s webhook signing secret (wss_...). Verify the signature before parsing or trusting the envelope.

Header Value
X-HealthSync-Signature-256 sha256=<hex>, where <hex> is the lowercase HMAC-SHA256 digest
X-HealthSync-Timestamp Unix timestamp in seconds
X-HealthSync-Delivery-Id Stable delivery id for this envelope — identical on every redelivery or retry of the same logical delivery
X-HealthSync-Event-Type Canonical event_type string

To verify a delivery:

  1. Read the exact raw UTF-8 request body. Do not parse and re-stringify JSON before verifying.
  2. Reject the request if X-HealthSync-Timestamp is missing, invalid, or more than 5 minutes from your current clock.
  3. Build the signing input exactly as {timestamp}.{deliveryId}.{body}. The two dots are literal separators.
  4. Compute HMAC-SHA256 using the plaintext webhook signing secret as UTF-8 bytes.
  5. Lowercase-hex encode the digest, prefix it with sha256=, and compare it with X-HealthSync-Signature-256 using a constant-time comparison.
  6. Deduplicate accepted at-least-once redeliveries on X-HealthSync-Delivery-Id.
import crypto from "node:crypto";
export function verifyHealthSyncWebhook(input: {
rawBody: string;
headers: Headers;
webhookSigningSecret: string;
toleranceSeconds?: number;
}): boolean {
const timestamp = input.headers.get("X-HealthSync-Timestamp");
const deliveryId = input.headers.get("X-HealthSync-Delivery-Id");
const signature = input.headers.get("X-HealthSync-Signature-256");
if (!timestamp || !deliveryId || !signature) return false;
const timestampSeconds = Number(timestamp);
if (!Number.isInteger(timestampSeconds)) return false;
const tolerance = input.toleranceSeconds ?? 300;
const nowSeconds = Math.floor(Date.now() / 1000);
if (Math.abs(nowSeconds - timestampSeconds) > tolerance) return false;
const signingInput = `${timestamp}.${deliveryId}.${input.rawBody}`;
const expectedDigest = crypto
.createHmac("sha256", Buffer.from(input.webhookSigningSecret, "utf8"))
.update(signingInput, "utf8")
.digest("hex");
const expected = `sha256=${expectedDigest}`;
const expectedBytes = Buffer.from(expected, "utf8");
const actualBytes = Buffer.from(signature, "utf8");
return (
expectedBytes.length === actualBytes.length &&
crypto.timingSafeEqual(expectedBytes, actualBytes)
);
}
{
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"schema_version": "1.1",
"event_type": "activity",
"stream": "session",
"provider": "garmin",
"sources": [
{
"provider_notification_id": "notif-abc123",
"fetched_at": 1742585000000
}
],
"devices": [
{
"device_id": "dev-001",
"name": "Forerunner 265",
"model": "3991",
"provider_device_id": "dev-001"
}
],
"tenant_id": "tenant-uuid",
"user_id": "user-uuid",
"external_user_ref": "your-user-123",
"connection_id": "conn-uuid",
"emitted_at": 1742585400000,
"data": [
// array of type-specific data items
]
}
Field Type Description
event_id string (uuid) Unique per emission. Re-processing the same data produces a new event_id.
schema_version string Envelope schema version for forward compatibility.
event_type string Discriminator for the data shape. All items in data[] share this type.
stream string Stream tier: "session", "snapshot", "timeseries", "aggregate", or "profile".
provider string Source provider identifier (e.g., "garmin", "googleHealth", or "polar").
sources array Notification references that triggered this event. Empty [] for backfill or non-notification events.
sources[].provider_notification_id string | null The provider notification that triggered the fetch.
sources[].fetched_at number (epoch ms) When HealthSync fetched in response to the notification.
devices array Device registry for this event. Data items reference devices by device_id.
devices[].device_id string HealthSync-scoped device identifier.
devices[].name string | null Device display name.
devices[].model string | null Device model identifier.
devices[].provider_device_id string | null Provider’s native device ID.
tenant_id string Target tenant.
user_id string Target user within the tenant (HealthSync internal tenant_user_id).
external_user_ref string Tenant-provided external user reference echoed from connect-time user creation.
connection_id string The connection that produced this data.
emitted_at number (epoch ms) When HealthSync emitted this event.
data array One or more data items, all of the same event_type.

The sources array records which provider notifications triggered this event:

  • Notification-triggered events: One or more source entries with fetched_at timestamps.
  • Backfill / replay events: Empty array [].
  • Manual / scheduled fetches: Empty array [].

The devices array is a registry of devices relevant to this event. Individual data items reference devices by device_id. When device attribution is unavailable, a data item sets device_id to null.