---
title: Webhook Events
---


## Introduction

This reference documents the exact JSON structure for each webhook event type. Use these schemas to parse incoming webhook payloads and map them to your data models.

{% callout title="Webhook payloads differ from API responses" %}
The JSON structure delivered via webhooks includes additional metadata fields (like `accountId`, `externalId`, and `version`) that may not appear in standard API responses. Always use these schemas when handling webhook events.
{% /callout %}

---

## Score

{% api-example badge="Event" title="ScoreCreatedIntegrationEvent" description="Fired when a health score is generated or updated. Includes the score value, state, and all contributing factors." %}

{% api-panel %}
{% api-property field="id" type="string" description="Unique identifier for this score record" /%}
{% api-property field="profileId" type="string" description="UUID of the profile this score belongs to" /%}
{% api-property field="accountId" type="string" description="UUID of the account that owns the profile" /%}
{% api-property field="externalId" type="string" description="Your external identifier for the user" /%}
{% api-property field="type" type="string" description="Score type: activity, sleep, readiness, wellbeing, mental_wellbeing" /%}
{% api-property field="state" type="string" nullable=true description="Severity level: minimal, low, medium, high" /%}
{% api-property field="score" type="float" nullable=true description="Normalized score from 0.0 to 1.0 where 1.0 is optimal" /%}
{% api-property field="factors" type="ScoreFactor[]" description="Array of contributing factors with individual scores" /%}
{% api-property field="dataSources" type="string[]" description="Data sources used to calculate this score (e.g., age, sleep, activity)" /%}
{% api-property field="scoreDateTime" type="datetime" description="The date this score represents (ISO 8601 format)" /%}
{% api-property field="createdAtUtc" type="datetime" description="UTC timestamp when the score was created" /%}
{% api-property field="version" type="float" description="Version of the scoring algorithm used" /%}
{% /api-panel %}

```json {% title="Example Payload" %}
{
	"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
	"profileId": "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
	"accountId": "a3c1e8d2-4f6b-4a9c-8e7d-2b5f1c3a9e6b",
	"externalId": "user_12345",
	"type": "sleep",
	"state": "high",
	"score": 0.85,
	"factors": [
		{
			"id": "sleep_duration",
			"name": "sleep_duration",
			"value": 7.5,
			"goal": 8.0,
			"score": 0.94,
			"state": "high",
			"unit": "hour"
		},
		{
			"id": "sleep_regularity",
			"name": "sleep_regularity",
			"value": 0.82,
			"goal": 0.9,
			"score": 0.91,
			"state": "high",
			"unit": "index"
		}
	],
	"dataSources": ["age", "sleep"],
	"scoreDateTime": "2025-01-22T00:00:00+00:00",
	"createdAtUtc": "2025-01-22T06:30:00Z",
	"version": 1.1
}
```

{% /api-example %}

{% api-panel badge="Object" name="ScoreFactor" description="Each factor in the factors array follows this structure:" %}
{% api-property field="id" type="string" description="Unique identifier for the factor" /%}
{% api-property field="name" type="string" description="Factor name (e.g., sleep_duration, activity_steps)" /%}
{% api-property field="value" type="float" nullable=true description="The actual measured value" /%}
{% api-property field="goal" type="float" nullable=true description="Target value for optimal health" /%}
{% api-property field="score" type="float" nullable=true description="Factor score from 0.0 to 1.0" /%}
{% api-property field="state" type="string" nullable=true description="Factor state: minimal, low, medium, high" /%}
{% api-property field="unit" type="string" description="Unit of measurement" /%}
{% /api-panel %}

---

## Biomarker

{% api-example badge="Event" title="BiomarkerCreatedIntegrationEvent" description="Fired when a biomarker value is calculated. Biomarkers are standardized health metrics like steps, heart rate, or sleep duration." %}

{% api-panel %}
{% api-property field="id" type="string" description="Unique identifier for this biomarker record" /%}
{% api-property field="profileId" type="string" description="UUID of the profile this biomarker belongs to" /%}
{% api-property field="accountId" type="string" description="UUID of the account that owns the profile" /%}
{% api-property field="externalId" type="string" description="Your external identifier for the user" /%}
{% api-property field="category" type="string" description="Biomarker category: activity, sleep, body, vitals, engagement" /%}
{% api-property field="type" type="string" description="Biomarker type (e.g., steps, heart_rate_resting, sleep_duration)" /%}
{% api-property field="periodicity" type="string" description="Data frequency: daily, weekly, monthly, or none" /%}
{% api-property field="aggregation" type="string" description="Aggregation method: total, average, maximum, minimum, or none" /%}
{% api-property field="value" type="string" description="The calculated biomarker value (as string for precision)" /%}
{% api-property field="unit" type="string" description="Unit of measurement (e.g., count, hour, bpm, kcal)" /%}
{% api-property field="valueType" type="string" description="Data type of the value: integer, float, boolean, string" /%}
{% api-property field="startDateTime" type="string" description="Start of the measurement period (ISO 8601)" /%}
{% api-property field="endDateTime" type="string" description="End of the measurement period (ISO 8601)" /%}
{% api-property field="createdAtUtc" type="datetime" description="UTC timestamp when the biomarker was created" /%}
{% api-property field="version" type="float" description="Version of the biomarker calculation" /%}
{% /api-panel %}

```json {% title="Example Payload" %}
{
	"id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
	"profileId": "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
	"accountId": "a3c1e8d2-4f6b-4a9c-8e7d-2b5f1c3a9e6b",
	"externalId": "user_12345",
	"category": "activity",
	"type": "steps",
	"periodicity": "daily",
	"aggregation": "total",
	"value": "8547",
	"unit": "count",
	"valueType": "integer",
	"startDateTime": "2025-01-22T00:00:00+00:00",
	"endDateTime": "2025-01-22T23:59:59+00:00",
	"createdAtUtc": "2025-01-22T18:30:00Z",
	"version": 1.0
}
```

{% /api-example %}

---

## Archetype

{% api-example badge="Event" title="ArchetypeCreatedIntegrationEvent" description="Fired when a user is assigned an archetype. Archetypes categorize users into behavioral patterns like activity level or sleep chronotype." %}

{% api-panel %}
{% api-property field="id" type="string" description="Unique identifier for this archetype record" /%}
{% api-property field="profileId" type="string" description="UUID of the profile this archetype belongs to" /%}
{% api-property field="accountId" type="string" description="UUID of the account that owns the profile" /%}
{% api-property field="externalId" type="string" description="Your external identifier for the user" /%}
{% api-property field="name" type="string" description="Archetype category name (e.g., activity_level, chronotype, sleep_pattern)" /%}
{% api-property field="value" type="string" description="Assigned archetype value (e.g., early_bird, night_owl, highly_active)" /%}
{% api-property field="dataType" type="string" description="Data type of the value" /%}
{% api-property field="periodicity" type="string" description="How often the archetype is recalculated: daily, weekly, monthly" /%}
{% api-property field="ordinality" type="integer" description="Rank order when multiple archetypes exist (0-based)" /%}
{% api-property field="startDateTime" type="datetime" description="Start of the analysis period" /%}
{% api-property field="endDateTime" type="datetime" description="End of the analysis period" /%}
{% api-property field="createdAtUtc" type="datetime" description="UTC timestamp when the archetype was assigned" /%}
{% api-property field="version" type="float" description="Version of the archetype algorithm" /%}
{% /api-panel %}

```json {% title="Example Payload" %}
{
	"id": "d4e5f6a7-b8c9-0123-def4-567890123456",
	"profileId": "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
	"accountId": "a3c1e8d2-4f6b-4a9c-8e7d-2b5f1c3a9e6b",
	"externalId": "user_12345",
	"name": "chronotype",
	"value": "early_bird",
	"dataType": "string",
	"periodicity": "weekly",
	"ordinality": 0,
	"startDateTime": "2025-01-15T00:00:00Z",
	"endDateTime": "2025-01-22T00:00:00Z",
	"createdAtUtc": "2025-01-22T06:00:00Z",
	"version": 1.0
}
```

{% /api-example %}

---

## Tag

{% api-example badge="Event" title="TagReceivedIntegrationEvent" description="Fired when a tag is received—a time-bound categorical label such as a symptom, medication, shift, or subscription. Tags arrive from the SDK, Sahha's platform integrations, or your own backend, and stream in the same shape they were sent." %}

{% api-panel %}
{% api-property field="id" type="string" description="Server-generated identifier. Identity is derived from name, type, source, and startDateTime under the profile" /%}
{% api-property field="profileId" type="string" description="UUID of the profile this tag belongs to" /%}
{% api-property field="accountId" type="string" description="UUID of the account that owns the profile" /%}
{% api-property field="externalId" type="string" description="Your external identifier for the user" /%}
{% api-property field="type" type="string" description="event (point in time) or state (window of time)" /%}
{% api-property field="category" type="string" nullable=true description="Optional bucket—reserved (symptom, reproductive) or any custom value" /%}
{% api-property field="name" type="string" description="The primary signal—reserved name or custom" /%}
{% api-property field="value" type="string" nullable=true description="Optional severity, dose, or variant. May be null for presence-only flags" /%}
{% api-property field="source" type="string" description="Which system produced the tag. SDK and integrations set this automatically; backend uploads typically use a reverse-DNS string (e.g. acme.workforce)" /%}
{% api-property field="startDateTime" type="datetime" description="When the tag began (ISO 8601)" /%}
{% api-property field="endDateTime" type="datetime" nullable=true description="When the tag ended. Null for events; may be null for open states" /%}
{% api-property field="receivedAtUtc" type="datetime" description="UTC timestamp when Sahha received the tag" /%}
{% api-property field="additionalProperties" type="object<string,string>" nullable=true description="Auxiliary metadata. Sahha uses reserved keys only; custom keys are stored and returned verbatim" /%}
{% /api-panel %}

```json {% title="Example Payload" %}
{
	"id": "f3b1a8e0-4c5d-4e6f-9a8b-1c2d3e4f5a01",
	"profileId": "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
	"accountId": "a3c1e8d2-4f6b-4a9c-8e7d-2b5f1c3a9e6b",
	"externalId": "user_12345",
	"type": "state",
	"category": "work",
	"name": "night_shift",
	"value": "12_hour",
	"source": "acme.workforce",
	"startDateTime": "2025-01-22T19:00:00+00:00",
	"endDateTime": "2025-01-23T07:00:00+00:00",
	"receivedAtUtc": "2025-01-23T07:05:02Z",
	"additionalProperties": {
		"role": "icu_nurse",
		"overtime": "false"
	}
}
```

{% /api-example %}

{% callout title="Tag identity" %}
A tag's identity is the tuple `profileId + name + type + source + startDateTime`, not the `id`. Re-uploading the same tuple—for example to close an open state with an `endDateTime`—updates the existing record, so you may receive more than one event for the same tag. Use the identity tuple for idempotency. See [Tags](/docs/products/tags) for the full schema.
{% /callout %}

---

## Data Log

{% api-example badge="Event" title="DataLogReceivedIntegrationEvent" description="Fired when raw health data is received from a user's device. Contains the original samples from HealthKit or Health Connect." %}

{% api-panel %}
{% api-property field="logType" type="string" description="Log category: activity, sleep, heart, body, energy, exercise, blood, oxygen, temperature, device" /%}
{% api-property field="dataType" type="string" description="Specific data type (e.g., steps, heart_rate, sleep_stage_deep)" /%}
{% api-property field="profileId" type="string" description="UUID of the profile this data belongs to" /%}
{% api-property field="accountId" type="string" description="UUID of the account that owns the profile" /%}
{% api-property field="externalId" type="string" description="Your external identifier for the user" /%}
{% api-property field="receivedAtUtc" type="string" description="UTC timestamp when Sahha received the data" /%}
{% api-property field="dataLogs" type="DataLog[]" description="Array of individual data samples" /%}
{% /api-panel %}

```json {% title="Example Payload" %}
{
	"logType": "activity",
	"dataType": "steps",
	"profileId": "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
	"accountId": "a3c1e8d2-4f6b-4a9c-8e7d-2b5f1c3a9e6b",
	"externalId": "user_12345",
	"receivedAtUtc": "2025-01-22T14:30:00Z",
	"dataLogs": [
		{
			"id": "e5f6a7b8-c9d0-1234-ef56-789012345678",
			"parentId": null,
			"value": 1250,
			"unit": "count",
			"source": "iPhone 15 Pro",
			"recordingMethod": "RECORDING_METHOD_AUTOMATICALLY_RECORDED",
			"deviceType": "iPhone16,1",
			"startDateTime": "2025-01-22T09:00:00+00:00",
			"endDateTime": "2025-01-22T10:00:00+00:00",
			"additionalProperties": {}
		},
		{
			"id": "f6a7b8c9-d0e1-2345-f678-901234567890",
			"parentId": null,
			"value": 890,
			"unit": "count",
			"source": "Apple Watch",
			"recordingMethod": "RECORDING_METHOD_AUTOMATICALLY_RECORDED",
			"deviceType": "Watch7,1",
			"startDateTime": "2025-01-22T10:00:00+00:00",
			"endDateTime": "2025-01-22T11:00:00+00:00",
			"additionalProperties": {}
		}
	]
}
```

{% /api-example %}

{% api-panel badge="Object" name="DataLog" description="Each item in the dataLogs array contains:" %}
{% api-property field="id" type="string" description="Unique identifier for this sample" /%}
{% api-property field="parentId" type="string" nullable=true description="Parent record ID for hierarchical data (e.g., exercise sessions)" /%}
{% api-property field="value" type="float" description="The recorded measurement value" /%}
{% api-property field="unit" type="string" description="Unit of measurement" /%}
{% api-property field="source" type="string" description="Device or app name that recorded the data" /%}
{% api-property field="recordingMethod" type="string" description="How the data was captured (automatic, manual, etc.)" /%}
{% api-property field="deviceType" type="string" description="Device model identifier" /%}
{% api-property field="startDateTime" type="string" description="When the measurement started (ISO 8601)" /%}
{% api-property field="endDateTime" type="string" description="When the measurement ended (ISO 8601)" /%}
{% api-property field="additionalProperties" type="map" description="Extra metadata specific to certain log types" /%}
{% /api-panel %}

---

### Additional Properties

The `additionalProperties` field in DataLog contains metadata specific to certain log types. Log types not listed below (Activity, Body, Energy, Engagement, Sleep) have no additional properties.

#### Blood Logs

| Property              | Type   | Description                         | Example                                |
| --------------------- | ------ | ----------------------------------- | -------------------------------------- |
| `BodyPosition`        | string | Body position during measurement    | `sitting`, `lying_down`                |
| `MealType`            | string | Type of meal consumed               | `breakfast`, `lunch`, `dinner`         |
| `MeasurementLocation` | string | Where on body measurement was taken | `finger`, `arm`                        |
| `RelationToMeal`      | string | Timing relative to meal             | `before_meal`, `after_meal`, `fasting` |
| `SpecimenSource`      | string | Source of the blood specimen        | `capillary`, `venous`                  |

#### Device Logs

| Property         | Type    | Description                      | Example         |
| ---------------- | ------- | -------------------------------- | --------------- |
| `DeviceScreenOn` | boolean | Whether the device screen was on | `true`, `false` |

#### Exercise Logs

| Property            | Type  | Description            | Example           |
| ------------------- | ----- | ---------------------- | ----------------- |
| `TotalDistance`     | float | Total distance covered | `5200.5` (meters) |
| `TotalEnergyBurned` | float | Total calories burned  | `320.0` (kcal)    |

#### Heart Logs

| Property              | Type   | Description                         | Example                            |
| --------------------- | ------ | ----------------------------------- | ---------------------------------- |
| `MeasurementLocation` | string | Where on body measurement was taken | `wrist`, `chest`, `finger`         |
| `MotionContext`       | string | User motion state when measured     | `stationary`, `walking`, `running` |

#### Oxygen Logs

| Property            | Type   | Description                              | Example          |
| ------------------- | ------ | ---------------------------------------- | ---------------- |
| `MeasurementMethod` | string | Method used to measure oxygen saturation | `pulse_oximetry` |

#### Temperature Logs

| Property              | Type   | Description                            | Example                    |
| --------------------- | ------ | -------------------------------------- | -------------------------- |
| `MeasurementLocation` | string | Where on body temperature was measured | `wrist`, `forehead`, `ear` |

<!-- #### Reproductive Logs

| Property | Type | Description |
|----------|------|-------------|
| `LengthInDays` | integer | Length of cycle in days |
| `DaysUntilNextPhase` | integer | Days remaining until next phase |
| `CycleStart` | string | Start date of the cycle |
| `Flow` | string | Flow intensity |
| `IsPredicted` | string | Whether the data is predicted |
| `Title` | string | Title or label for the entry |
| `OriginalDueDate` | string | Original expected date |
| `Appearance` | string | Physical appearance description |
| `Sensation` | string | Physical sensation description |
| `Result` | string | Test or measurement result |
| `ProtectionUsed` | string | Protection method used |
| `ContraceptiveUsed` | string | Contraceptive method used | -->

---

<!-- ## Handling Events

Here's a complete example of routing webhook events to the appropriate handler:

```javascript {% title="Event routing example" %}
function handleWebhookEvent(eventType, payload) {
  switch (eventType) {
    case 'ScoreCreatedIntegrationEvent':
      handleScore(payload);
      break;
    case 'BiomarkerCreatedIntegrationEvent':
      handleBiomarker(payload);
      break;
    case 'ArchetypeCreatedIntegrationEvent':
      handleArchetype(payload);
      break;
    case 'DataLogReceivedIntegrationEvent':
      handleDataLogs(payload);
      break;
    default:
      console.warn(`Unknown event type: ${eventType}`);
  }
}

function handleScore(score) {
  const { profileId, externalId, type, score: value, factors } = score;

  // Store the score
  db.scores.upsert({
    id: score.id,
    userId: externalId,
    type,
    value,
    factors,
    scoredAt: score.scoreDateTime
  });
}

function handleDataLogs(event) {
  const { externalId, logType, dataType, dataLogs } = event;

  // Process each sample
  for (const log of dataLogs) {
    db.rawSamples.insert({
      userId: externalId,
      logType,
      dataType,
      value: log.value,
      unit: log.unit,
      source: log.source,
      device: log.deviceType,
      startedAt: log.startDateTime,
      endedAt: log.endDateTime,
      metadata: log.additionalProperties
    });
  }
}
```

--- -->

## Support

Questions about webhook events? Reach out in the [Slack community](https://join.slack.com/t/sahhacommunity/shared_invite/zt-1w0fmfbvk-qUwQ83tJgXyjT9XSxJvKIw) or contact [support@sahha.ai](mailto:support@sahha.ai).
