# Introduction

Welcome to Thryve! We help you to access data from 500+ wearable devices and health apps through one integration.

Thryve enables app developers to access fitness and health data from smartwatches, smartphones, medical devices, health sensors, and health apps via one unified integration.&#x20;

Thryve's technology allows you to obtain authorization to get data within your existing web or mobile app. We will ensure you always have the latest information on your users' activities and health.

The following pages explain the main concepts and will help you to:

* [**Connect**](/thryve-product-overview/connect) your users' wearables with your app, ensuring health data is flowing in near-time 24/7
* [**Access**](/thryve-product-overview/access/data-types-biomarker) new data and historical data for hundreds of health data sources in a well-structured format
* [**Understand**](/thryve-product-overview/understand) your users' health by leveraging Thryve's data annotations and on-top analytics
* [**Control**](/thryve-product-overview/control) all aspects of your users' experience and all data processing<br>

{% hint style="info" %}
Check out the full list of [data sources](/thryve-product-overview/connect) and [data types](/thryve-product-overview/access/data-types-biomarker#data-type-categories)  that we support.
{% endhint %}


# Get your API Keys

This guide walks you through creating your Thryve account and obtaining the credentials necessary to integrate with our API and SDKs.

{% stepper %}
{% step %}

### Subscribe to Thryve

Visit [Thryve Health Pricing](https://www.thryve.health/product/pricing) to choose a suitable plan. You'll be directed to Stripe checkout for payment.

<figure><img src="/files/GSseoWd30cZCrSuhC8Mr" alt=""><figcaption></figcaption></figure>

After payment confirmation, you'll receive a welcome email at your specified address. This email includes a link to set up your Thryve account.
{% endstep %}

{% step %}

### Create your account

Click **CREATE MY THRYVE ACCOUNT** in the welcome email. Follow these steps:

1. Set a secure password for your Thryve account.
2. Configure two-factor authentication (2FA) with an authenticator app.
3. Name your app.

After setup, Thryve automatically creates two app environments:

* `staging-{your_app_name}` – For testing and development.
* `live-{your_app_name}` – For production.

You'll then be redirected to the Thryve Dashboard overview page.
{% endstep %}

{% step %}

### Access and store your credentials

After naming your apps, you'll receive three separate emails containing:

1. **Global API Key:** Required for any API requests; this key is consistent across all your Thryve apps
2. **App Authentication Keys**: Required for SDK initialization and API requests; each Thryve app receives unique credentials.
3. **SDK Download Credentials:** Necessary to download Thryve SDK dependencies

{% hint style="info" %}
All credentials are displayed only once and expire 24 hours after email delivery. Store them securely and share them only with authorised team members. If you lose access to your credentials, [contact support](https://thryve.zendesk.com/) to generate a new credential set. Previously shared credentials cannot be recovered.
{% endhint %}
{% endstep %}

{% step %}

### Explore Thryve using the product demo tour (optional)

Upon first accessing the Dashboard, you'll be invited to begin the product orientation tour. You have the option to skip it and revisit later or complete the 5-step guided setup immediately.

**Key Features of the Tour:**

* **Staging App Setup**: Configure your app and manage settings within the Thryve Dashboard.
* **Data Source Selection**: Choose which data sources and data types you want to enable.
* **Webhook Configuration**: Establish and test webhook endpoints using mock payloads.
* **User Experience Simulation**: Experience the Thryve connection widget as your end users would.
* **API Testing**: Test Thryve API requests using either real or mock data.

Any configurations made during the tour are saved to your staging app, providing you with a foundational setup to build upon.
{% endstep %}
{% endstepper %}

### What's next?

You now have everything needed to integrate Thryve.

* **For Mobile App Integration:**  [Follow the Mobile Integration Guide](/integrate-your-mobile-app/setup-thryve-sdk)
* **For Web App Integration:** [Follow the Web Integration Guide](/integrate-your-web-app/create-thryve-user)


# Use the Thryve Dashboard

Thryve Dashboard is a unified web interface to manage Thryve's core products - the SDKs and Web APIs. It enables customers to configure, manage, and visualize wearable-derived health data from their users in a single dashboard.

{% hint style="info" %}
The Dashboard alone is not sufficient. You must integrate Thryve SDK or API into your application first. Once integrated, you can use the Dashboard to manage configurations remotely and analyze end-user data
{% endhint %}

## Overview Page

The Overview page provides a snapshot of your apps and Thryve integration metrics.

Two of the most useful sections would be:

1. **Data source connections**

* See the distribution of connected data sources across your end users for each app

2. **Integration metrics**

* Number of Webhooks sent and errors
* Number of Health API requests processed and errors

These metrics can be used to monitor your integration health and identify potential issues.

<div align="left" data-with-frame="true"><figure><img src="/files/8LIm91jho5FKsD92YEXg" alt="" width="563"><figcaption></figcaption></figure></div>

## Configure your apps

Manage three core configuration types that control how Thryve collects and delivers health data.

1. **Data sources**\
   Enable or disable health and fitness platforms ( Apple Health, Samsung Garmin, Strava, etc.) available to your end users through the Thryve connection widget.\
   Some data sources with custom oAuth-client needs to be manually enabled by Thryve support, which appear at the bottom of the list. Contact support to enable them.<br>

   <div align="left" data-with-frame="true"><figure><img src="/files/PyTs1YphRKLo7asdIkNN" alt="" width="563"><figcaption></figcaption></figure></div>

2. **Data types**\
   Control which health data categories and specific data types Thryve collects from connected sources. You can enable or disable full categories (Activity, Sleep, Cardiovascular Health, etc.) or configure individual data types within each category.\
   For example, under Activity, you can enable steps while disabling ElevationGain. Only enabled data types are collected from end users and sent to your webhook endpoint.\ <br>

   <div align="left" data-with-frame="true"><figure><img src="/files/8QnYT8VIgfOSeFkSKZwH" alt="" width="563"><figcaption></figcaption></figure></div>

3. **Webhooks**\
   Configure your webhook endpoint to receive real-time health data updates from Thryve.\
   \
   **Endpoint configuration:**

* Set your webhook URL where Thryve sends data
* Add optional authentication for secure webhook delivery
* Choose webhook type: Data push webhooks (recommended) or notification webhooks
* Customize message format and advanced settings\
  \
  **Test your webhook:** \
  Use the test function to send a sample payload to your endpoint and verify it's receiving data correctly.\ <br>

  <div align="left" data-with-frame="true"><figure><img src="/files/tNXKjVtRnXYS07dZYZYO" alt="" width="563"><figcaption></figcaption></figure></div>

## Manually View End-User Data

1. **Review users**\
   View all end users who have connected their wearable data sources through your app.

   The users table displays:

   * End User ID (Thryve's unique identifier)&#x20;
   * End User Alias (optional identifier you can set)
   * Creation timestamp (when the user was created in Thryve)

   <div align="left" data-with-frame="true"><figure><img src="/files/RVxjZ3ANMPEmly9xSGwT" alt="" width="563"><figcaption></figcaption></figure></div>

2. **Analyze user data**\
   Request and view health data for specific end users directly in the Dashboard without using API calls or tools.\
   \
   **How to use:**

   1. Select a user from the dropdown
   2. Set start and end dates for the data request range
   3. (Optional) Filter by specific data sources or data types
   4. Click **Search** to view results

   The data table displays both epoch data and daily data based on availability. Export data for further analysis.\ <br>

   <div align="left"><figure><img src="/files/SrZNYCbjxyyrJF33eZmL" alt="" width="563"><figcaption></figcaption></figure></div>


# Dashboard Roles

The Thryve Dashboard supports role-based access control to protect your production environment while enabling team collaboration. Access is managed through three roles: **admin, developer, and data analyst.**

## Available roles

### Admin

* Full access to all configuration and data in both staging and production environments

### Developer (staging only access)

* Access to configuration and data in staging environment only
* No access to production data or configuration changes

### Data Analyst (data only access)

* Can view and request data in both staging and production environments
* Cannot modify any configuration settings

## Role Permissions Breakdown

### Service Configurations

Applies to webhooks, data sources, and data types configuration pages

| Area                      | Action             | Admin | Developer | Data Analyst |
| ------------------------- | ------------------ | ----- | --------- | ------------ |
| **Staging App**           | View configuration | ✅     | ✅         | ✅            |
|                           | Edit configuration | ✅     | ✅         | ❌            |
| **Live App (Production)** | View configuration | ✅     | ✅         | ✅            |
|                           | Edit configuration | ✅     | ❌         | ❌            |

### Health Data Access

Applies to Review Users and Analyze User Data pages

| Area                      | Action              | Admin | Developer | Data Analyst |
| ------------------------- | ------------------- | ----- | --------- | ------------ |
| **Staging data**          | Request & view data | ✅     | ✅         | ✅            |
| **Live App (Production)** | Request & view data | ✅     | ❌         | ✅            |

{% hint style="info" %}
The first dashboard account automatically receives the admin role. For adding additional users with specific roles, please contact Thryve Support.
{% endhint %}


# Thryve SDK 4.x to 5.x migration

This page covers migrations from previous to latest versions.

In version 5.0.0, the Thryve SDK introduced major changes to its architecture. If your application was built using Thryve SDK 4.x.x, ensure to complete the actions listed in the following sections to have a smooth migration of your Thryve implementation in your application to Thryve SDK 5.0.0.

## **Core changes**

The 5.0 update introduces a `ThryveSDK` singleton, streamlining access to the SDK's functionality. This unified interface simplifies interactions by encapsulating all internal mechanisms.

### CoreConnector is now ThryveSDK

In version 5.0.0, `ThryveSDK` replaces `CoreConnector`. As a singleton, `ThryveSDK` it consolidates the functionalities of `CoreConnector` . Initializing `CoreConnector` is now obsolete.

Initialize the SDK using:

```swift
await ThryveSDK.getOrCreate(thryveSDKConfig).getUserInformation()

// Optionally, when ThryveSDK is initialized from a non-async context (AppDelegate, legacy code, etc.), 
// it is recommended to use the getOrCreate(...) callback to know when the SDK is ready.

ThryveSDK.getOrCreate(thryveSDKConfig) { initResult in
    if initResult.successful {
        Logger.i("ThryveSDK ready, you can start calling API methods")
    } else if let error = initResult.errors?.first {
        Logger.e("ThryveSDK init failed: \(error.errorMessage ?? "Unknown error")")
    }
} 
```

Check [Initialize the Thryve SDK](https://docs.thryve.health/integrate-your-mobile-app/connect-data-sources#initialize-the-thryve-sdk) section for more info.

### Centralized (module) configuration

All configuration options provided to developers are within the `ThryveSDKConfig`  object. See [documentation](/integrate-your-mobile-app/connect-data-sources#initialize-the-thryve-sdk) for further information.

### Accessing (module) functions

All module functions, like those from `ThryveAppleHealth` or `ThryveHealthConnect`, are now accessed through:

```swift
ThryveSDK.get().getUserInformation()
ThryveSDK.get().synchronize(...)
ThryveSDK.get().backfillEpoch(...)
```

### Automated User Creation with Thryve SDK

In Thryve SDK 4.x, developers needed to call `getAccessToken` to create or fetch users. This process is now [automated during SDK initialization](/integrate-your-mobile-app/connect-data-sources#create-a-thryve-user). To obtain the `endUserId` (previously `accessToken`) for backend operations, use the new `getEndUserId` method.

### Thryve Connection Widget replaces the former screen provided via `dataSourceUrl`

With the release of Thryve SDK 5.0.0, we've introduced the new [`ThryveDataSourceConnectionWidget`](/integrate-your-mobile-app/connect-data-sources#display-the-thryve-connection-widget). This widget empowers your users to easily connect and disconnect all enabled data sources for your application, eliminating the need for you to implement additional views or logic - the Thryve SDK takes all care.

<figure><img src="/files/qzBiLT1CzGy5kusP0dpL" alt="" width="188"><figcaption><p>Thryve Connection Widget makes it super simple to allow users to connect theiir data sources</p></figcaption></figure>

Unlike the previous screen provided via `dataSourceURL`, the `ThryveDataSourceConnectionWidget` now supports native data sources such as Apple Health, Health Connect, and Samsung Health, provided the necessary modules are added and configured in your application.

## Plattform-specific changes

{% tabs %}
{% tab title="iOS SDK" %}

### ModuleAppleHealth is now ThryveAppleHealth

The Apple Health module of the Thryve iOS SDK was previously named `ModuleAppleHealth`  and has been renamed to `ThryveAppleHealth` . All imports and references to `ModuleAppleHealth` should be changed to `ThryveAppleHealth` .

### HKConnector initialization  is obsolete

The manual initialization of `HKConnector` is no longer required in 5.0.0. [ThryveSDK](/integrate-your-mobile-app/connect-data-sources#ios) singleton handles all the internal mechanisms of `HKConnector` .
{% endtab %}

{% tab title="Android SDK" %}

### Base package name changed

The base package name of the Android SDK is renamed from `com.thryve.connector` to `com.thryve.sdk`  all references and imports should be updated accordingly. The Thryve SDK dependencies in `build.gradle` should be renamed to:

```gradle
dependencies {
    ...
    api "com.thryve.sdk:core:${thryve_sdk_version}"
}
```

### Thryve Health Connect module package renamed

The package name of the Thryve SDK Health Connect module is renamed to `com.thryve.sdk.healthConnect`. It was named `com.thryve.connector.module_hconnect`  in all versions before 5.0.0. All references and imports should be updated accordingly.

### ThryveHealthConnectConnector initialization is obsolete

The manual initialization of `ThryveHealthConnectConnector` is no longer required in 5.0.0. [ThryveSDK](/integrate-your-mobile-app/connect-data-sources#android) singleton handles all the internal mechanisms of `ThryveHealthConnectConnector`

### Thryve Samsung Health module package renamed

The package name of the Thryve SDK Samsung Health module is renamed to `com.thryve.sdk.samsungHealth` . It was named `com.thryve.connector.shealth`  in all versions before 5.0.0. All references and imports should be updated accordingly.

### SHealthConnector initialization  is obsolete

The manual initialization of `SHealthConnector` is no longer required in 5.0.0. [ThryveSDK](/integrate-your-mobile-app/connect-data-sources#android) singleton handles all the internal mechanisms of `SHealthConnector`
{% endtab %}
{% endtabs %}

## Adapted naming of keywords and variables

With the introduction of Thryve SDK 5.0.0, we have renamed certain keywords and variables to improve clarity. Parameters will be aligned with webhooks and Thryve backend API with the release of next API version. (coming in August)

| Previous Variable/Parameter         | Current Variable/Keyword | Description                                                                                                                                                                                                     |
| ----------------------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `appId`                             | `authId`                 | Credentials to authorize your app with the Thryve SDK.                                                                                                                                                          |
| `appSecret`                         | `authSecret`             | Credentials to authorize your app with the Thryve SDK.                                                                                                                                                          |
| `partnerUserID`                     | `endUserAlias`           | Alias for Thryve user that can be set optionally by you. Make sure to set a secure, non-predictable, unique identifier without personal identifiable information to keep Thryve data pseudonomous.              |
| `accessToken`/`authenticationToken` | `endUserId`              | Unique identifier of Thryve user automatically generated by Thryve backend. All data saved with Thryve is linked to this endUserId. It is also used to specify the user you request data for with Thryve's API. |
| `language`                          | `locale`                 | The language code following [ISO 639-1](https://www.loc.gov/standards/iso639-2/php/code_list.php) to set the language that will be used on UI elements, e.g. the Thryve Widget.                                 |


# Connect

With health data the end-user and patients are in the driver seat! We make it a breeze to get your end-users'  authorization within your web or mobile app so that you can access all the data you need.

When it comes to wearables and health sensors, the end user has ultimate control over what data is shared. Therefore, you must ask your end user to authorize their data source or device within your app before you can receive any health and wearable data. This will enable us to collect data for you and present it in a unified format.

<figure><img src="/files/qzBiLT1CzGy5kusP0dpL" alt="The gif shows the Thryve Connection Widget and how a user connects to Apple Health using it." width="188"><figcaption><p>Thryve Connection Widget (embedded in Thryve Sample App)</p></figcaption></figure>

Users will need to authorize their data sources within your application. For authorization of [web data sources](#user-content-fn-1)[^1], they will authorize access to the data of their data source account, and therefore all devices linked to this account. For [native data sources](#user-content-fn-2)[^2], users will authorize access to data on their smartphone or tablet where your app is installed, and therefore access data from all devices and apps connected to the data source on the corresponding device.

With Thryve, you only need to do two things to obtain authorization and make your users connect:

1. Create a Thryve user for whom the connection will be established, and data will be saved with
2. Let your users connect within your app via the Thryve Connection Widget or your custom data source connection screen.

### How do I create a user and let my user connect?

If you have a **mobile application,** please refer to the following integration guidelines:

* [Initialize the Thryve SDK and launch the Thryve Connection Widget](/integrate-your-mobile-app/connect-data-sources)
* [Build your own data source connection screen using the SDK](/integrate-your-mobile-app/connect-data-sources/build-your-custom-data-source-connection-screen)

If you have a **web application,** please refer to the following integration guidelines:

* [Create a Thryve user via API call](/integrate-your-web-app/create-thryve-user)
* [Receive Thryve data source connection widget URL via API call](/connect-data-sources)

[^1]: Data sources like Fitbit, Garmin, Oura or Withings where a server-to-server connection is established

[^2]: Data sources like Apple Health, Health Connect, or Samsung Health where data is retrieved locally on the users device via the Thryve SDK.


# Access

We will make sure the latest health and activity data is available for your end-users at all times. And here's how you can access it!

When your user has connected their data source, we will immediately start retrieving your user's data, making sure you can start working with it within seconds of the data source connection.&#x20;

Thryve's data processing and storage engine will collect the data from all kinds of data sources, harmonize and normalize it according to the Thryve data type definitions and provision it to you via our API endpoints.

The subsequent pages will introduce you to all the types and dimensions available as well as give you an overview of when data will be available and how historic data (prior to user connection) can be retrieved and configured.

If you want to understand the technical implementation to access, you can directly jump into the following pages:

* [Receiving data updates via webhook notifications](/receive-updates-via-webhooks/notifications)


# Data Model

Your user's data is flowing in, and you want to build something awesome? Great! But first, you need to understand how we organize this data - picking the right approach will save you headaches later.

Thryve processes and stores wearable data using two primary temporal frameworks: **epoch data** and **daily data**. Understanding the distinction between these approaches is crucial for proper data interpretation and application development.

<table><thead><tr><th width="170.65234375">Aspect</th><th>Epoch Data</th><th>Daily Data</th></tr></thead><tbody><tr><td><sub><strong>Time Reference</strong></sub></td><td>Absolute timestamps or timeframes</td><td>Calendar date in user's local timezone</td></tr><tr><td><sub><strong>Precision</strong></sub></td><td>High (seconds)</td><td>Low (daily aggregates)</td></tr><tr><td><sub><strong>Data Volume</strong></sub></td><td>Up to hundreds of records per day per data source per data type</td><td>One value per data source per data type per day</td></tr><tr><td><sub><strong>Uniqueness</strong></sub></td><td><code>dataSourceId</code>, <code>thirdPartyDataSourceId</code>, <code>dataTypeId</code>, <code>startTimestamp</code>, <code>generationType</code></td><td><code>dataSourceId</code>, <code>dataTypeId</code>, <code>day</code></td></tr></tbody></table>

### Epoch data

**Epoch data** represents continuous, timestamped measurements collected at specific moments in time. This data maintains precise temporal accuracy and is ideal for detailed analysis of patterns, trends, and health and activity monitoring.

#### Key Characteristics

**Granularity**: Varies significantly based on data sources and devices used by the end user. Sensors in wearables typically record data at high sampling rates (50Hz and higher), which manufacturers transform into digestible values. The granularity of these processed values depends on the manufacturer's philosophy:

* **Withings**: Provides step data in chunks of a maximum 10 minutes (during walking periods)
* **Polar**: Aggregates data on an hourly level
* **Fitbit**: Only provides intraday data for sleep periods and workout recordings without [special access](https://dev.fitbit.com/build/reference/web-api/intraday/)

Granularity also depends on measurement context. Some data sources generate more granular data during workout recordings triggered by end users compared to passive measurements throughout the day.

{% hint style="success" %}
Thryve always stores data at the highest possible granularity and does not pre-aggregate epoch data.
{% endhint %}

**Temporal Precision**:

* For point-in-time measurements (e.g., weight, sometimes heart rate), only `startTimestamp` is provided
* For duration-based data (e.g., activity periods, avg heart rate over a period), both `startTimestamp` and `endTimestamp` are provided
* All timestamps maintain seconds-level precision

**Timestamp Formats**: Data is provided by Thryve in your preferred format:

* **ISO 8601** with timezone information (when available) and additional `timezoneOffset` in minutes to UTC - recommended for human-readable applications
* **Unix timestamp** in milliseconds (UTC) with `timezoneOffset` in minutes to UTC - recommended for programmatic processing

{% tabs %}
{% tab title="ISO 8601" %}

```json
{
  "startTimestamp": "2025-05-31T09:33:59+01:00",
  "endTimestamp": "2025-05-31T09:34:59+01:00",
  "timezoneOffset": 60,
  "dataTypeId": 0,
  "value": 0,
  "additionalDetails": {}
}
```

{% endtab %}

{% tab title="Unix timestamp in milliseconds" %}

```json
{
  "startTimestamp": 1748680439000,
  "endTimestamp": 1748680499000,
  "timezoneOffset": 60,
  "dataTypeId": 0,
  "value": 0,
  "additionalDetails": {}
}
```

{% endtab %}
{% endtabs %}

### Daily data

**Daily data** represents aggregated measurements organized by calendar days in the user's local timezone. This data is designed for simplified consumption and day-over-day comparisons.

#### Key Characteristics

**Enhanced data availability**: Daily aggregates provided directly by data sources may extend beyond available epoch data for a given user and data source. For example, Fitbit provides intraday data only when users actively trigger activity recording, while daily values include passive measurements throughout the entire day.

**Timezone Handling**:

* The `day` field represents a calendar date in the user's local timezone
* `timezoneOffset` provides the offset to UTC in minutes
* For users traveling across timezones within a single day, `timezoneOffset` reflects the timezone where more data was recorded

**Timestamp Formats**: Data is provided by Thryve in your preferred format:

* **ISO 8601 date**: Simple date string (YYYY-MM-DD) representing a calendar date in the user's local timezone - recommended for user interfaces
* **Unix timestamp**: Milliseconds midnight UTC for the date - recommended for calculations and storage

{% hint style="info" %}
`timezoneOffset` reflects the offsent in minutes to UTC timezone where data was recorded
{% endhint %}

**Timezone Travel Detection**: When users cross timezones during a calendar day, the actual duration of their "day" may not be exactly 24 hours. The `chronologicalExactness` field captures this deviation in minutes:

* **Positive values**: Day was longer than 24 hours (e.g., +60 minutes when traveling westward and "gaining" an hour)
* **Negative values**: Day was shorter than 24 hours (e.g., -60 minutes when traveling eastward and "losing" an hour)
* **Null**: Standard 24-hour day with no significant timezone changes

For values that are not exactly 24 hours, `timezoneOffset` reflects the timezone where more data was recorded.

{% hint style="info" %}
Timezone Travel Detection logic only applies when data is aggregated and calculated by Thryve, not when daily data is directly provided by the data source.
{% endhint %}

**Smart Overlap Detection**: When daily data is calculated and aggregated by Thryve, intelligent mechanisms prevent value inflation through smart overlap detection within the same data type and data source. This ensures accurate aggregation when data is recorded simultaneously by multiple devices (e.g., both smartphone and fitness tracker), preventing double-counting of activities like steps or calories.

{% hint style="info" %}
Smart Overlap Detection logic only applies when data is aggregated and calculated by Thryve, not when daily data is directly provided by the data source. Data sources may use similar logics, however, no official documentation on how aggregates are created is available.
{% endhint %}

{% tabs %}
{% tab title="ISO 8601" %}

```json
{
    "day": "2025-05-31",
    "timezoneOffset": 60,
    "dataTypeId": 0,
    "value": 0,
    "additionalDetails": {}
}
```

{% endtab %}

{% tab title="Unix timestamp in milliseconds" %}

```json
{
    "day": 1748642400000,
    "timezoneOffset": 60,
    "dataTypeId": 0,
    "value": 0,
    "additionalDetails": {}
}
```

{% endtab %}
{% endtabs %}

### When to Use Each

#### Choose Epoch Data When:

* Building detailed health and activity dashboards or monitoring systems
* Requiring intraday breakdowns for comprehensive health and activity assessment
* Performing detailed temporal analysis or pattern recognition
* Analyzing user behavior patterns throughout specific time periods
* Correlating data across different timezones

#### Choose Daily Data When:

* Creating simple user-facing summaries and progress reports
* Building day-over-day comparison features
* Generating weekly or monthly trend reports
* Minimizing data processing complexity
* Reducing bandwidth requirements for mobile applications

### Implementation Considerations

**Data Volume**: Epoch data can generate hundreds of records per day per data type, while daily data provides one consolidated value. Plan storage and bandwidth accordingly.

**Timezone Complexity**: Daily data simplifies timezone handling for basic use cases, while epoch data provides maximum flexibility for complex temporal analysis.


# Data Types (Biomarker)

We've got 250+ data types covering everything from basic steps to advanced cardiac analysis. Here's your complete guide to building amazing health experiences.

Thryve supports a comprehensive range of health and fitness data types, each designed to enable specific product experiences and use cases. You can access the full list [here](https://airtable.com/appUsNn6CVszlBjfw/shroLjZ7pigt4oV7j).

{% hint style="info" %}
Data type availability varies significantly across data sources. Not every wearable or health platform supports all data types. Always check the availability matrix to understand which data sources provide the specific metrics you need for your product.
{% endhint %}

{% embed url="<https://airtable.com/appUsNn6CVszlBjfw/shroLjZ7pigt4oV7j>" %}

## Data type categories

Our data types are organized into 18 categories designed around product use cases and user experiences:

### Body Composition & Measurements

Foundation metrics for health tracking apps, weight management platforms, and fitness progress monitoring. Includes weight, height, BMI, muscle mass, bone mass, and body fat measurements.

**Key Use Cases**: Weight loss apps, fitness progress tracking, health monitoring dashboards, body composition analysis tools.

### Activity

Daily movement and general activity metrics for lifestyle and wellness applications. Covers steps, calories burned, active duration, distance covered, and general activity tracking.

**Key Use Cases**: Daily wellness apps, step challenges, lifestyle coaching platforms, general fitness tracking.

### Workouts

Exercise-specific performance metrics for fitness and training applications. Includes pace, speed, training intensities, sport-specific metrics, and cycling performance data.

**Key Use Cases**: Fitness training apps, running coaches, cycling platforms, sports performance analysis, workout tracking.

### Heart Rate

Basic cardiovascular monitoring for health and fitness applications. Covers resting heart rate, average heart rate, sleep heart rate, and heart rate zones.

**Key Use Cases**: Fitness apps, health monitoring, workout intensity tracking, general cardiovascular health awareness.

### Sleep

Comprehensive sleep tracking for wellness and health optimization apps. Includes sleep duration, sleep stages, sleep quality metrics, and sleep-related measurements.

**Key Use Cases**: Sleep optimization apps, wellness platforms, health coaching, circadian rhythm tracking, sleep disorder monitoring.

### Stress & HRV

Stress monitoring and heart rate variability for mental health and recovery applications. Combines stress indicators with HRV metrics that reflect autonomic nervous system activity.

**Key Use Cases**: Stress management apps, mental health platforms, recovery optimization, meditation apps, wellness coaching.

### Cardiovascular Health

Advanced cardiovascular metrics for medical and serious health monitoring applications. Includes blood pressure measurements, arterial pressure, and pulse wave velocity.

**Key Use Cases**: Medical monitoring apps, hypertension management, cardiovascular health platforms, clinical health tracking.

### Advanced Cardiac Analysis

Sophisticated cardiac monitoring for medical and research applications. Includes ECG data, arrhythmia detection, and advanced cardiac health indicators.

**Key Use Cases**: Medical monitoring platforms, cardiac health apps, research applications, clinical-grade health tracking.

### Blood Glucose

Blood sugar monitoring for diabetes management and metabolic health. Includes actual and estimated glucose measurements.

**Key Use Cases**: Diabetes management apps, metabolic health platforms, medical monitoring tools, health coaching for pre-diabetes.

### Respiratory & Breathing

Breathing and respiratory health metrics for wellness and medical applications. Includes respiratory rate, breathing patterns, and blood oxygen saturation.

**Key Use Cases**: Wellness apps, meditation platforms, respiratory health monitoring, fitness recovery tracking.

### Movement Analysis

Advanced biomechanical metrics for serious athletes and movement optimization. Includes stride length, ground contact time, vertical oscillation, and gait analysis.

**Key Use Cases**: Running performance apps, injury prevention platforms, athletic coaching tools, biomechanical analysis.

### Detailed Nutrition

Comprehensive nutritional tracking for diet and health management. Covers macronutrients, micronutrients, vitamins, minerals, and detailed dietary intake.

**Key Use Cases**: Nutrition tracking apps, diet management platforms, health optimization tools, medical nutrition monitoring.

### Audio & Hearing Health

Hearing protection and audio exposure monitoring. Tracks audio exposure levels for hearing health awareness.

**Key Use Cases**: Hearing protection apps, audio exposure monitoring, occupational health tools, hearing wellness platforms.

### Location & GPS

Geographic data for activity context and location-based health insights. Includes latitude, longitude, and location-specific measurements.

**Key Use Cases**: Activity mapping, location-based health insights, outdoor fitness tracking, geographic health analysis.

## Choosing the Right Data Types

#### For General Wellness Apps

Focus on **Activity**, **Sleep and** **Heart Rate** categories. These provide comprehensive lifestyle tracking without overwhelming users with complex metrics.

#### for Fitness and Training Apps

Prioritize **Activity**, **Workouts**, **Heart Rate**, and **Movement Analysis**. Add **Sleep** and **Stress & HRV** for recovery optimization features.

#### For Health Monitoring Platforms

Emphasize **Body Composition**, **Cardiovascular Health**, **Blood Glucose**, and **Advanced Cardiac Analysis** for comprehensive health tracking.

#### For Specialized Applications

Utilize **Advanced Cardiac Analysis**, **Blood Glucose**, **Cardiovascular Health**, and **Respiratory & Breathing**


# Data Type Structure

Each data type in Thryve has several key attributes:

* **Data Type ID**: Unique identifier used in API calls
* **Name**: Human-readable name of the metric
* **Description**: Detailed explanation of what the data represents
* **Value Type**: Technical data format (LONG, DOUBLE, BOOLEAN, STRING, JSON, DATE, Binary, FLOAT)
* **Unit**: Measurement unit (e.g., steps, bpm, kilograms, minutes)
* **Temporal Availability**: Whether available as Daily data, Intraday data, or both

### Value Types Explained

| Value Type | Description       |
| ---------- | ----------------- |
| LONG       | Whole numbers     |
| DOUBLE     | Decimal numbers   |
| BOOLEAN    | True/false values |
| STRING     | Text values       |
| DATE       | Date/time values  |

### Temporal Data Availability

Most data types are available in both Daily and Intraday formats, though some are only available in one format, depending on how the source device collects the data. For detailed information about the difference between Daily and Intraday data, see our [Data Model](/thryve-product-overview/access/data-model) documentation.


# Activity Types

{% embed url="<https://airtable.com/app7DudCExMcY22NR/shrEePlBTAVx5HHAW>" %}


# Data Availability

Your user has connected their data source and now? Simple: We'll get all data you need asap and all data updates in near-time. However, there are some limiting factors you need to be aware of.

At Thryve, we retrieve all data made available by the data sources. While we optimize to get data as fast as possible, there are still cases where data seems missing. There are many factors that can cause this, so we've grouped the most prominent factors affecting data availability:

### Device and Sync Factors

#### Data Has Not Arrived at the Data Source

We cannot access data from a data source if it hasn't arrived yet. Most users record data with wearable sensors (e.g., Apple Watch), but these devices rarely stream data in real-time. Instead, data is synced in batches with smartphones, creating delays between recording and availability.

**Common sync delay factors:**

* **Bluetooth connectivity**: Users turning off Bluetooth or moving out of range
* **Operating system optimizations**: Energy-saving mechanisms and background process termination
* **Network connectivity**: For web data sources, data must reach the cloud before we can retrieve it

**Important note**: For web data sources, data can only be retrieved once it reaches the data source's cloud. Data being visible in a smartphone app doesn't guarantee it has synced to the cloud yet.

#### Device Capabilities

Not all devices within a data source ecosystem can record all data types. Older devices may lack certain sensors (e.g., SpO2 measurement capability) even though these data types are listed in our data source overview. Some measurements may also be limited to specific geographic regions due to regulatory requirements.

### User Behavior Factors

#### End-User Activity in Your App

For native data sources, the Thryve SDK synchronizes data through your app on the user's device. This process depends heavily on the operating system, allowing synchronization, especially in the background.

When users don't regularly use your app, the operating system may:

* Reduce background data retrieval frequency
* Completely terminate background processes when prioritizing more frequently used apps

Regular app usage helps maintain consistent data synchronization.

#### End-User Activity in Data Source Apps

For web data sources, users must actively use the manufacturer's apps (e.g., Fitbit, Garmin Connect, Polar Flow) to ensure proper data flow. When users don't regularly open these apps, two critical sync processes are affected:

* **Device-to-app sync**: Data remains on the wearable device and doesn't transfer to the smartphone app
* **App-to-cloud upload**: Data stays locally in the app and doesn't reach the manufacturer's cloud servers

Since Thryve can only access data once it reaches the manufacturer's cloud, inactive users may experience significant data gaps even if their devices are recording properly.

### System and API Limitations

#### API Data Availability Restrictions

Unfortunately, not all data visible in smartphone apps is made available to third parties through APIs. Data source manufacturers may restrict:

* **Specific data granularities**: Some data types are only available at the daily level without intraday breakdowns.
* **Certain data types**: Complete categories of data may be unavailable to third parties, this is specifically referring to scores and more complex assessments done by wearable devices.

{% hint style="warning" %}
Please note that certain data sources, like Fitbit or Polar, have limitations on the data available via API. Please check the dedicated data source pages for further information.
{% endhint %}

### Best Practices for Data Availability

**For Developers:**

* Implement graceful handling of missing data periods
* Don't assume real-time data availability
* Consider data source-specific limitations when building features

**For End Users:**

* Encourage regular app usage to maintain background sync
* Ensure devices stay connected and charged
* Keep data source apps updated for optimal sync performance


# Understand

Accessing data is just the start. True value lies in effectively analyzing and interpreting it to create exceptional experiences.

In data analysis, understanding two key aspects is crucial for effective data management:

* **The context of data recording:** How was the data collected? Understanding this helps in assessing its accuracy and relevance.
* **Interpreting data for insights:** What does the data mean? Analyzing data meaningfully to gain actionable insights is vital.

Knowing the creation process enhances data accuracy assessment. Therefore, we provide standardized annotations about measurement context when available. Explore our [data annotations](/thryve-product-overview/understand/data-annotations) for further context.

[Thryve Analytics Platforms](/thryve-analytics-platform/overview) excel in turning raw data into clear interpretations. Rooted in scientific evidence, our calculations guide organizations toward informed decision-making.&#x20;


# Data annotations

Context matters. How was data recorded? What sensor captured it? In which timezone? Was it manually entered or automatically detected? We provide all annotations so you can make informed decisions

Data annotations provide crucial metadata that helps you understand the context and quality of wearable data. These annotations appear in the `additionalDetails` object of epoch and daily, and can significantly impact how you interpret and use the data in your applications.

{% hint style="info" %}
Not all data sources provide every type of annotation. The availability of specific annotations depends on the capabilities and policies of each data source manufacturer.
{% endhint %}

### Timezone UTC Offset

When available, we store and provide the offset to UTC as an integer representing minutes.

**Key**: `timezoneOffset`\
**Type**: Integer (minutes to UTC)\
**Availability**: When timezone information is available from the data source

```json
{
    "startTimestamp": "2025-05-31T11:11:13+06:00",
    "endTimestamp": "2025-05-31T11:11:13+06:00",
    "timezoneOffset": 240,
    "dataTypeId": 0,
    "value": 0,
    "additionalDetails": {}
}
```

**Example**: A value of `240` means the data was recorded in a timezone that is UTC+4 (240 minutes ahead of UTC).

### Generation

When available, we annotate data with information about how it was generated, allowing you to assess data quality and decide whether to rely on it for specific use cases.

**Key**: `generation`\
**Type**: String\
**Availability**: When generation information is directly provided by the data source

<pre class="language-json"><code class="lang-json"><strong>"additionalDetails": {
</strong><strong>    "generation": "smartphone"
</strong>}
</code></pre>

<table><thead><tr><th width="251">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>"manual_entry"</code></td><td>Data was manually entered by a user</td></tr><tr><td><code>"manual_measurement"</code></td><td>Data was recorded by a sensor measurement manually triggered by a user</td></tr><tr><td><code>"automated_measurement"</code></td><td>Data was recorded by a passive sensor measurement</td></tr><tr><td><code>"smartphone"</code></td><td>Data was recorded by a smartphone sensor</td></tr><tr><td><code>"tracker"</code></td><td>Data was recorded by a wearable sensor or medical device</td></tr><tr><td><code>"third_party"</code></td><td>Data was recorded by a third-party app</td></tr><tr><td><code>"calculation"</code></td><td>Data was calculated by Thryve (e.g., daily steps if not provided by manufacturer)</td></tr></tbody></table>

### Medical Grade Certification

When we know a data point was recorded by a device certified by the FDA or equivalent regulatory agency, we annotate the data accordingly.

**Key**: `medicalGrade`\
**Type**: Boolean\
**Availability**: When device certification status is known

```json
"additionalDetails": {
    "medicalGrade": true
}
```

<table><thead><tr><th width="142">Value</th><th>Description</th></tr></thead><tbody><tr><td>True</td><td>Data was recorded by a sensor that can be considered medical/clinical grade</td></tr><tr><td>False</td><td>Data was recorded by a sensor with no clinical validation</td></tr></tbody></table>

### Trustworthiness Assessment

Some data sources like Garmin or Withings evaluate the reliability of measurements based on their algorithms and user feedback. We pass through these assessments to help you evaluate data quality.

**Key**: `trustworthiness`\
**Type**: String\
**Availability**: Only from data sources that provide trustworthiness assessments

```json
"additionalDetails": {
    "trustworthiness": "doubt_from_user"
}
```

| Parameter                           | Description                                                                                                                       |
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `"unfavorable_measurement_context"` | Device manufacturer believes recording was made under suboptimal conditions (e.g., during movement when stillness is recommended) |
| `"doubt_from_device_source"`        | Device algorithms flagged the measurement as potentially unreliable                                                               |
| `"doubt_from_user"`                 | User manually tagged the recording as unlikely or implausible                                                                     |
| `"verified_from_device_source"`     | Device manufacturer considers the recording plausible and reliable                                                                |
| `"verified_from_user"`              | User manually verified the recording as accurate                                                                                  |

### **Chronological exactness**

This annotation indicates potential deviations from precise timestamps, measured in minutes.

**Key**: `chronologicalExactness`\
**Type**: Integer (minutes of potential deviation)\
**Availability**: When timestamp precision is uncertain

#### For Daily Data

For daily data, this annotation appears when users have started and ended their day in different timezones, making their "day" shorter or longer than 24 hours. We provide this deviation in minutes when we calculate daily data ourselves through our analytics.

```json
"additionalDetails": {
    "chronologicalExactness": 120
}
```

**Example**: A value of `120` means the day has been 2 hours longer than a normal 24h long day.

### Using Annotations in Your Application

#### Data Quality Assessment

Use generation and trustworthiness annotations to implement data quality filters:

* Prioritize `"automated_measurement"` over `"manual_entry"` for passive tracking
* Consider excluding data marked with `"doubt_from_device_source"` for critical health applications
* Use `medicalGrade: true` data for clinical or medical use cases

#### Timezone Handling

Always consider `timezoneOffset` when:

* Displaying data to users in their local timezone
* Correlating data across different time periods
* Analyzing patterns that depend on local time (sleep, meal times, etc.)

#### Timestamp Reliability

Factor in `chronologicalExactness` when:

* Correlating data from multiple sources
* Analyzing time-sensitive patterns
* Building features that require precise timing

#### Example Implementation

```json
{
  "startTimestamp": "2025-05-31T14:20:00-08:00",
  "endTimestamp": "2025-05-31T14:30:00-08:00",
  "timezoneOffset": -480,
  "dataTypeId": 1000,
  "value": 72,
  "additionalDetails": {
    "generation": "automated_measurement",
    "medicalGrade": false,
    "trustworthiness": "verified_from_device_source",
    "chronologicalExactness": 0
  }
}
```

This data point represents a heart rate measurement that was automatically recorded by a non-medical device in Pacific Standard Time, verified as reliable by the device, with precise timestamps.


# Visualize (Beta)

We have built ready-made, embeddable charts you can use to display your users' health data directly in your mobile/web app. All through a simple API call.

The Thryve Visualization Widget renders health data statistics and insights directly within your application based on pre-defined visualization templates. Request the visualisation specific to your user via a simple API call and embed the returned widget URL into your application.

{% columns %}
{% column width="50%" %}

<figure><img src="/files/sqFUGwIMRU8xmZJS8wIf" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="50%" %}

<figure><img src="/files/2bfmy6gzlwhMqhE5gdeT" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Supported locales

Text displayed on the widget is available in multiple languages. Currently, the following ISO-639 locales are supported:

`ar`, `bg`, `cs`, `da`, `de`, `el`, `en`, `es`, `et`, `fi`, `fr`, `hu`, `id`, `it`, `ja`, `ko`, `lt`, `lv`, `nl`, `pl`, `pt`, `ro`, `ru`, `sk`, `sl`, `sv`, `tr`, `uk`

## Visualization Widget Templates

{% hint style="info" %}
Visualization widgets are in **beta**, and we're planning to add more templates over time. If you have any specific requests for new templates or feedback on existing templates, please reach out to our product team via the support center.
{% endhint %}

### Daily Totals Template

Visualizes a single daily aggregate data type over a configurable timeframe in a single template. The template supports data types showing a daily sum, like Steps, Calories Burned, Distances, and Durations. Note that the underlying data can come from multiple sources.

{% columns %}
{% column %}

<figure><img src="/files/kiDL48RBPG2Owh1ayMd1" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}

<figure><img src="/files/33Xv5X9Ofb268BMXfrQf" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Supported data types

| ID     | Metric            |
| ------ | ----------------- |
| `1000` | Steps             |
| `1001` | Covered Distance  |
| `1010` | Burned Calories   |
| `1100` | Activity Duration |
| `1113` | Rest Duration     |
| `1114` | Active Duration   |
| `1115` | Walk Duration     |
| `1715` | Walk Distance     |
| `2000` | Sleep Duration    |

#### Optional Parameters

<table><thead><tr><th width="226.45831298828125">Config field</th><th>Description</th></tr></thead><tbody><tr><td><code>timeframe</code></td><td>Number of days to display. Defaults to <code>30</code>.</td></tr><tr><td><code>dataTypeId</code></td><td>The daily data type to plot. Defaults to <code>dataTypeId=1000</code> (Steps).</td></tr><tr><td><code>referenceDate</code></td><td>The visualization timeframe is calculated backwards from this day. Expects <code>YYYY-MM-DD</code> format. Defaults to today (the user's local date).</td></tr></tbody></table>

### Social Jet Lag Template

Visualizes the misalignment of your users' internal body clock on workdays and free days (e.g. weekends) by comparing the sleep midpoints and durations of those two groups. Data types SleepStartTime (2100) and SleepEndTime (2101) are used as inputs by the widget for this visualization.

<figure><img src="/files/aXhy60h2uArfwmZ3RPDx" alt="" width="349"><figcaption><p>Social Jetlag Template</p></figcaption></figure>

{% hint style="info" %}
The template requires sleep data for a minimum of 10 workdays and 4 holidays to calculate and visualize the Social Jet Lag. If the data threshold is not met, the widget will indicate to the user that more data is required.
{% endhint %}

#### Optional Parameters

| Optional Config field | Description                                                                                                                                                          |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `timeframe`           | <p>Number of days to visualize. Defaults to <code>28</code>.<br>For example, if <code>timeframe = 60</code>, data across { Today - 60 days } will be visualized.</p> |
| `workdays`            | Defaults to `["monday", "tuesday", "wednesday", "thursday", "friday"]`.                                                                                              |
| `holidays`            | Defaults to `["saturday", "sunday"]`.                                                                                                                                |

{% hint style="info" %}
The widget auto-sizes its content vertically. If embedded in a scrollable container, listen for the height messages the widget posts to the parent window and resize the iframe accordingly.
{% endhint %}


# Control

Health data is sensitive, health data requires care. Therefore we have built the tools so that you are in full control over what kinds of data is stored and processed.

### Enabled data sources

Configure the data sources you want your users to connect to.&#x20;

#### Configure data source scopes

Limit the data your users need to grant access to to the minimum you need for your use case. When bringing your own oAuth credentials, decide for your app which data will be requested when users grant permissions.

### Allowed health data types

To minimize processed data and really just store what data is required for your product, you can granularly define the data types we will store for your end users by data type. Only need Steps? Then that’s what we will store even when data sources send us more then just that.

### Historic data

As for allowed data sources, you can also control the storage of historic data. We consider historic data as data prior to the creation date of the Thryve user. By default, we allow for the retrieval of 14 days of historic data. When set to 0, only data from the user creation date onwards will be stored.&#x20;


# Overview

You can find our claims of providing you access to more than 500+ wearables and health apps all over our website and texts. What does that mean? Find out here!

If you have made it to this page, you probably have already heard that Thryve allows developers like you to connect to all kinds of smartwatches, health trackers, consumer sensors, but also health data created from smartphones and other health apps.

<figure><img src="/files/JGhcsTMHN0B0mKVgyJ37" alt="" width="188"><figcaption><p>Thryve Connection Widget displaying selected data sources</p></figcaption></figure>

You can find the full list of actively supported and maintained data sources that your users can connect to. But make sure to scroll past the table, as we will explain some key concepts when it comes to consumer health data sources.

<table data-full-width="true"><thead><tr><th width="82">ID</th><th width="208">Data Source</th><th width="107">Type</th><th width="140.11279296875">Retrieval Method</th><th width="164">Historic data</th><th>Shared oAuth-client</th></tr></thead><tbody><tr><td>1</td><td>Fitbit</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>2</td><td>Garmin</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>3</td><td>Polar</td><td>Web</td><td>Ping</td><td>no</td><td>yes</td></tr><tr><td>5</td><td>Apple Health</td><td>Native</td><td>SDK</td><td>yes</td><td>n.a.</td></tr><tr><td>6</td><td>Samsung Health</td><td>Native</td><td>SDK</td><td>yes</td><td><a data-footnote-ref href="#user-content-fn-1">n.a.</a></td></tr><tr><td>8</td><td>Withings</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>11</td><td>Strava</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>12</td><td>GoogleFitREST <a data-footnote-ref href="#user-content-fn-2"><em>(EOL)</em></a></td><td>Web</td><td>Bulk</td><td>yes</td><td>no</td></tr><tr><td>16</td><td>Omron Connect</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>17</td><td>Suunto</td><td>Web</td><td>Bulk</td><td>yes</td><td>yes</td></tr><tr><td>18</td><td>Oura</td><td>Web</td><td>Ping</td><td>yes</td><td>yes</td></tr><tr><td>21</td><td>iHealth</td><td>Web</td><td>Ping</td><td>yes</td><td>no</td></tr><tr><td>27</td><td>Beurer</td><td>Web</td><td>Bulk</td><td>yes</td><td>yes</td></tr><tr><td>38</td><td>HuaweiHealth</td><td>Web</td><td>Bulk</td><td><a data-footnote-ref href="#user-content-fn-3">yes</a></td><td>yes</td></tr><tr><td>40</td><td>GoogleFitNative <em>(</em><a data-footnote-ref href="#user-content-fn-2"><em>EOL</em></a><em>)</em></td><td>Native</td><td>SDK</td><td>yes</td><td>no</td></tr><tr><td>41</td><td>Dexcom</td><td>Web</td><td>Bulk</td><td>yes</td><td>no</td></tr><tr><td>42</td><td>Whoop</td><td>Web</td><td>Ping</td><td>yes</td><td>no</td></tr><tr><td>43</td><td>Decathlon</td><td>Web</td><td>Ping</td><td>yes</td><td>no</td></tr><tr><td>44</td><td>Health Connect</td><td>Native</td><td>SDK</td><td><a data-footnote-ref href="#user-content-fn-4">yes</a></td><td>n.a.</td></tr><tr><td>45</td><td>Komoot</td><td>Web</td><td>Bulk</td><td>yes</td><td>no</td></tr><tr><td>46</td><td>FreeStyleLibre (LibreView)</td><td>Web</td><td>Bulk</td><td>yes</td><td>no</td></tr><tr><td>47</td><td>ShenAI</td><td>Native</td><td>SDK</td><td>n.a.</td><td>no</td></tr><tr><td>48</td><td>Garmin Companion<br>(Coming soon)</td><td>Native</td><td>SDK</td><td>n.a</td><td>no</td></tr><tr><td>49</td><td>Google Health<br>(Coming soon)</td><td>Web</td><td>Bulk</td><td>yes</td><td>no</td></tr></tbody></table>

{% hint style="warning" %}
When no shared oAuth-client is available, you must bring your own oAuth-client (*clientId*, *clientSecret*) or API keys to enable the data source
{% endhint %}

You can access an overview of what data is provided by the different data sources [here](/thryve-product-overview/access/data-types-biomarker).

[^1]: Requires [verification](https://developer.samsung.com/health/data/process.html#Partner-App-Program) by Samsung for production use

[^2]: As of May 1, 2024, new apps cannot sign up to use these APIs. Existing integrations will continue to work till 2026.

[^3]: Only possible if historic data access is allowed by Huawei for own oAuth-client

[^4]: Timeframes extending 30 days prior to user connection require user granting dedicated permission for historic data retrieval.


# Shared & custom oAuth-clients

When your users connect their web data sources they will by default connect with the shared "Thryve app" (oAuth-client). This way you can start immediately letting your users connect without the need to go through tedious approval processes to obtain your own oAuth-client with each web data source provider which may take weeks.

<figure><img src="/files/m7Ntfs8IvwwNL7ZQgu7J" alt="" width="188"><figcaption><p>Example of connecting Withings via shared Thryve oAuth-client.</p></figcaption></figure>

While your users connect to the Thryve oAuth-client you still have full control over your users and their data, as well as the kind of data stored, as we're acting as a data processor on your behalf.&#x20;

When using the shared OAuth clients provided by Thryve, users will be asked to grant access to all data scopes.

#### **Bring your own oAuth-client for custom authorization configurations**

We allow our customers to bring their own oAuth-client configuration for web data sources. This way you will be able to configure more granularly which data scopes will be requested from your users as well as be in full control over what information is displayed to your users during the authorization process.

<figure><img src="/files/lvAWrAHVxtaf7XyHa27b" alt="" width="188"><figcaption><p>Example of connecting Withings to own oAuth-client with full control of displayed logo and text.</p></figcaption></figure>

The advantages of bringing your own oAuth-clients are:

* Ownership and control over the data source developer/app accounts (e.g., Fitbit, Garmin)
* Custom branding on OAuth consent screens (domain, name, logo)
* Access to data sources that are not available via Thryve's shared oAuth-clients
* API rate limits are tied to the customer’s own developer account, not shared with others
* Improved user trust and brand consistency - users see the customer’s identity, not Thryve’s

#### Create your own oAuth-client

You can create and configure your own oAuth-client through the developer portals or support channels provided by each data source (e.g., Fitbit, Garmin). During this setup, it is essential to specify URLs for redirection and pinging as provided by Thryve to ensure seamless integration with Thryve.&#x20;

To assist you in this process, we offer a series of guides detailing the configuration steps for various data sources:

* [Create your own oAuth-client for Fitbit](/thryve-data-sources/fitbit#create-your-own-oauth-client-for-fitbit)

{% hint style="info" %}
Please reach out to our support team to receive the correct URLs ({{appName}}.und-gesund.de) for redirection and ping configuration
{% endhint %}

### A note on data scopes

When requesting authorization, certain data scopes are requested from the end users. Data scopes are broad categories of data that the user will grant access to. Scopes can be e.g. "Activity", "Sleep", or "Profile", which each enable access to different kinds of data.

For some data sources, users need to actively confirm access to individual scopes or can narrow down and proceed without granting access to all data. When access is not granted to a given scope, Thryve won't be able to retrieve this data for the specific user.&#x20;

<figure><img src="/files/S85ir9ligQBZgaM7W32b" alt="" width="188"><figcaption><p>Data scope selection when authorizing Fitbit.</p></figcaption></figure>

Therefore, we advise explaining to end users what data scopes will be requested as well as the purpose of the requested data. Ensure users understand that their experience with your app will be affected if not all data scopes as data might be missing.


# Data source types & retrieval methods

When working with consumer health sensors and sources like smartwatches, smart scales, connected medical devices, etc., there are three main concepts of data sources that are important to understand:

### Web data sources

Data sources storing health data in the cloud, like Fitbit, Garmin, or Withings, are called web data sources or oAuth data sources (due to the authorization protocol oAuth used by these sources). Data from web data sources is retrieved and flows between the data sources’ server to Thryve’s server.

Web data sources allow for data retrieval to happen fully in the background without the user needing to open your app. This means that when the user is wearing their wearable and data has been synced between the wearable and the data source cloud, it can be accessed by Thryve (given that a valid authorization exists).

### Native data sources

Data sources storing health data exclusively on the end-user's smartphone, like Apple Health and Health Connect, are called native data sources. The authorization, as well as the data retrieval, is happening on the smartphone of the end user.&#x20;

Native data sources are only available for mobile applications. The Thryve SDK will take care of all things authorization and data retrieval for you so that accessing data from these data sources won't require any huge implementations when using our technology.

Within the SDK, we have implemented certain mechanisms allowing for background data retrieval; however, these mechanisms are always a bit at the mercy of the operating system and might not work if the end user does not open your app regularly.

### Web-Direct data sources

Web-direct data sources are a sub-category of web data sources. These are data sources that don't have an official API to access data; however, we have built integrations allowing you to still get the data your end-users see in the data source app.

When authorizing web-direct data sources, your users will need to provide their username and password. We use these, however, only to obtain authorization for the sources and don't store them.

While we don't use any official API, legally, Thryve acts as a vicarious agent on your behalf/on behalf of your end user when accessing data from web-direct sources - this requires corresponding transparency in the service terms & conditions as well as the privacy guidelines of your application.&#x20;

## Data retrieval methods

The availability of data depends on how Thryve can retrieve data from the different data sources. To give you more context, we have grouped all data sources into one of these 3 categories:

### Ping-based data retrieval

Data is retrieved when we have received a notification from data sources about the availability of new data - basically, when they have "pinged" us. Typically, we subscribe to these kinds of notifications from data sources in this way, we ensure to retrieve data in near-real-time, as we take on average 1s from the ping notification until the data has been retrieved, stored, and made available on our side.

However, we know that certain data source providers are not always super reliable when it comes to notifications on new data, which is why we have mechanisms in place that ensure that data will still be retrieved even if a data source might have missed notifying us.

Historic data retrievals is independent of the ping notifications and performed upon user creation as well as when requested.

### Bulk data retrieval

Not all data sources have mechanisms that notify us when new data is available. For those data sources, we request new data for all users on a schedule with an interval of a maximum of 15 minutes. We have mechanisms in place to ensure all data is retrieved even for users who might not have synced their devices for multiple days.

### SDK-based data retrieval

Data retrieval for native data sources is performed via the Thryve SDK. The SDK will request data locally on your end-users' smartphones and send it to the Thryve backend. This can be triggered by your app via manual data synchronization routines of the Thryve SDK, e.g., when your app is moving to foreground or by a silent push notification system.

The Thryve SDK will also retrieve data in the background. On iOS, we use the routines provided by the operating system and HealthKit, while for the native data sources on the Android platform, we have implemented background workers that will request background workers to retrieve data at a scheduled interval every 30 minutes.

As the ability to perform the data retrieval is linked to the background workers on the Android platform, factors like resource optimizations and energy-saving mechanisms of the individual devices have a strong effect on how often the sync actually succeeds.


# Samsung Health

With Thryve you can easily integrate your application with Samsung Health. Thryve enables integration via the [new Samsung Health Data for Android](https://developer.samsung.com/health/data/overview.html) with SDK 5.2.0 onwards.

{% hint style="info" %}
To access data from Samsung Health using the `ThryveSamsungHealth` module, register your application with the Samsung Partner App Program. The Thryve SDK includes all necessary Samsung SDKs, eliminating the need for additional logic. Ensure your application ID is approved by Samsung for Samsung Health access. For more details, visit the [Samsung developer website](https://developer.samsung.com/health/android).
{% endhint %}

<figure><img src="/files/dPrSOMUln6Yqped3fArc" alt="" width="188"><figcaption></figcaption></figure>

### Data availability

#### Manually entered data

Data manually input by users into Samsung Health, such as Blood Pressure and Exercise, is no longer marked with the `"manual_entry"` [annotation](/thryve-product-overview/understand/data-annotations), as Samsung has removed this feature.

### Migration Guide

{% hint style="danger" %}
This section is relevant if you have used the Thryve Samsung Health module with Thryve SDK 5.1.2 or prior. If you are starting to integrate Samsung Health from scratch, please refer to the general integrate your mobile app section to understand how to [Setup the Thryve SDK,](/integrate-your-mobile-app/setup-thryve-sdk) [Connect data sources](/integrate-your-mobile-app/connect-data-sources) and [specifically use Samsung Health](/integrate-your-mobile-app/apple-health-health-connect-and-samsung-health).
{% endhint %}

Samsung is deprecating its old implementation of the Samsung Health Module. We strongly advise migrating your user base to the updated module.

**Important Considerations:**

* **Re-Authentication Required:** Existing users must re-authenticate Samsung Health on their devices due to the new API foundation. Thryve SDK accounts for that and `isActive` for Samsung Health will return `false` if we have a previous connection stored in backend (e.g. for previous integration) but the user has not authorized any types with the new SDK.
* **No Native Migration Options:** Samsung is not offering direct migration paths for current users.
* **Samsung approval required:** To use the new Samsung Health module in production, [request a partnership migration](https://developer.samsung.com/enroll/partner/SHealth/m48wvqi1mt9w2w4c/business) through your existing Samsung Developer account.

{% hint style="danger" %}
When migrating from the legacy Samsung Health Android SDK to the Samsung Health Data SDK, all apps - including those that were previously approved - must go through a new partner approval process using your existing Samsung Developer account. Approvals granted for the legacy SDK do not transfer to the Data SDK.
{% endhint %}

Both the legacy (`shealth`) and the new (`samsung_health`) Samsung Health modules are available with the same model names but different package names: `com.thryve.sdk.samsungHealth` and `com.thryve.sdk.samsung.health`, respectively.

To complete the migration, developers only need to update the imports of `ThryveSamsungHealthConfig` and `ThryveSamsungHealthDataType` to the new package, `com.thryve.sdk.samsung.health`.

{% hint style="warning" %}
Thryve SDK support for the old Samsung Health SDK for Android (`shealth`)has been deprecated as of 16th April, 2026. While Thryve SDK 5.2.0 still supports the Samsung Health SDK for Android via the module `shealth` the old implementation will be completely removed with Thryve SDK 5.3.0.
{% endhint %}

Follow these instructions to migrate from the deprecated old Thryve Samsung Health module to new Thryve Samsung Health module

#### **Step 1: Add the New Samsung Health Module Dependencies**

{% tabs %}
{% tab title="Thryve Maven Repo " %}

```groovy
dependencies {
    ...
    // new Samsung Health module dependency
    api("com.thryve.sdk:samsung_health:${thryve_sdk_version}")
    
    // old Samsung Health module dependency (we do not recommend to use this anymore)
    api("com.thryve.sdk:shealth:${thryve_sdk_version}")
}
```

{% endtab %}

{% tab title="AAR Libraries" %}

```groovy
dependencies {
    ...
    implementation(files("libs/thryve_module_samsung_health_${thryve_sdk_version}.aar")
    // dependency for compression
    implementation("com.github.luben:zstd-jni:$zstdVersion") {
         artifact { type = "aar" }
      }
    
    // dependency for new Samsung Data SDK 
    // skip this dependency if kotlin-parcelize is already added as a plugin(recommended)
    implementation ("org.jetbrains.kotlin:kotlin-parcelize-runtime:$kotlin")
    ...
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If you are currently using the **old Thryve Samsung Health SDK**, it is strongly recommended to **remove it before integrating the new Samsung Health module** to avoid conflicts and ensure a clean migration.
{% endhint %}

#### **Step 2: Use the New Configuration Model**

Replace all deprecated Samsung Health configuration classes. Use the new ThryveSamsungHealthConfig and ThryveSamsungHealthDataType

```kotlin
import com.thryve.sdk.samsung.health.model.ThryveSamsungHealthConfig
import com.thryve.sdk.samsung.health.model.ThryveSamsungHealthDataType

val samsungHealthConfig = ThryveSamsungHealthConfig(
    dataTypes = ThryveSamsungHealthDataType.entries.toList(),
    enableBackgroundSync = true
)
```

{% hint style="warning" %}
Ensure you have new Samsung module in build gradle as stated in Step 1 and use the right imports package `com.thryve.sdk.samsung.health` not the deprecated package `com.thryve.sdk.samsungHealth`
{% endhint %}

With the new module, Samsung has adapted their data type classification. Please check this table for changes:

| shealth (old module) dataTypes | samsung\_health (new module) dataTypes | Note                                                                               |
| ------------------------------ | -------------------------------------- | ---------------------------------------------------------------------------------- |
| Not available                  | `ACTIVITY_SUMMARY`                     | Daily Data on total active time, ActiveBurnedCalories, BurnedCalories and Distance |
| `BLOOD_GLUCOSE`                | `BLOOD_GLUCOSE`                        |                                                                                    |
| `HBA1C`                        | Not available                          |                                                                                    |
| `OXYGEN_SATURATION`            | `BLOOD_OXYGEN`                         |                                                                                    |
| `BLOOD_PRESSURE`               | `BLOOD_PRESSURE`                       |                                                                                    |
| `WEIGHT`                       | `BODY_COMPOSITION`                     |                                                                                    |
| `BODY_MUSCLE`                  | Not available                          | Data available as part of `BODY_COMPOSITION`                                       |
| `BODY_FAT`                     | Not available                          | Data available as part of `BODY_COMPOSITION`                                       |
| `WAIST_CIRCUMFERENCE`          | Not available                          |                                                                                    |
| `BODY_TEMPERATURE`             | `BODY_TEMPERATURE`                     |                                                                                    |
| `EXERCISE`                     | `EXERCISE`                             |                                                                                    |
| `FLOORS_CLIMBED`               | `FLOORS_CLIMBED`                       |                                                                                    |
| `HEART_RATE`                   | `HEART_RATE`                           |                                                                                    |
| Not available                  | `SKIN_TEMPERATURE`                     |                                                                                    |
| `SLEEP`                        | `SLEEP`                                |                                                                                    |
| `SLEEP_STAGE`                  | Not available                          | Sleep stage data is now available as part of `SLEEP` dataType                      |
| `STEP_DAILY_TREND`             | `STEPS`                                | Daily-data only                                                                    |
| `STEP_COUNT`                   | Not available                          | Intraday step data is not available anymore.                                       |
| `WATER_INTAKE`                 | `WATER_INTAKE`                         |                                                                                    |
| `HEIGHT`                       | `USER_PROFILE`                         |                                                                                    |

#### **Step 3: Provide Samsung Health Configuration to SDK**

Pass the `ThryveSamsungHealthConfig` instance created in the previous step to all instances where `ThryveSDKConfig` is initialized or updated.

```kotlin
val thryveSDKConfig = ThryveSDKConfig(
    authId = "ASSIGNED_AUTH_ID",
    authSecret = "ASSIGNED_AUTH_SECRET",
    endUserAlias = "XXXXXXXXXXX",
    endUserId = null, 
    locale = "de",
    samsungHealthConfig = samsungHealthConfig
    //Add any other configs like ThryveHealthConnectConfig, ThryveShenAIConfig, etc which you are using
)

val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context) { thryveResponse ->
       if(thryveResponse.successful){
           //ThyveSDK initialization processes completed successfully
       } else {
           // ThryveSDK initalization process failed. process the ThryveErrors for the specific reason.
           thryveResponse.errors.map { thryveError -> Logger.e(TAG){" getOrCreate ThryveError in onCreate function $thryveError"} }
       }
  }
 //Call updateSDKConfig only when you want to update the thryveSDKconfig
 thryveSDK?.updateSDKConfig(thryveSDKConfig)
```

#### Step 4: Re-authenticate User

Connect users to the new Samsung Health module by calling `thryveSDK.start()`

{% code overflow="wrap" %}

```kotlin
thryveSDK?.start(this, Source.SAMSUNG) { authorizeStartResponse ->
        Logger.i(TAG) { "Results for authorize and Start ${authorizeStartResponse.data}" }
    }
```

{% endcode %}


# Fitbit

Fitbit is a well-known brand that specializes in wearable technology designed to help users track various health and fitness metrics. Their product lineup includes a range of devices such as fitness trackers and smartwatches that can monitor heart rate, sleep patterns, step count, and more.&#x20;

## Data availability

Almost all epoch data from Fitbit is only provided when users actively record activities or during sleep periods. Daily data is always available.

**Special partnerships**: If you have a [special partnership with Fitbit](https://dev.fitbit.com/build/reference/web-api/intraday/), access to intraday data can be extended to include all intraday measurements. Thryve fully supports Fitbit's complete intraday data extension.

## Create your own oAuth-client for Fitbit

Follow these steps to create your dedicated Fitbit oAuth-client and integrate its credentials with our data source connection system seamlessly.

1. **Create a Fitbit account**

To create a Fitbit account, you first need to have a Google account. On the [Fitbit website](https://accounts.fitbit.com/signup), you can either log in with your existing Fitbit account (if you created one before Google acquired them) or choose the option to log in with Google. After the authorization, your Google account will be linked to a Fitbit account, which you can only log in to via your Google credentials. Use the same account to sign in to the [Fitbit developer dashboard](https://dev.fitbit.com/apps).

2. **Create an API application**

If you want to use the Fitbit API to pull data from your users, you'll need to register a new application under [Register an app](https://dev.fitbit.com/apps/new).

Enter the name of the application and a link to it, your website, privacy policy, and terms of service.

Choose 'server' application type and set the default access type to 'read only'

3. **Set Up the redirect URL**

Please enter the following redirect URL: `https://${appName}.und-gesund.de/dataSourcesSwitch.html`&#x20;

<figure><img src="/files/32doiYOV57JuBiefSQZe" alt=""><figcaption><p>Illustrative Example: Fields Completed So Far</p></figcaption></figure>

4. **Add a subscriber**

Click on "Add a subscriber"

<figure><img src="/files/lbybnHJglVZJX71PKxg2" alt=""><figcaption><p>Select "Add a subscriber"</p></figcaption></figure>

* Set it to default
* Enter the following endpoint URL: `https://${appName}.und-gesund.de/dynDataSourcePing/Fitbit`&#x20;
* Ensure the Type is set to 'JSON body'.
* Set Subscriber ID field to `${appName}`&#x20;

<figure><img src="/files/l4IYqQnk9195Nwmu7Rdo" alt=""><figcaption><p>Illustrative Example: Subscriber Setup</p></figcaption></figure>

5. **Share credentials with Thryve**&#x20;

After you have created your App, you will be provided with your:

* ClientID
* ClientSecret
* Subscriber verification code

Please encrypt these credentials using our [secret sharing service](https://secret.thryve.de/) and then [share](https://thryve.zendesk.com/hc/en-us/requests/new) the resulting link with our Customer Operations Team.

6. **Get confirmation from our Team**

Thryve will reach out to you to confirm that your credentials have been successfully integrated. Once they confirm, please click the “Verify Subscriber” button to enable ping messages.

<figure><img src="/files/D4A5062Yn6JUKbpCbpHb" alt=""><figcaption><p>Click on "Verify" to enable Ping messages</p></figcaption></figure>

{% hint style="info" %}
Please confirm that the 'Subscriber has not been successfully verified' message is replaced with a verification timestamp (e.g. 2025-04-07T10:20:44.000Z)."
{% endhint %}

{% hint style="info" %}
Understanding the `${appName}` Variable

In this guide, you'll see the placeholder `${appName}`. Whenever you encounter it, replace it with your actual partner name, exactly as it's registered in our system.<br>

For example, if your app name is `yourcompany`, then:

`https://${appName}.und-gesund.de/dataSourcesSwitch.html`&#x20;

should become:

`https://yourcompany.und-gesund.de/dataSourcesSwitch.html`&#x20;

If you're unsure what your `${appName}` is, please refer your web authentication username, it usually follows the format `${appName}-api`. Otherwise, feel free to [contact us](https://thryve.zendesk.com/hc/en-us/requests/new) and we’ll confirm it for you.
{% endhint %}


# Polar

Polar excels in the wearable tech space by offering devices tailored for serious athletes and fitness enthusiasts. Their sports watches and heart rate monitors provide detailed performance analysis, surpassing basic activity tracking.&#x20;

## Data availability

#### Manually Added Polar Data

Not all data manually entered into Polar Flow mobile and web apps is made available through their API. There is no visual indicator in the Polar interface to distinguish between API-available and unavailable manually entered data.

## Create your own oAuth-client for Polar

Follow these steps to create your dedicated Polar oAuth-client and integrate its credentials with our data source connection system seamlessly.

1. **Create a Polar Flow account**

If you don’t already have one, create a Polar Flow account at [flow.polar.com](https://flow.polar.com/). Use this same account to sign in to the [Polar Developer Dashboard](https://admin.polaraccesslink.com/).

2. **Create a Client**

Register a new client by selecting [Create a client](https://admin.polaraccesslink.com/#/clients/create) in the Polar Developer Dashboard.

Please fill in your company's details:

<figure><img src="/files/ex9qVVAXv9apSm7BnQU8" alt=""><figcaption><p>Illustrative Example: Contractual Information</p></figcaption></figure>

Ensure that the provided information is accurate, then click on "Next"

Please fill in your application's details:

* Set Authorization redirect URL: `https://${partnerName}.und-gesund.de/dataSourcesSwitch.html`&#x20;
* Set the data types (scopes) you wish to receive from your Polar users

<figure><img src="/files/2d2phTFiTOhM2YWhpjdE" alt=""><figcaption><p>Illustrative Example: Application Information</p></figcaption></figure>

Ensure that the provided information is accurate, then click on "Next" and create your Polar oAuth-client

&#x20;

3. **Share credentials with Thryve**

After you have created your App, you will be provided with your:

* ClientID
* ClientSecret

Please encrypt these credentials, along with the requested data types, using our [secret sharing service](https://secret.thryve.de/) and then [share](https://thryve.zendesk.com/hc/en-us/requests/new) the resulting link with our Customer Operations Team.

{% hint style="info" %}
Understanding the `${appName}` Variable

In this guide, you'll see the placeholder `${appName}`. Whenever you encounter it, replace it with your actual partner name, exactly as it's registered in our system.<br>

For example, if your partner name is `yourcompany`, then:

`https://${appName}.und-gesund.de/dataSourcesSwitch.html`&#x20;

should become:

`https://yourcompany.und-gesund.de/dataSourcesSwitch.html`&#x20;

If you're unsure what your `${appName}` is, please refer your web authentication username, it usually follows the format `${appName}-api`. Otherwise, feel free to [contact us](https://thryve.zendesk.com/hc/en-us/requests/new) and we’ll confirm it for you.
{% endhint %}


# Withings

Withings is a prominent player in the wearable tech industry, known for its range of health-focused devices such as smart scales, activity trackers, and health monitors. These products provide users with vital health metrics, like heart rate and sleep patterns. With connected blood pressure devices and innovative health sensors, they are driving sensor development within the market.

## Data availability

#### Daily Data

When data has been written by third parties into the Withings app (e.g. Apple Health, Health Connect) it is often not reflected in the daily data values provided by Withings or daily data values are not available at all.

## Create your own oAuth-client for Withings

Follow these steps to create your dedicated Withings oAuth-client and integrate its credentials with our data source connection system seamlessly.

1. **Create a Withings account**

If you don’t already have one, create a [Withings account](https://www.withings.com/eu/en/account/login).

2. **Create a Client**

Register a new application under [Application Creation](https://developer.withings.com/dashboard/create).

Choose 'Public API integration' as the kind of integration under "services".

Please fill in your company's details:

<figure><img src="/files/ex9qVVAXv9apSm7BnQU8" alt=""><figcaption><p>Illustrative Example: Contractual Information</p></figcaption></figure>

Ensure that the provided information is accurate, then click on "Next"

Please fill in your application's details:

* Set Authorization redirect URL: `https://${partnerName}.und-gesund.de/dataSourcesSwitch.html`&#x20;
* Set the data types (scopes) you wish to receive from your Polar users

<figure><img src="/files/2d2phTFiTOhM2YWhpjdE" alt=""><figcaption><p>Illustrative Example: Application Information</p></figcaption></figure>

Ensure that the provided information is accurate, then click on "Next" and create your Withings oAuth-client.

3. **Share credentials with Thryve**

After you have created your App, you will be provided with your:

* ClientID
* ClientSecret

Please encrypt these credentials, along with the requested data types, using our [secret sharing service](https://secret.thryve.de/) and then [share](https://thryve.zendesk.com/hc/en-us/requests/new) the resulting link with our Customer Operations Team.

{% hint style="info" %}
Understanding the `${appName}` Variable

In this guide, you'll see the placeholder `${appName}`. Whenever you encounter it, replace it with your actual partner name, exactly as it's registered in our system.<br>

For example, if your partner name is `yourcompany`, then:

`https://${appName}.und-gesund.de/dataSourcesSwitch.html`&#x20;

should become:

`https://yourcompany.und-gesund.de/dataSourcesSwitch.html`&#x20;

If you're unsure what your `${appName}` is, please refer your web authentication username, it usually follows the format `${appName}-api`. Otherwise, feel free to [contact us](https://thryve.zendesk.com/hc/en-us/requests/new) and we’ll confirm it for you.
{% endhint %}


# Strava

Strava is a leading fitness tracking platform that connects athletes and outdoor enthusiasts by allowing them to record and share their activities. By integrating with Strava, our wearable data platform and API can provide comprehensive insights into users' fitness journeys, enriching the overall user experience.

## Create your own oAuth-client for Strava

* Sign up for a Strava account at <https://www.strava.com/register/free>
* Navigate to <https://www.strava.com/settings/api> Fill out "Application Name" with your Thryve API app's name

![](https://ajeuwbhvhr.cloudimg.io/colony-recorder.s3.amazonaws.com/files/2022-11-07/c872429a-efb0-4f59-a8be-dcc532449089/user_cropped_screenshot.jpeg?tl_px=12,69\&br_px=872,550\&force_format=png\&width=860\&wat_scale=76\&wat=1\&wat_opacity=0.7\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.us-west-1.amazonaws.com/images/watermarks/FB923C_standard.png\&wat_pad=402,212)

* &#x20;Choose a category that best fits your use case - if in doubt, choose "Social motivation"

![](https://ajeuwbhvhr.cloudimg.io/colony-recorder.s3.amazonaws.com/files/2022-11-07/33f366ed-a0d5-48c7-b9af-88fc1141622c/user_cropped_screenshot.jpeg?tl_px=3,131\&br_px=862,612\&force_format=png\&width=860\&wat_scale=76\&wat=1\&wat_opacity=0.7\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.us-west-1.amazonaws.com/images/watermarks/FB923C_standard.png\&wat_pad=402,212)

* Fill out the "Authorization Callback Domain" field with the following URL structure: `https://${appName}.und-gesund.de`&#x20;
* Read Strava's API agreement
* Click "I've read and agree with Strava's API Agreement"

![](https://ajeuwbhvhr.cloudimg.io/colony-recorder.s3.amazonaws.com/files/2022-11-07/d77c213b-9d05-495c-af21-4fc11fb7abc3/user_cropped_screenshot.jpeg?tl_px=0,371\&br_px=859,852\&force_format=png\&width=860\&wat_scale=76\&wat=1\&wat_opacity=0.7\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.us-west-1.amazonaws.com/images/watermarks/FB923C_standard.png\&wat_pad=356,333)

* Click "Create".

![](https://ajeuwbhvhr.cloudimg.io/colony-recorder.s3.amazonaws.com/files/2022-11-07/dea6d672-4a5f-4516-afe0-f6883b68d767/user_cropped_screenshot.jpeg?tl_px=0,371\&br_px=859,852\&force_format=png\&width=860\&wat_scale=76\&wat=1\&wat_opacity=0.7\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.us-west-1.amazonaws.com/images/watermarks/FB923C_standard.png\&wat_pad=395,382)

* Upload your app's logo and press "Save"

![](https://ajeuwbhvhr.cloudimg.io/colony-recorder.s3.amazonaws.com/files/2022-11-07/907f4cae-2334-4fac-889e-2e8376be7764/ascreenshot.jpeg?tl_px=133,121\&br_px=992,602\&force_format=png\&width=860\&wat_scale=76\&wat=1\&wat_opacity=0.7\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.us-west-1.amazonaws.com/images/watermarks/FB923C_standard.png\&wat_pad=402,212)

5. **Share credentials with Thryve**&#x20;

After you have created your App, you will be provided with your:

* ClientID
* ClientSecret

Please encrypt these credentials using our [secret sharing service](https://secret.thryve.de/) and then [share](https://thryve.zendesk.com/hc/en-us/requests/new) the resulting link with our Customer Operations Team.

&#x20;&#x20;

### **Apply for the Strava developer program** <a href="#h_01hw8jpbbhz0ckeb90r4nka8h3" id="h_01hw8jpbbhz0ckeb90r4nka8h3"></a>

Strava has recently implemented stricter API limits for new apps. If you find that your app's current limits are insufficient, you'll need to apply for their partnership program [here](https://share.hsforms.com/1VXSwPUYqSH6IxK0y51FjHwcnkd8).

This form shouldn't take longer than 5 minutes to fill out, and submitted forms are typically reviewed within one week.

{% hint style="info" %}
Understanding the `${appName}` Variable

In this guide, you'll see the placeholder `${appName}`. Whenever you encounter it, replace it with your actual partner name, exactly as it's registered in our system.<br>

For example, if your partner name is `yourcompany`, then:

`https://${appName}.und-gesund.de/dataSourcesSwitch.html`&#x20;

should become:

`https://yourcompany.und-gesund.de/dataSourcesSwitch.html`&#x20;

If you're unsure what your `${appName}` is, please refer your web authentication username, it usually follows the format `${appName}-api`. Otherwise, feel free to [contact us](https://thryve.zendesk.com/hc/en-us/requests/new) and we’ll confirm it for you.
{% endhint %}


# Overview

The Thryve Health Analytics Platform processes wearable sensor data into health metrics following clinical and scientific best practices in near real-time. Our analytics engine transforms data from hundreds of data signals into standardized health insights suitable for healthcare applications, research, and population health monitoring.

All analytics are computed and available within milliseconds of data ingestion, enabling immediate access to health insights. Algorithms are based on established clinical frameworks and peer-reviewed research, ensuring that metrics meet healthcare application requirements.

### Core Analytics Capabilities

#### Real-Time Processing

Analytics are calculated continuously as new data arrives, rather than through batch processing. This enables immediate health insights and supports applications requiring real-time health monitoring.

#### Scientific backing

The analytics platform is built on our roots in biosignal analysis and our scientific approach given Thryve was built as a spin-off of renowned Fraunhofer Institute. Where applicable we build our algorithms on top of established clinical frameworks adapted for continuous wearable data monitoring and are actively involved in research projects all around Europe.

#### Data Harmonization

Our data harmonization efforts go beyond storing and providing data from different kinds of data sources in a unified data format and API. With our extensive analytics suit we harmonize core health metrics across different wearable manufacturers and data sources. This solves the fundamental challenge of inconsistent metric definitions (e.g. for sleep data) between devices and enables longitudinal health tracking regardless of device changes.

#### Multi-Device/Source Data Fusion

Advanced algorithms handle data from multiple simultaneous sources:

* **Overlap Detection**: Identifies and resolves conflicts when multiple devices record the same timeframe
* **Priority-Based Selection**: Hierarchical data selection when conflicts arise
* **Data Deduplication**: Prevents double-counting across connected devices

Data priority is determined based on information on recording device and context.


# Foundational analytics

Foundation metrics provide essential health measurements that form the data infrastructure for advanced health analytics. These metrics transform wearable data points into standardized, clinically relevant measurements through sophisticated data processing and validation algorithms.

### Body Composition Analysis

#### BMI and Waist Circumference Estimation

Calculates body mass index and estimates waist circumference using validated anthropometric algorithms that incorporate age and gender-specific adjustments.

**Input Data**

<table><thead><tr><th>dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th><th data-type="checkbox">Required</th><th>Fallback</th></tr></thead><tbody><tr><td><span data-option="XFNuDkVoCuHF">epoch, </span><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>5020</code></td><td>Weight</td><td>true</td><td>n.a.</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch, </span><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>5030</code></td><td>Height</td><td>false</td><td>male: 175, female: 165</td></tr><tr><td><span data-option="Tqu2fsZQpEme">constant</span></td><td><code>1</code></td><td>Gender</td><td>true</td><td>n.a.</td></tr><tr><td><span data-option="Tqu2fsZQpEme">constant</span></td><td><code>10</code></td><td>Birthyear</td><td>false</td><td>1980</td></tr><tr><td><span data-option="Tqu2fsZQpEme">constant</span></td><td><code>11</code></td><td>Birth Month</td><td>false</td><td>01</td></tr><tr><td><span data-option="Tqu2fsZQpEme">constant</span></td><td><code>12</code></td><td>Birth Day</td><td>false</td><td>01</td></tr></tbody></table>

**Output Data**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="UBtQ2D7bXLcq">epoch</span></td><td><code>5026</code></td><td>BMI</td></tr><tr><td><span data-option="UBtQ2D7bXLcq">epoch</span></td><td><code>5027</code></td><td>WaistCircumference</td></tr></tbody></table>

***

### Daily Activity Intelligence

Processes activity data from multiple sources to generate standardized daily activity summaries for Walk, Run and Bike activities.

**Input Data**

<table><thead><tr><th>dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1114</code></td><td>ActiveBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1115</code></td><td>WalkBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1116</code></td><td>RunBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1117</code></td><td>BikeBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1715</code></td><td>CoveredDistanceWalk</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1716</code></td><td>CoveredDistanceRun</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1717</code></td><td>CoveredDistanceBike</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1825</code></td><td>ActiveWalkDuration</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1826</code></td><td>ActiveRunDuration</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1827</code></td><td>ActiveBikeDuration</td></tr></tbody></table>

**Processing Logic**

1. **Overlap Detection**: Identifies and removes duplicate data from multiple sources
2. **Manual vs. Automatic Classification**: Separates user-entered from sensor-detected data for daily data aggregation
3. **Daily Aggregation**: Sums durations and distances by activity type and data source

**Output Data**

**Sensor-Detected Activity**:

<table><thead><tr><th>dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1114</code></td><td>ActiveDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1115</code></td><td>WalkDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1116</code></td><td>RunDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1117</code></td><td>BikeDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1715</code></td><td>CoveredDistanceWalk</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1716</code></td><td>CoveredDistanceRun</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1717</code></td><td>CoveredDistanceBike</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1825</code></td><td>ActiveWalkDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1826</code></td><td>ActiveRunDuration</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1827</code></td><td>ActiveBikeDuration</td></tr></tbody></table>

**Manual Activity Entries**:

<table><thead><tr><th>dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1814</code></td><td>ActiveDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1815</code></td><td>WalkDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1816</code></td><td>RunDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1817</code></td><td>BikeDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1725</code></td><td>CoveredDistanceWalkManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1726</code></td><td>CoveredDistanceRunManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1727</code></td><td>CoveredDistanceBikeManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1835</code></td><td>ActiveWalkDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1836</code></td><td>ActiveRunDurationManual</td></tr><tr><td><span data-option="cvt8P6Lusu6d">daily</span></td><td><code>1837</code></td><td>ActiveBikeDurationManual</td></tr></tbody></table>

**Data Quality Features**

* Timezone-aware daily boundary calculation
* Multi-source conflict resolution with data prioritization
* Quality indicators for manual vs. automatic data classification

***

### Metabolic Equivalent (MET) Analysis

#### Real-Time Energy Expenditure Analysis

Calculates metabolic equivalent values from calorie expenditure and activity data, providing continuous assessment of activity intensity relative to weight as a multiple of resting metabolic rate.

**Input Data**

<table><thead><tr><th width="231.2109375">dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th width="92.33203125">dataTypeId</th><th width="185.4140625">Name</th><th width="93.6328125" data-type="checkbox">Required</th><th width="144.046875">Fallback</th></tr></thead><tbody><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1011</code></td><td>ActiveBurnedCalories</td><td>true</td><td>n.a.</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1010</code></td><td>BurnedCalories</td><td>true</td><td>n.a.</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>1200</code></td><td>ActivityType</td><td>true</td><td>n.a.</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch, </span><span data-option="cvt8P6Lusu6d">daily, </span><span data-option="Tqu2fsZQpEme">constant</span></td><td><code>5020</code></td><td>Weight</td><td>false</td><td>75kg</td></tr></tbody></table>

**Output Data**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="UBtQ2D7bXLcq">epoch</span></td><td><code>1012</code></td><td>MetabolicEquivalent</td></tr></tbody></table>

**Data Processing Features**

* **Quality Control**: Filters unreasonable MET values
* **Data Prioritization**: Calorie availability takes precedence over generic activity information

**Fallback Mechanisms**

* Weight defaults to 75kg when unavailable
* Activity type classification is used when calorie data is incomplete

***

### Advanced MET Analysis

#### Daily Physical Activity Assessment

Processes continuous MET data to generate comprehensive daily activity intensity assessments and maximum metabolic capacity indicators.

**Input Data**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="UBtQ2D7bXLcq">epoch</span></td><td><code>1012</code></td><td>MetabolicEquivalent</td></tr></tbody></table>

**METmax Analysis**

Calculates maximum metabolic equivalent values over specified time windows to assess cardiovascular capacity and exercise tolerance.

**Processing Logic**

1. **Daily Maximum Selection**: Peak values identified for each time window

**Output Data**

<table><thead><tr><th width="128.37890625">dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th width="96.8671875">dataTypeId</th><th width="257.703125">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1286</code></td><td>MetabolicEquivalentMax1Min</td><td>highest 1-minute rolling average</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1287</code></td><td>MetabolicEquivalentMax5Min</td><td>highest 5-minute rolling average</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1288</code></td><td>MetabolicEquivalentMax10Min</td><td>highest 10-minute rolling average</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1289</code></td><td>MetabolicEquivalentMax60Min</td><td>highest 60-minute rolling average</td></tr></tbody></table>

**Activity Intensity Classification**

**Input Data**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="UBtQ2D7bXLcq">epoch</span></td><td><code>1012</code></td><td>MetabolicEquivalent</td></tr></tbody></table>

**Output Data**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1101</code></td><td>ActivityLowDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1102</code></td><td>ActivityMidDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>1103</code></td><td>ActivityHighDuration</td></tr></tbody></table>

**Processing Features**:

* Timezone consistency is maintained across daily boundaries

**Clinical Applications**

METmax values provide insights into cardiovascular fitness and exercise capacity, typically available only through clinical exercise testing. Activity intensity classifications align with established exercise prescription guidelines for healthcare applications.

### Standardized Sleep Analysis

#### Sleep Cycle Identification and Standardization

Addresses the challenge of inconsistent sleep definitions across wearable manufacturers by implementing standardized sleep cycle identification and analysis. Provides consistent sleep metrics regardless of the underlying data source. Enriches data when sleep data sets provided by data source are incomplete

#### Input Data

<table><thead><tr><th width="127.953125">dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th width="92.33203125">dataTypeId</th><th width="527.8828125">Name</th></tr></thead><tbody><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2000</code></td><td>SleepStateBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2001</code></td><td>SleepInBedBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2002</code></td><td>SleepREMBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2003</code></td><td>SleepDeepBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2005</code></td><td>SleepLightBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2006</code></td><td>SleepAwakeBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>4101</code></td><td>SnoringBinary</td></tr></tbody></table>

#### Processing Logic

1. **Data Harmonization**: Consolidates sleep data from all connected sources
2. **Cycle Identification**: Identifies all sleep periods using a 30-minute interruption threshold
3. **Main Sleep Selection**: Selects the longest cycle as the primary sleep period
4. **Day Assignment**: Assigns sleep cycles to calendar days based on mid-sleep time

**ThryveMainSleep Definition**

The longest continuous sleep cycle of each day, where interruptions (wake phases) do not exceed 30 minutes. This standardized definition enables consistent metrics across different devices and longitudinal tracking when users change devices.

#### Output data

**Standard Sleep Metrics**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2000</code></td><td>SleepDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2001</code></td><td>SleepInBedDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2002</code></td><td>SleepREMDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2003</code></td><td>SleepDeepDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2005</code></td><td>SleepLightDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2006</code></td><td>SleepAwakeDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2007</code></td><td>SleepLatency</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2008</code></td><td>SleepAwakeAfterWakeup</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2100</code></td><td>SleepStartTime</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2101</code></td><td>SleepEndTime</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2102</code></td><td>SleepInterruptions</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2103</code></td><td>SleepMidTime</td></tr></tbody></table>

**ThryveMainSleep Standardized Metrics**

<table><thead><tr><th>dataDimension<select multiple><option value="UBtQ2D7bXLcq" label="epoch" color="blue"></option><option value="I92d09KZQRnp" label="daily" color="blue"></option><option value="pmS5xH6BFBmT" label="constant" color="blue"></option></select></th><th width="147.8671875">dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2300</code></td><td>ThryveMainSleepDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2301</code></td><td>ThryveMainSleepInBedDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2302</code></td><td>ThryveMainSleepREMDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2303</code></td><td>ThryveMainSleepDeepDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2305</code></td><td>ThryveMainSleepLightDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2306</code></td><td>ThryveMainSleepAwakeDuration</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2307</code></td><td>ThryveMainSleepLatency</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2308</code></td><td>ThryveMainSleepAwakeAfterWakeup</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2400</code></td><td>ThryveMainSleepStartTime</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2401</code></td><td>ThryveMainSleepEndTime</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2402</code></td><td>ThryveMainSleepInterruptions</td></tr><tr><td><span data-option="I92d09KZQRnp">daily</span></td><td><code>2403</code></td><td>ThryveMainSleepMidTime</td></tr></tbody></table>

**Epoch-Level Sleep State Data**

<table><thead><tr><th width="127.953125">dataDimension<select multiple><option value="cvt8P6Lusu6d" label="daily" color="blue"></option><option value="XFNuDkVoCuHF" label="epoch" color="blue"></option><option value="NcGS6usRVIAp" label="dail" color="blue"></option><option value="Tqu2fsZQpEme" label="constant" color="blue"></option></select></th><th width="92.33203125">dataTypeId</th><th width="527.8828125">Name</th></tr></thead><tbody><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2300</code></td><td>ThryveMainSleepStateBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2301</code></td><td>ThryveMainSleepInBedBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2302</code></td><td>ThryveMainSleepREMBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2303</code></td><td>ThryveMainSleepDeepBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2305</code></td><td>ThryveMainSleepLightBinary</td></tr><tr><td><span data-option="XFNuDkVoCuHF">epoch</span></td><td><code>2306</code></td><td>ThryveMainSleepAwakeBinary</td></tr></tbody></table>


# Health status assessment

Health status metrics enhance traditional clinical markers by converting foundational data into actionable health insights. These algorithms leverage established clinical frameworks tailored for continuous monitoring through wearable devices, enabling healthcare applications to offer users comprehensive health assessments.

## **Sleep Assessment**

Sleep plays a crucial role in maintaining overall health and well-being, impacting both physical and mental performance. Accurate assessment of sleep quality helps in identifying potential health issues early on, allowing for timely interventions and improved health outcomes.

Our algorithms perform a two-dimensional sleep assessment following existing clinical standards, evaluating the Quality and Efficiency of a specific night's sleep as well as assessing circadian health and sleep consistency patterns across a rolling historical timeframe.

#### **Input Data**

* Thryve Foundational Sleep Analytics

#### Output Data

<table><thead><tr><th width="147.6163330078125">dataDimension<select><option value="xnm7WCENx3uo" label="daily" color="blue"></option></select></th><th width="126.470458984375">dataTypeId</th><th width="164.86279296875">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2201</code></td><td>SleepQuality</td><td><p><strong>Scale:</strong> 0-100 (higher values indicate better sleep quality). </p><p></p><p><strong>Clinical significance:</strong> Values >77 indicate good sleep quality</p></td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2200</code></td><td>SleepEfficiency</td><td><strong>Scale:</strong> 0-100 (higher values indicate better sleep hygiene). <br><br><strong>Clinical significance:</strong> Values &#x3C;75 are correlated with aging and indicate can various health conditions</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2220</code></td><td>SleepRegularity</td><td><strong>Scale</strong>: 0-100 (higher values indicate more regular sleep patterns)<br><br><strong>Clinical significance</strong>: Values &#x3C;60 associated with increased health risks</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2221</code></td><td>InterdailyStability</td><td><strong>Scale</strong>: 0-100 (higher values indicate more stable circadian rhythms)<br><br><strong>Clinical significance</strong>: Values &#x3C;50 point to irregular daily structure, often reflecting underlying mental, neurological, or lifestyle-related issues.</td></tr></tbody></table>

***

## Physical Activity Index Assessment

The Physical Activity Index provides crucial insights into an individual's activity patterns, serving as a multidimensional tool to evaluate and improve activity-related health outcomes.&#x20;

By systematically analyzing the intensity, frequency, and duration of physical activity, this index empowers users to identify potential causes of health disparities and encourages the adoption of healthier lifestyles.&#x20;

#### Input Data

<table><thead><tr><th>dataDimension<select><option value="OQcmGaKtRnZ1" label="daily" color="blue"></option><option value="NR0YK1pnpjU6" label="epoch" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td><code>1101</code></td><td>ActivityLowDuration</td></tr><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td><code>1102</code></td><td>ActivityMidDuration</td></tr><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td><code>1103</code></td><td>ActivityHighDuration</td></tr><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td><code>1287</code></td><td>MetabolicEquivalentMax5Min</td></tr></tbody></table>

{% hint style="info" %}
All required input data is calculated by Thryve's foundational analytics.
{% endhint %}

#### Output Data

<table><thead><tr><th width="147.6163330078125">dataDimension<select><option value="xnm7WCENx3uo" label="daily" color="blue"></option></select></th><th width="126.470458984375">dataTypeId</th><th width="185.3966064453125">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>1013</code></td><td>PhysicalActivityIndex</td><td><p><strong>Scale</strong>: 0-45 (higher values indicate higher physical activity)<br><br><strong>Clinical interpretation</strong>: </p><ul><li>0: Inactive lifestyle</li><li>1-20: Moderately active</li><li>>20: Highly active<br></li></ul><p><strong>Clinical significance:</strong><br>Low physical activity indicates a sedentary lifestyle, leading to increased risk of metabolic syndrome, cardiovascular events, and earlier mortality.</p></td></tr></tbody></table>

## Cardiovascular Fitness Assessment

This assessment provides valuable insights into your users' heart and lung capacity to transport and utilize oxygen during intense physical activities. By estimating VO2max, which indicates the maximum rate of oxygen consumption during increasing exercise intensity, we offer a vital indicator of your users' aerobic endurance and overall cardiovascular health. The estimation incorporates data from wearables and demographic information to deliver an accurate measure of your users' cardiovascular fitness.

#### **Input Data**

<table><thead><tr><th>dataDimension<select><option value="OQcmGaKtRnZ1" label="daily" color="blue"></option><option value="NR0YK1pnpjU6" label="epoch" color="blue"></option></select></th><th>dataTypeId</th><th>Name</th></tr></thead><tbody><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td>1013</td><td>PhysicalActivityIndex</td></tr><tr><td><span data-option="OQcmGaKtRnZ1">daily</span></td><td>3001/3002</td><td>HeartRateResting/HeartRateSleep (depending on availability)</td></tr><tr><td><span data-option="NR0YK1pnpjU6">epoch</span></td><td>5027</td><td>WaistCircumference</td></tr><tr><td><span data-option="NR0YK1pnpjU6">epoch</span></td><td></td><td>Gender</td></tr><tr><td><span data-option="NR0YK1pnpjU6">epoch</span></td><td></td><td>Birthyear</td></tr></tbody></table>

#### **Output Data**

<table><thead><tr><th width="147.6163330078125">dataDimension<select><option value="xnm7WCENx3uo" label="daily" color="blue"></option></select></th><th width="126.470458984375">dataTypeId</th><th width="164.86279296875">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>3030</code></td><td>VO2max</td><td>VO2max represents a strong predictor of cardiovascular mortality and all-cause mortality. </td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>3032</code></td><td>VO2maxPercentile</td><td>Provides percentile ranking of user based on Cooper Institute fitness standards with age and gender stratification.</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>3031</code></td><td>FitnessAge</td><td>Translates VO2max into age-equivalent fitness level using population fitness norms.</td></tr></tbody></table>


# Health risk assessment

Wearable data provides continuous, real-time insights into an individual's sleep patterns and overall health status, offering a more comprehensive view than traditional methods. By leveraging this data, Thryve can accurately assess health risks on the population level, enhancing preventative care strategies.

{% hint style="info" %}
Designed for population health screening and wellness monitoring, not diagnostic use.
{% endhint %}

## Sleep-based health risk assessment

This risk assessment translates a commonly underutilized health signal, sleep, into a tangible risk-scoring model. Built on a foundation of large-scale epidemiological research and real-world wearable data, the calculated metric tells a deeper story about your user's metabolic, cardiovascular, cognitive, and emotional resilience. Our models take these patterns and calculate individualized risk levels for a variety of health outcomes.

#### Input Data

* Thryve Foundational Sleep Analysis & Health Status Assessment

#### Output Data

<table><thead><tr><th width="147.6163330078125">dataDimension<select><option value="xnm7WCENx3uo" label="daily" color="blue"></option></select></th><th width="126.470458984375">dataTypeId</th><th width="224.8065185546875">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2251</code></td><td>SleepRelatedMortalityRisk</td><td>Elevated mortality risk compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2252</code></td><td>SleepRelatedCardiovascularRisk</td><td>Elevated risk of developing cardiovascular disease compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2253</code></td><td>SleepRelatedStrokeRisk</td><td>Elevated risk of having a stroke compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2254</code></td><td>SleepRelatedMentalHealthRisk</td><td>Elevated risk of developing mental health diseases compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2255</code></td><td>SleepRelatedDementiaRisk</td><td>Elevated risk of developing dementia compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2256</code></td><td>SleepRelatedCancerRisk</td><td>Elevated risk of developing cancer compared to the standard population in percent (%).</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2257</code></td><td>SleepRelatedSickLeavePrediction</td><td>Estimated increase in sick leave days compared to the reference population.</td></tr><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>2258</code></td><td>SleepRelatedLifeExpectancyImpact</td><td>Estimated reduction in life expectancy (years lost) compared to the reference population.</td></tr></tbody></table>

## Multi-dimensional Mental Health Risk

Thryve, in collaboration with FU Berlin, has established a validated mental health risk scoring system that assesses depression risk using clinical questionnaires and behavioral health evaluations.&#x20;

<figure><img src="/files/SDbFvs20nAxbCx8tXoyC" alt="" width="188"><figcaption><p>Thryve Mental Health Risk Score implemented in coaching application</p></figcaption></figure>

By offering a detailed understanding of an individual's mental health risk, this marker allows for the creation of targeted prevention strategies, thereby enhancing early intervention efforts and improving mental wellness outcomes.

**Input Data**

* Activity data
* Sleep data
* Vital data
* 4 patient-reported answers to standardized questions&#x20;

**Output Data**

<table><thead><tr><th width="147.6163330078125">dataDimension<select><option value="xnm7WCENx3uo" label="daily" color="blue"></option></select></th><th width="126.470458984375">dataTypeId</th><th width="224.8065185546875">Name</th><th>Description</th></tr></thead><tbody><tr><td><span data-option="xnm7WCENx3uo">daily</span></td><td><code>6406</code></td><td>MentalHealthRisk</td><td><p>Binary risk assessment:<br></p><ul><li>false: No increased risk detected</li><li>true: Increased depression risk identified</li></ul></td></tr></tbody></table>


# Setup Thryve SDK

Thryve SDK enables effortless mobile app integration on iOS, Android, React Native, and Flutter developer platforms. Paired with the Thryve Connection Widget, it facilitates the quick connection to all data sources, including Apple Health, Health Connect, and Samsung Health, within just a few lines of code, enabling full integration of Thryve in minutes.

Developers can integrate the Thryve SDK into their projects using:

* **Remote Dependency Management:** Simplifies version control and maintenance by automatically updating to the latest SDK version from a remote repository.
* **Manual Framework Addition**: Framework files can be added directly to the project.

Whether using automated updates or manual integration, Thryve SDK provides flexibility and ease of use to enhance mobile app capabilities.

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td>Setup Thryve SDK for iOS developers</td><td><a href="/pages/hnewAJjjtf5jP9Ks2p3L">/pages/hnewAJjjtf5jP9Ks2p3L</a></td><td><a href="/files/frekpfdVtnfDPgbLmATu">/files/frekpfdVtnfDPgbLmATu</a></td></tr><tr><td>Setup Thryve SDK for Android developers</td><td><a href="/pages/gd15Xn3eNpfQhy8TrHU5">/pages/gd15Xn3eNpfQhy8TrHU5</a></td><td><a href="/files/rAB9afaNRUiSSbAIyRJs">/files/rAB9afaNRUiSSbAIyRJs</a></td></tr><tr><td>Setup Thryve SDK for React Native developers</td><td><a href="/pages/xOThFe3wAvaZ3HG8hrNh">/pages/xOThFe3wAvaZ3HG8hrNh</a></td><td><a href="/files/befm1y9BzQltHMWrd650">/files/befm1y9BzQltHMWrd650</a></td></tr><tr><td>Setup Thryve SDK for Flutter developers</td><td><a href="/pages/W1fUrSLPe87hrvElTDDu">/pages/W1fUrSLPe87hrvElTDDu</a></td><td><a href="/files/eCjesxd6uIBFIWvCb4ia">/files/eCjesxd6uIBFIWvCb4ia</a></td></tr></tbody></table>


# iOS

The Thryve iOS SDK is the fastest way to implement Thryve's product into your iOS application and is required to allow users to connect Apple Health as a data source. The Thryve iOS SDK is available as Cocoapods and frameworks. It requires:

* **Xcode:** version 14.2 or later.
* **iOS Target:** version 14 or higher is recommended.

{% tabs %}
{% tab title="Integration via Cocoapods" %}
To integrate the Thryve iOS SDK modules via **Cocoapods** into your application, follow these steps:

1. **Add Thryve Specs Repository**\
   Open your terminal and navigate to your project directory. Then, execute the following command to add the Thryve Specs repository:

   ```
   pod repo add ThryveSpecs https://git.thryve.de/thryve/Specs.git
   ```
2. **Update Your Podfile**\
   Modify your Podfile to include the necessary Thryve SDK modules. Refer to the sample [Podfile](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/ThryveConnectorSample/Podfile?ref_type=heads) provided in the Thryve iOS [Sample App](https://git.thryve.de/thryve/sdk/-/tree/master/iOS?ref_type=heads) for guidance.
3. **Install Pods**\
   Run the following command in your terminal to install the specified pods:

   ```
   pod install
   ```

Ensure you regularly update the Thryve Specs repository to get the latest features and fixes. For more details, visit the Thryve Specs Git repository: [Thryve Specs](https://git.thryve.de/thryve/Specs.git).

```ruby
platform :ios, '13.0'
source 'https://git.thryve.de/thryve/Specs.git'

target 'ThryveConnectorSample' do
 
  use_frameworks!

pod 'ThryveCore', '5.2.4'
pod 'ThryveCommons', '5.2.4'
pod 'ThryveAppleHealth', '5.2.4'
pod 'ThryveShenAI', '5.2.4'
pod 'ThryveObservability', '5.2.4'
pod 'ThryveBLE', '5.2.4'

end
```

{% endtab %}

{% tab title="Integration via frameworks" %}
To integrate the Thryve iOS SDK into your app manually, download the Thryve SDK framework files and sample app code. Follow the instructions below for seamless integration.

| Module Name         | Download Version                                                                                                       |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| ThryveCore          | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_core_sdk_5.2.4.xcframework.zip)         |
| ThryveCommons       | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_commons_sdk_5.2.4.xcframework.zip)      |
| ThryveAppleHealth   | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_apple_health_sdk_5.2.4.xcframework.zip) |
| ThryveShenAI        | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_module_shen_ai_5.2.4.xcframework.zip)   |
| ShenaiSDK           | [3.0.2](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/ShenaiSDK._3.0.2.xcframework.zip)              |
| Sample App          | [5.2.4](https://git.thryve.de/thryve/sdk/-/tree/master/iOS/ThryveiOSSampleApp)                                         |
| ThryveObservability | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_observability_5.2.4.xcframework.zip)    |
| ThryveBLE           | [5.2.4](https://git.thryve.de/thryve/sdk/-/blob/master/iOS/xcframeworks/thryve_ble_5.2.4.xcframework.zip)              |

#### Adding and Linking a Framework in Xcode

1. **Add Framework**
   1. Right-click on your Xcode project's root and create a `New Group` named `Framework`.
   2. Drag and drop the extracted `.xcframework` folders from Finder into this group.
   3. In the dialog box, select `Copy items if needed`, `Create folder references`, and choose the targets for the framework.

<figure><img src="/files/UtV8U8LFxZ7NTPL9NyAm" alt=""><figcaption></figcaption></figure>

2. **Link Framework**
   1. Navigate to `project root > target > General`.
   2. Add the frameworks to `Frameworks, Libraries, and Embeded Content` by clicking the **+** button.
   3. Select the desired framework, such as `ThryveCore` or `ThryveCommons` .
   4. Choose `Embed & Sign` .

If you have followed the import correctly, the screen should look like this, depending on the imported frameworks.

<figure><img src="/files/Se7xcfBS0qttoPEo3Xfk" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
A runtime error such as the following indicates that the `Embed & Sign` setting was not correctly applied to an added framework:

`dyld[5119]: Library not loaded: @rpath/ThryveCommons.framework/ThryveCommons`\
`../ThryveCommons.framework/ThryveCommons' (no such file),`
{% endhint %}
{% endtab %}

{% tab title="Integration via SPM" %}
To integrate the Thryve iOS SDK modules via Swift Package Manager (SPM) into your application, follow these steps:

1. **Add Thryve Package Repository**
   1. In Xcode, navigate to `File > Add Package Dependencies`. In the search field, enter the Thryve package repository URL: \
      \
      `https://git.thryve.de/thryve/Pods` \
      \
      Xcode will find the package. <br>

      <figure><img src="/files/oayLQDYCSkDZKMjVhFcE" alt=""><figcaption></figcaption></figure>

   2. Set the `Dependency Rule` to `Up to Next Major Version` starting from your desired version (e.g. 5.2.4), select your project under `Add to Project`, and click `Add Package`.\ <br>
2. **Choose Package Products**\
   After the package is fetched, Xcode will present a list of available package products.
   1. Select the modules you need and assign them to the appropriate target.&#x20;
   2. Click `Add Package` to confirm.

<figure><img src="/files/WrjnJdQ61pW2WRykX0eK" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

{% hint style="info" %}
If an `Undefined symbol:` error occurs, ensure that all modules use the same SDK version. For example, `ThryveAppleHealth.xcframework` (or Pod) version `5.0.2` cannot be used together with `ThryveCommons.xcframework` (or Pod) version `5.0.4`.
{% endhint %}

## App Store Privacy Compliance Configuration

### Adding a Privacy Manifest File

Starting May 1, 2024, all apps and third-party SDKs must include the use of [required reason API](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api), such as [`UserDefaults`](https://developer.apple.com/documentation/foundation/userdefaults), in their privacy manifest file for App Store Connect approval. Follow these steps:

1. **Create a Privacy Manifest File**: Ensure your app includes a [manifest file](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files).
2. **Specify Privacy API Types**: Add `Privacy Accessed API Types` or `NSPrivacyAccessedAPITypes` to your file.
3. **Provide API Reasoning**: Under `Privacy Accessed API Reasons`, or `NSPrivacyAccessedAPITypeReasons`, list `CA92.1` in an array. More details can be found [here](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api#4278401).

<details>

<summary>The <code>PrivacyInfo.xcprivacy</code> plist file should look similar to this sample</summary>

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>NSPrivacyAccessedAPITypes</key>
    <array>
        <dict>
            <key>NSPrivacyAccessedAPITypeReasons</key>
            <array>
                <string>CA92.1</string>
            </array>
            <key>NSPrivacyAccessedAPIType</key>
            <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
        </dict>
    </array>
</dict>
</plist>
```

</details>

## Apple Health (HealthKit) project configuration

### Integrate ThryveAppleHealth module

To add HealthKit to your iOS app:

* Integrate `ThryveAppleHealth`, along with `ThryveCore` and `ThryveCommons`.
* Use either CocoaPods or framework files for installation.
* This setup allows users to connect with Apple Health and retrieve health data automatically.

### Add HealthKit to project & configure Info.plist

To be able to build your app with integrated `ThryveAppleHealth` module you need to:

1. **Enable HealthKit**
   1. In Xcode: Navigate to *Target → Signing & Capabilities → add (+) → HealthKit*.
   2. For [Background Sync feature](/integrate-your-mobile-app/connect-data-sources) to work, ensure *Background Delivery* is enabled.

<figure><img src="/files/VBuXBDW6NeGkgszAMm8I" alt=""><figcaption></figcaption></figure>

2. **Update your app's `info.plist`**

```xml
<key>NSHealthShareUsageDescription</key>
<string>This app needs permission to share your health data.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>This app needs permission to update your health data.</string>
```

{% hint style="warning" %}
Although `ThryveAppleHealth` module does not update data via HealthKit, `NSHealthUpdateUsageDescription` is required. A missing description will lead to rejection during the App Store review process.
{% endhint %}

{% hint style="success" %}
Read [the ThryveBLE Set-up guide](https://docs.thryve.health/integrate-your-mobile-app/direct-bluetooth-device-connection) for additional information on how to set-up the ThryveBLE module
{% endhint %}

{% hint style="success" %}
Read [the ThryveShenAI Set-up guide](https://docs.thryve.health/integrate-your-mobile-app/camera-based-health-data-recording) for additional information on how to set-up the ThryveShenAI module
{% endhint %}


# Android

The Thryve Android SDK is the fastest way to implement Thryve's product into your Android application and is required to allow users to connect Health Connect and Samsung Health as a data source. The Thryve iOS SDK is available via the Maven repository and frameworks.

## Integrate using Thryve Repository Dependencies

Thryve provides a private, protected repository supporting the Maven repository format to retrieve the Thryve SDK build artifacts. To configure a Gradle project to resolve dependencies declared in `build.gradle` file, the Thryve repository has to be declared as shown in the root and app `build.gradle` files.

### The Root `build.gradle` file

{% tabs %}
{% tab title="build.gradle.kts" %}

```kotlin
allprojects {
    repositories {
        ... 
        maven {         
            url = uri("https://git.thryve.de/api/v4/projects/12/packages/maven")
            credentials {
                    username = thryveUsername
                    password = thryvePassword
            }
        }
        ...
    }
}
```

{% endtab %}

{% tab title="build.gradle" %}

```groovy
allprojects {
    repositories {
        ...
        maven {
            url "https://git.thryve.de/api/v4/projects/12/packages/maven"
            credentials {
                username = thryveUsername
                password = thryvePassword
            }
        }
        ...
    }
}
```

{% endtab %}

{% tab title="settings.gradle.kts" %}

```
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        ...
        maven {
            url = uri("https://git.thryve.de/api/v4/projects/12/packages/maven")
            credentials {
                username = thryveUsername
                password = thryvePassword
            }
        }
        ...
    }
}
```

{% endtab %}
{% endtabs %}

Your username and password are provided in onboarding when signing up with Thryve. It is recommended to store credentials in your project’s `local.properties` or the user-global Gradle properties `gradle.properties`

```
thryveUsername=YOUR_SDK_CREDENTIAL_USER
thryvePassword=YOUR_SDK_CREDENTIAL_PASSWORD
```

### The App `build.gradle` file

Add dependencies to the app `build.gradle` after adding the repository

{% hint style="info" %}
You must use `api` instead of `implementation` to make the Thryve SDK and it's modules work correctly
{% endhint %}

{% hint style="info" %}
Note the change in name of the package. The versions preceding 5.0.0 used  `com.thryve.connector` . Use the appropriate package when upgrading to or downgrading from 5.x
{% endhint %}

## Integrate using Thryve .aar Libraries

The Thryve Android SDK module is available as a standard Android Archive (`aar`). You can download the framework files here:

<details>

<summary>The <code>.aar</code> libraries can be downloaded from here</summary>

| Module Name           | Download Version                                                                                       |
| --------------------- | ------------------------------------------------------------------------------------------------------ |
| Core SDK Module       | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_core_sdk_5.2.2.aar)              |
| Commons Module        | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_module_commons_5.2.2.aar)        |
| Health Connect Module | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_module_hconnect_5.2.2.aar)       |
| Samsung Health Module | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_module_samsung_health_5.2.2.aar) |
| Observability Module  | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_module_observability_5.2.2.aar)  |
| ShenAI module         | [5.2.2](https://git.thryve.de/thryve/sdk/-/blob/master/Android/thryve_module_shen_ai_5.2.2.aar)        |
| Android Sample Code   | [5.2.2](https://git.thryve.de/thryve/sdk/-/tree/master/Android/ThryveAndroidSample)                    |

</details>

### Integrating AAR Libraries into Your Application

1. **Add AAR File:**
   1. Place the `.aar` file in a project directory, such as `libs`.
2. **Update `build.gradle`:**
   * Add `implementation files('libs/.aar')`.
3. **Enable Kotlin Support:**
   * Include [annotation processing](https://kotlinlang.org/docs/reference/kapt.html).
4. **Add Android Support Libraries:**
   * Integrate the `Android AppCompat-Library`.
5. **Set Java Compatibility:**
   * Ensure target and source compatibility for Java 1.8.
6. **Set Kotlin JVM Target:**
   * Use Kotlin JVM target version 1.8.

Ensure you include the necessary dependencies for the Thryve SDK and verify that they are all compatible versions.

{% tabs %}
{% tab title="build.gradle.kts" %}

```kotlin
...
android {
    ...
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    ...
}

dependencies {
    ...
    implementation("androidx.appcompat:appcompat:$appCompat")
    implementation("androidx.core:core-ktx:$androidXCore")

    // Referenced in project's build.gradle
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version")

    implementation(files("libs/thryve_core_sdk_${thryve_sdk_version}.aar")

    // CommonsModule import needed for other modules
    implementation(files("libs/thryve_module_commons_${thryve_sdk_version}.aar"))
    
    // Optional modules
    implementation(files("libs/thryve_module_samsung_health_${thryve_sdk_version}.aar"))
    implementation(files("libs/thryve_module_hconnect_${thryve_sdk_version}.aar"))
    ...
    // dependencies for network and others
    implementation("com.google.code.gson:gson:$gson")
    implementation("androidx.legacy:legacy-support-v4:$legacySupport")
    implementation("io.reactivex.rxjava2:rxjava:$rxJava")
    implementation("io.reactivex.rxjava2:rxandroid:$rxAndroid")
    implementation("io.reactivex.rxjava2:rxkotlin:$rxKotlin")
    implementation("io.github.reactivecircus.cache4k:cache4k:$cache4k")

    // dependencies for background sync (Google Fit, Health Connect, Samsung Health)
    implementation("androidx.work:work-runtime:$work")
    implementation("androidx.work:work-runtime-ktx:$work")
    implementation("androidx.work:work-gcm:$work")

    implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle")
    implementation "androidx.lifecycle:lifecycle-process:$lifecycle"

    implementation("androidx.concurrent:concurrent-futures:$concurrentFutures")
    implementation("androidx.concurrent:concurrent-futures-ktx:$concurrentFutures")

    // dependencies for encryption/auth mechanisms
    implementation("androidx.security:security-crypto:$crypto")
    
    // dependencies for health connect
    implementation("androidx.health.connect:connect-client:$healthConnectClient")
    
    // dependency for compression
    implementation("com.github.luben:zstd-jni:$zstdVersion") {
        artifact { type = "aar" }
    }
    
    // dependency for new Samsung Data SDK 
    // skip this dependency if kotlin-parcelize is already added as a plugin(recommended)
    implementation ("org.jetbrains.kotlin:kotlin-parcelize-runtime:$kotlin")
    
   // dependencies for Observability Module
    implementation("io.opentelemetry:opentelemetry-api:$openTelemetryVersion")
    implementation("io.opentelemetry:opentelemetry-sdk:$openTelemetryVersion")
    implementation("io.opentelemetry.semconv:opentelemetry-semconv:$openTelemetrySemanticConventionsVersion")
    implementation("io.opentelemetry:opentelemetry-exporter-otlp:$openTelemetryVersion")// OpenTelemetry Exporters
    
  }
```

{% endtab %}

{% tab title="build.gradle" %}

```gradle
...
  ...
  android {
    ...
    compileOptions {
      sourceCompatibility 1.8
      targetCompatibility 1.8
    }
    kotlinOptions {
        jvmTarget = 1.8
    }
  }
  ...
  dependencies {
    ...
    implementation "androidx.appcompat:appcompat:$appCompat"
    implementation "androidx.core:core-ktx:$androidXCore"

    // Referenced in project's build.gradle
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version'

    implementation files("libs/thryve_core_sdk_${thryve_sdk_version}.aar")

    // CommonsModule import needed for other modules
    implementation files("libs/thryve_module_commons_${thryve_sdk_version}.aar")
    
    // Optional modules
    implementation files("libs/thryve_module_samsung_health_${thryve_sdk_version}.aar")
    implementation files("libs/thryve_module_hconnect_${thryve_sdk_version}.aar")
    ...
    // dependencies for network and others
    implementation "com.google.code.gson:gson:$gson"
    implementation "io.github.reactivecircus.cache4k:cache4k:$cache4k"
    implementation "androidx.legacy:legacy-support-v4:$legacySupport"

    implementation "io.reactivex.rxjava2:rxjava:$rxJava"
    implementation "io.reactivex.rxjava2:rxandroid:$rxAndroid"
    implementation "io.reactivex.rxjava2:rxkotlin:$rxKotlin"
    implementation "io.github.reactivecircus.cache4k:cache4k:$cache4k"

    // dependencies for background sync (Google Fit, Health Connect, Samsung Health)
    implementation "androidx.work:work-runtime:$work"
    implementation "androidx.work:work-runtime-ktx:$work"
    implementation "androidx.work:work-gcm:$work"

    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle"
    implementation "androidx.lifecycle:lifecycle-process:$lifecycle"

    implementation "androidx.concurrent:concurrent-futures:$concurrentFutures"
    implementation "androidx.concurrent:concurrent-futures-ktx:$concurrentFutures"

    // dependencies for Google Fit Native
    implementation "com.google.android.gms:play-services-auth:$playServicesAuth"
    implementation "com.google.android.gms:play-services-fitness:$playServicesFitness"

    // dependencies for encryption/auth mechanisms
    implementation "androidx.security:security-crypto:$crypto"
    
    // dependency for compression
    implementation("com.github.luben:zstd-jni:$zstdVersion") {
        artifact { type = "aar" }
    }
    
    // dependency for new Samsung Data SDK 
    // skip this dependency if kotlin-parcelize is already added as a plugin(recommended)
    implementation "org.jetbrains.kotlin:kotlin-parcelize-runtime:$kotlin"
    
    // dependency for compression
    implementation("com.github.luben:zstd-jni:${zstdVersion}") {
     artifact {
       type = "aar"
     }
    }
    
    // dependencies for Observability Module
    implementation "io.opentelemetry:opentelemetry-api:${openTelemetryVersion}"
    implementation "io.opentelemetry:opentelemetry-sdk:${openTelemetryVersion}"
    implementation "io.opentelemetry.semconv:opentelemetry-semconv:${openTelemetrySemanticConventionsVersion}"
    implementation "io.opentelemetry:opentelemetry-exporter-otlp:${openTelemetryVersion}"// OpenTelemetry Exporters
   
  }
```

{% endtab %}
{% endtabs %}

### Configure dependency versions

Keeping your dependency versions aligned with the supported versions of the Thryve Android SDK is crucial for ensuring compatibility and maintaining the stability of your application.&#x20;

Outdated or mismatched versions can lead to integration issues, such as runtime errors or unexpected behavior, which may hinder app performance and user experience.&#x20;

```groovy
buildscript {
    ext.androidXCore = "1.12.0"
    ext.appCompat = "1.6.1"
    ext.annotation ="1.7.1"
    ext.cache4k = "0.13.0"
    ext.crypto = "1.1.0-alpha06"
    ext.concurrentFutures = "1.1.0"
    ext.gradlePlugin = "8.6.0"
    ext.gson = "2.10.1"
    ext.kotlin = "1.9.23"
    ext.legacySupport = "1.0.0"
    ext.lifecycle = "2.7.0"
    ext.playServicesLocation = "21.2.0"
    ext.playServicesWearable = "18.1.0"
    ext.playServicesFitness = "21.1.0"
    ext.playServicesAuth = "21.0.0"
    ext.rxAndroid2 = "2.1.1"
    ext.rxJava2 = "2.2.21"
    ext.rxKotlin = "2.4.0"
    ext.sdkVersion = "5.2.0"
    ext.work = "2.9.0"
    ext.healthConnectClient = "1.1.0"
    ext.zstdVersion = "1.5.7-6"
    ext.openTelemetryVersion = "1.61.0"
    ext.openTelemetrySemanticConventionsVersion = "1.40.0"
    ...
}
```

{% hint style="info" %}
When updating Thryve SDK versions, always refer to the release changelog for documented dependency version updates.
{% endhint %}

## Custom WorkManager configuration

Thryve Android SDK relies on [Android WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager) for scheduled background task. To provide a custom implementation and rules for background tasks and overwrite Thryve SDK defaulty, implement `Configuration.Provider` and use `WorkManagerInitializer` in your Application class. See the Kotlin code example below for guidance. The code snippet changes the minimum logging level for your app, but the implementation can be further customized to your apps needs.

```kotlin
class App : Application, Configuration.Provider {
    override fun getWorkManagerConfiguration() =
            Configuration.Builder()
                    .setMinimumLoggingLevel(Log.VERBOSE)
                    .build()
```

{% hint style="info" %}
Thryve Android SDK uses WorkManager for background data synchronization for HealthConnect and Samsung Health.
{% endhint %}

## Health Connect project configuration

To integrate Health Connect with your Android app, utilize the `ThryveHealthConnect` module from the Thryve Android SDK. This module enables users to connect with Health Connect on their smartphones and allows your app to retrieve evaluated and aggregated data from various sources linked to Health Connect. You can integrate it by using [Thryve Maven Repository Dependency](/integrate-your-mobile-app/setup-thryve-sdk/android#using-thryve-repository-dependencies) or [AAR Libraries](https://docs.thryve.health/integrate-your-mobile-app/setup-thryve-sdk/pages/gd15Xn3eNpfQhy8TrHU5#id-2.-using-the-.aar-libraries) and updating your app's `build.gradle` file accordingly.

{% tabs %}
{% tab title="Thryve Maven Repo " %}

```kotlin
dependencies {
    ...
    api("com.thryve.sdk:hconnect:${thryve_sdk_version}")
}
```

{% endtab %}

{% tab title="AAR Libraries" %}

```kotlin
dependencies {
    ...
    implementation(files("libs/thryve_module_hconnect_5.2.1.aar"))
    implementation("androidx.health.connect:connect-client:1.1.0-rc02")
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
The Health Connect SDK supports Android 8 (API level 26) or higher, while the Health Connect app is only compatible with Android 9 (API level 28) or higher. This means that third-party apps can support users with Android 8, but only users with Android 9 or higher can use Health Connect.
{% endhint %}

### Declare Health Connect permissions

To utilize Health Connect, your application must declare all necessary permissions and provide a privacy policy activity for handling the `ACTION_SHOW_PERMISSIONS_RATIONALE` intent within the `AndroidManifest`. Pay attention to the differences in declarations for Android 14 versus older versions.&#x20;

```xml
<activity
    android:name=".PermissionsActivity"
    android:exported="true" >
    <intent-filter>
        <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
    </intent-filter>
    <meta-data android:name="health_permissions" android:resource="@array/health_permissions"/>
</activity>

<activity-alias
    android:name="AndroidURationaleActivity"
    android:exported="true"
    android:targetActivity=".PermissionsActivity"
    android:permission="android.permission.START_VIEW_PERMISSION_USAGE">
    <intent-filter>
        <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
        <category android:name="android.intent.category.HEALTH_PERMISSIONS" />
    </intent-filter>
</activity-alias>
```

Ensure that the declared policies align with the data types set in `ThryveHealthConnectConfig`. Also, remember to declare permissions for background sync and health data history when enabling these features.

```xml
<! -- Required for background sync -->
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
<! -- Required for health data history -->
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />

<! -- Required to request ACTIVECALORIESBURNED -->
<uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
<! -- Required to request BASALBODYTEMPERATURE -->
<uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
<uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
<uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
<uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
<uses-permission android:name="android.permission.health.READ_BODY_FAT" />
<uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
<uses-permission android:name="android.permission.health.READ_BODY_WATER_MASS" />
<uses-permission android:name="android.permission.health.READ_BONE_MASS" />
<uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS" />
<uses-permission android:name="android.permission.health.READ_EXERCISE" />
<uses-permission android:name="android.permission.health.READ_DISTANCE" />
<uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED" />
<uses-permission android:name="android.permission.health.READ_EXERCISE" />
<uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
<uses-permission android:name="android.permission.health.READ_HEIGHT" />
<uses-permission android:name="android.permission.health.READ_HYDRATION" />
<uses-permission android:name="android.permission.health.READ_INTERMENSTRUAL_BLEEDING" />
<uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" />
<uses-permission android:name="android.permission.health.READ_MENSTRUATION" />
<uses-permission android:name="android.permission.health.READ_NUTRITION" />
<uses-permission android:name="android.permission.health.READ_OVULATION_TEST" />
<uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
<uses-permission android:name="android.permission.health.READ_POWER" />
<uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
<uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
<uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY" />
<uses-permission android:name="android.permission.health.READ_SLEEP" />
<uses-permission android:name="android.permission.health.READ_SPEED" />
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
<uses-permission android:name="android.permission.health.READ_VO2_MAX" />
<uses-permission android:name="android.permission.health.READ_WEIGHT" />
<uses-permission android:name="android.permission.health.READ_MINDFULNESS" />
<uses-sdk tools:overrideLibrary="androidx.health.connect.client" />
```

## Samsung Health project configuration

You must suppress warnings after adding the `ThryveSamsungHealth` module, include `-dontwarn com.samsung.**` in your `proguard-rules` file.

{% hint style="success" %}
Read [the ThryveBLE Set-up guide](https://open-2v.gitbook.com/url/preview/site_WRtC1/~/revisions/8MPw4Z6n3dOec6crWrLf/integrate-your-mobile-app/connect-bluetooth-devices#set-up) for additional information on how to set-up the ThryveBLE module
{% endhint %}


# React Native

Thryve provides React Native SDK and modules that are using the Thryve native SDKs.

The React Native wrapper for the native SDKs supports all functionalities of the native SDKs unless stated differently.

{% hint style="info" %}
Starting from version 5.2.0, the Thryve React Native SDK, supports integration via the [new Samsung Health Data for Android](https://developer.samsung.com/health/data/overview.html) exclusively. Read more on the [Thryve Samsung Health module](/thryve-data-sources/samsung-health)
{% endhint %}

## Configuration of projects

To integrate the Thryve React Native SDK into a bare React Native, follow the steps below for installing the packages. If you are using React Native Expo, please refer to the [dedicated page](/integrate-your-mobile-app/setup-thryve-sdk/react-native/react-native-expo).

### Install packages

Download the `.tgz` package files provided by Thryve and place them in a directory inside your project (e.g. `./packages/`). Then install the core SDK and the individual module packages for the integrations your app uses.

```sh
# Install the core SDK
npm install ./packages/thryve-react-native-sdk-<version>.tgz

# Install only the modules you need
npm install ./packages/thryve-react-native-hconnect-module-<version>.tgz   # Health Connect (Android only)
npm install ./packages/thryve-react-native-samsung-health-module-<version>.tgz    # Samsung Health (Android only)
npm install ./packages/thryve-react-native-apple-health-module-<version>.tgz # Apple HealthKit (iOS only)
npm install ./packages/thryve-react-native-shenai-module-<version>.tgz     # ShenAI (Android & iOS)
```

Replace `<version>` with the version number of the package files you received (e.g. `5.2.1`). After installation your `package.json` dependencies will reference the local `.tgz` paths:

```json
"dependencies": {
  "@thryve/react-native-sdk": "./packages/thryve-react-native-sdk-5.2.1.tgz",
  "@thryve/react-native-hconnect-module": "./packages/thryve-react-native-hconnect-module-5.2.1.tgz",
  "@thryve/react-native-samsung-health-module": "./packages/thryve-react-native-samsung-health-module-5.2.1.tgz",
  "@thryve/react-native-apple-health-module": "./packages/thryve-react-native-apple-health-module-5.2.1.tgz",
  "@thryve/react-native-shenai-module": "./packages/thryve-react-native-shenai-module-5.2.1.tgz"
}
```

### Setup Android configuration

#### Configure Nexus Maven repository (`android/settings.gradle`)

Add the Thryve Nexus repository so Gradle can resolve the native Android dependencies. Credentials are read from `android/local.properties` first, falling back to environment variables — keep them out of source control.

```groovy
// android/settings.gradle
def localProps = new Properties()
def localPropsFile = new File(settingsDir, 'local.properties')
if (localPropsFile.exists()) { localPropsFile.withInputStream { localProps.load(it) } }
def resolvedUser = localProps['THRYVE_NEXUS_USERNAME'] ?: System.getenv('THRYVE_NEXUS_USERNAME') ?: ""
def resolvedPass = localProps['THRYVE_NEXUS_PASSWORD'] ?: System.getenv('THRYVE_NEXUS_PASSWORD') ?: ""

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        maven {
            url "https://nexus.external.thryve.de/repository/releases/"
            credentials {
                username = resolvedUser
                password = resolvedPass
            }
            content {
                includeGroupByRegex "com\\.thryve.*"
            }
        }
    }
}
```

Add your credentials to `android/local.properties` (this file should be in `.gitignore`):

```
THRYVE_NEXUS_USERNAME=YOUR_SDK_CREDENTIAL_USER
THRYVE_NEXUS_PASSWORD=YOUR_SDK_CREDENTIAL_PASSWORD
```

#### Add Thryve SDK dependencies (`android/app/build.gradle`)

Add the required runtime dependencies:

```groovy
dependencies {
    implementation("androidx.security:security-crypto:1.1.0-alpha06")
    implementation("io.reactivex.rxjava2:rxjava:2.2.21")
    implementation("io.reactivex.rxjava2:rxandroid:2.1.1")
    // ... your other dependencies
}
```

#### Define Android SDK versions (`android/build.gradle`)

Ensure your project-level `build.gradle` targets the required SDK versions:

```groovy
ext {
    minSdkVersion = 26
    compileSdkVersion = 36
    targetSdkVersion = 36
    buildToolsVersion = "36.0.0"
}
```

#### Configure project when using Health Connect

{% hint style="info" %}
For more details exceeding below explanations, please refer to the [sample code](https://git.thryve.de/thryve/react-native/-/tree/main) demonstrating the SDK configuration.
{% endhint %}

**Android Manifest**

When using Health Connect you need to declare the that your app will query HealthConnect and display the permission rational as well as declare the data types you intend to use. Do this in your `android/app/src/main/AndroidManifest.xml` .

{% hint style="warning" %}
Declare only the data type your app actually reads and needs — extensive permission requests require justification during Google Play Store review. Every data type you pass to `start()` must have its corresponding permission declared here, otherwise Health Connect will reject the call at runtime (error 90005).
{% endhint %}

Import `HEALTH_CONNECT_PERMISSIONS` from `@thryve/react-native-sdk/permissions` as a reference for all available permission strings.

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
    <uses-permission android:name="android.permission.health.READ_STEPS"/>
    <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED"/>
    <uses-permission android:name="android.permission.health.READ_SLEEP"/>
    <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE"/>
    <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE"/>
    <uses-permission android:name="android.permission.health.READ_WEIGHT"/>
    <uses-permission android:name="android.permission.health.READ_HEIGHT"/>
    <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION"/>
    <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE"/>
    <!-- Add further Health Connect permissions your app needs -->

    <uses-sdk tools:overrideLibrary="androidx.health.connect.client"/>

    <queries>
        <package android:name="com.google.android.apps.healthdata"/>
    </queries>

    <application ...>
        <!-- Health Connect rationale activity — required for health-connect module -->
        <activity
            android:name=".PermissionsActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
            </intent-filter>
            <meta-data
                android:name="health_permissions"
                android:resource="@array/health_permissions"/>
        </activity>
        <activity-alias
            android:name="AndroidURationaleActivity"
            android:exported="true"
            android:targetActivity=".PermissionsActivity"
            android:permission="android.permission.START_VIEW_PERMISSION_USAGE">
            <intent-filter>
                <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
                <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
            </intent-filter>
        </activity-alias>
        <!-- ... rest of application -->
    </application>
</manifest>

```

**Health Permission resource**

List the same Health Connect permissions that you declared in the manifest in `android/app/src/main/res/values/health_permissions.xml` .

```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
  <array name="health_permissions">
    <item>android.permission.health.READ_HEART_RATE</item>
    <item>android.permission.health.READ_STEPS</item>
    <item>android.permission.health.READ_ACTIVE_CALORIES_BURNED</item>
    <item>android.permission.health.READ_SLEEP</item>
    <item>android.permission.health.READ_BLOOD_GLUCOSE</item>
    <item>android.permission.health.READ_BLOOD_PRESSURE</item>
    <item>android.permission.health.READ_WEIGHT</item>
    <item>android.permission.health.READ_HEIGHT</item>
    <item>android.permission.health.READ_OXYGEN_SATURATION</item>
    <item>android.permission.health.READ_BODY_TEMPERATURE</item>
    <!-- Mirror the permissions declared in AndroidManifest.xml -->
  </array>
</resources>
```

**Permission activity**

Additionally you need to create this file in your app's package directory (`android/app/src/main/java/<your.package>/PermissionsActivity.kt` ):

```kotlin
package your.app.package

import androidx.activity.ComponentActivity

class PermissionsActivity : ComponentActivity()
```

{% hint style="info" %}
Replace `your.app.package` in above path with your actual application package name (e.g. `com.example.myapp`).
{% endhint %}

#### Configure project when using Samsung Health

When allowing users to connect to Samsung Health ensure to declare queries in your `android/app/src/main/AndroidManifest.xml` .

```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">
          
    <queries>
        <!-- Samsung Health queries — include only if using samsung-health module -->
        <package android:name="com.samsung.health"/>
        <package android:name="com.sec.android.app.shealth"/>
        
        <!-- ... rest of queries, see section above for Health Connect -->
    </queries>
    
    <!-- ... rest of manifest -->
</manifest>
```

### Setup iOS configuration

#### Configure the Podfile&#x20;

Add the Thryve CocoaPods source in your `ios/Podfile` and include only the subspecs your app uses:

```ruby
source 'https://git.thryve.de/thryve/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'

# ... rest of Podfile setup ...

target 'YourAppTarget' do
  config = use_native_modules!

  # Include only the subspecs your app uses: 'AppleHealth', 'ShenAI'
  pod 'RNThryveSDKModule', :path => '../node_modules/@thryve/react-native-sdk',
    :subspecs => ['AppleHealth', 'ShenAI']

  use_react_native!(
    :path => config[:reactNativePath],
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )
end
```

After you have added the configuration, ensure to run:

```sh
cd ios && pod install && cd ..
```

#### Configure the Info.plist&#x20;

Add the required usage descriptions in `ios/<YourApp>/Info.plist` :

<pre class="language-xml"><code class="lang-xml">&#x3C;!-- Required for Apple Health only -->
<strong>&#x3C;key>NSHealthShareUsageDescription&#x3C;/key>
</strong>&#x3C;string>This app needs permission to share your health data&#x3C;/string>
&#x3C;key>NSHealthUpdateUsageDescription&#x3C;/key>
&#x3C;string>This app needs permission to update your health data&#x3C;/string>
&#x3C;!-- Required for ShenAI only -->
&#x3C;key>NSCameraUsageDescription&#x3C;/key>
&#x3C;string>Camera is required for ShenAI facial health measurements&#x3C;/string>
&#x3C;!-- Required for Apple Health background delivery -->
&#x3C;key>UIBackgroundModes&#x3C;/key>
&#x3C;array>
  &#x3C;string>fetch&#x3C;/string>
&#x3C;/array>
</code></pre>

#### Configure the required entitlements

When using Apple Health add the following HealthKit entitlements in your `ios/<YourApp>/<YourApp>.entitlements` .

```xml
<key>com.apple.developer.healthkit</key>
<true/>
<key>com.apple.developer.healthkit.background-delivery</key>
<true/>
```

### Common issues

#### iOS build error: `Typedef redefinition with different types` in `RCT-Folly/folly/portability/Time.h`

Some users have reported the following error when building for iOS:

```
RCT-Folly/folly/portability/Time.h:52:17: Typedef redefinition with different types
('uint8_t' (aka 'unsigned char') vs 'enum clockid_t')
```

**Option 1:** Add the following `sed` command to your `post_install` block in `ios/Podfile`:

```ruby
post_install do |installer|
  # ...existing post_install steps...
  sed -i -e $'s/__IPHONE_10_0/__IPHONE_13_0/' Pods/RCT-Folly/folly/portability/Time.h
end
```

**Option 2:** If the above does not resolve the issue, open `ios/Pods/RCT-Folly/folly/portability/Time.h` and comment out the offending line:

```c
// typedef uint8_t clockid_t;
```

## Migrating to React Native SDK 5.2.0

### Breaking changes

#### Samsung Health data types replaced

The entire `ThryveSamsungHealthDataType` enum has been replaced to align with the new Samsung Health data model. All previous values are removed with no backwards-compatible aliases.

**You must update every reference** in your app to use the new values listed in the [ThryveSamsungHealthDataType reference](https://docs.thryve.health/thryve-data-sources/samsung-health#step-2-use-the-new-configuration-model).


# React Native Expo

Thryve React Native SDK supports Expo projects. The SDK will set-up all the native project configurations automatically for both Android and iOS after adding the `@thryve/react-native-sdk` plugin to your `app.config.js` - no additional plugins or manual native file changes are required.

{% hint style="info" %}
The plugin handles the Nexus Maven repository, Gradle SDK versions, Android manifest permissions, Health Connect infrastructure, iOS entitlements, and privacy manifests automatically. No manual native file changes are needed.
{% endhint %}

Please refer to the [React Native set-up](/integrate-your-mobile-app/setup-thryve-sdk/react-native#install-packages) for guidance on installing packages before proceeding with adding the following configuration:

```js
// app.config.js
module.exports = {
  expo: {
    ios: {
      infoPlist: {
        NSHealthShareUsageDescription: 'Allow to share your health data',
        NSHealthUpdateUsageDescription: 'Allow to update your health data',
        NSCameraUsageDescription: 'Camera is required for ShenAI facial health measurements', // Required for ShenAI only
        UIBackgroundModes: ['fetch'],
      },
    },
    plugins: [
      [
        '@thryve/react-native-sdk',
        {
          nexusUsername: process.env.THRYVE_NEXUS_USERNAME,
          nexusPassword: process.env.THRYVE_NEXUS_PASSWORD,
          android: {
            // Include only the modules your app uses
            modules: ['health-connect', 'samsung-health'],
            // Omit `permissions` entirely to include all permissions for the selected modules.
            // Provide it only when you want a subset — but every data type you pass to
            // start() must have its permission listed here, otherwise Health Connect will
            // reject the call at runtime (error 90005).
            // Unused permissions require justification during Google Play Store review.
            permissions: [
              'android.permission.health.READ_HEART_RATE',
              'android.permission.health.READ_STEPS',
              'android.permission.health.READ_ACTIVE_CALORIES_BURNED',
              'android.permission.health.READ_SLEEP',
              'android.permission.health.READ_BLOOD_GLUCOSE',
              'android.permission.health.READ_BLOOD_PRESSURE',
              'android.permission.health.READ_WEIGHT',
              'android.permission.health.READ_HEIGHT',
              'android.permission.health.READ_OXYGEN_SATURATION',
              'android.permission.health.READ_BODY_TEMPERATURE',
              // Add further permissions your app needs.
              // All available strings are in HEALTH_CONNECT_PERMISSIONS:
              // const { HEALTH_CONNECT_PERMISSIONS } = require('@thryve/react-native-sdk/permissions');
            ],
          },
          // Include only the iOS pods your app uses
          // Apple Health is configured via ios[] and infoPlist above
          ios: ['ThryveCore', 'ThryveAppleHealth', 'ThryveShenAI'],
        },
      ],
    ],
  },
};
```


# Flutter

Thryve provides Flutter SDK and modules that are using the Thryve native SDKs.

The Flutter wrapper for the native SDKs supports all functionalities of the native SDKs unless stated differently.

{% hint style="info" %}
Starting from version 5.2.0, the Thryve Flutter SDK, supports integration via the [new Samsung Health Data for Android](https://developer.samsung.com/health/data/overview.html) exclusively. Read more on the [Thryve Samsung Health module](/thryve-data-sources/samsung-health)
{% endhint %}

## Configuration of  projects

The Flutter SDK supports the development of iOS and Android applications.  Follow the guide below to configure your project.<br>

* Create a directory, `plugin` inside the project's root directory
* Copy the [Thryve Flutter SDK plugins](https://git.thryve.de/thryve/flutter/-/tree/main/plugin) (applicable to your project) into the newly created `plugin` directory of the project.
* In your project's `pubspec.yaml`, ensure the `environment` `sdk` property is `>=3.1.0 <4.0.0`&#x20;
* In your project's `pubspec.yaml`, add the Thryve Flutter SDK dependencies applicable to your project in the `dependencies:` block

{% hint style="danger" %}
Starting with version 5.2.0, the Samsung Health plugin in the Thryve Flutter SDK has been renamed from `module_shealth` to `module_samsung_health`.

To ensure compatibility, update all references in your codebase to use the new module name. Refer to the sample implementation below for guidance.
{% endhint %}

```yaml
...
dependencies:
  flutter:
    sdk: flutter
    
  thryve_sdk:
    path: plugin/thryve_sdk // required for all integrations
  module_samsung_health:
    path: plugin/module_samsung_health // optional, required for Samsung Health integration
  module_health_connect:
    path: plugin/module_health_connect // optional, required for Health Connect integration
  module_apple_health:
    path: plugin/module_apple_health // optional, required for Apple Healthkit integration
  module_shen_ai:
    path: plugin/module_shen_ai // optional, required for ShenAI integration
...
```

* Add the Thryve Pods Spec source to `Podfile` and/or Android dependencies repository to `build.gradle`&#x20;

{% tabs %}
{% tab title="iOS" %}
Add the Thryve Pods spec source the the Podfile

```ruby
platform :ios, '13.0'

source 'https://git.thryve.de/thryve/Specs'
...
```

{% endtab %}

{% tab title="Android" %}
Add the following to the project's `android/build.gradle`&#x20;

<pre class="language-gradle"><code class="lang-gradle"><strong>...
</strong><strong>allprojects {
</strong>    repositories {
        google()
        mavenCentral()
        ....
        //Thryve Maven Repository
        maven {
        url "https://git.thryve.de/api/v4/projects/12/packages/maven"
        credentials {
            username = thryveUsername // the Thryve git token name
            password = thryvePassword // the Thryve git token
        }
        ...
}
...
</code></pre>

{% endtab %}
{% endtabs %}

{% hint style="info" %}
For more details refer to the [sample code](https://git.thryve.de/thryve/flutter/-/tree/main) demonstrating the SDK configuration.
{% endhint %}

### Migrating to Flutter SDK 5.2.0

### Breaking Changes (5.2.0)

#### Samsung Health

{% hint style="danger" %}
Starting with version 5.2.0, the Samsung Health plugin in the Thryve Flutter SDK has been renamed from `module_shealth` to `module_samsung_health`.

To ensure compatibility, update all references in your codebase to use the new module name.&#x20;
{% endhint %}

**Samsung Health data types replaced**

{% hint style="warning" %}
Starting with version 5.2.0, `SHealthDataType` enum has been renamed  to `ThryveSamsungHealthDataType`.

To ensure compatibility, update all references in your codebase to use the new `ThryveSamsungHealthDataType` .
{% endhint %}

The entire `ThryveSamsungHealthDataType` enum has been replaced to align with the new Samsung Health data model. All previous values are removed with no backwards-compatible aliases.

**You must update every reference** in your app to use the new values listed in the [ThryveSamsungHealthDataType reference](https://docs.thryve.health/thryve-data-sources/samsung-health#step-2-use-the-new-configuration-model).

#### **Health Connect `HealthConnectDataType` renamed**

{% hint style="danger" %}
Starting with version 5.2.0, `HealthConnectDataType` enum has been renamed  to `ThryveHealthConnectDataType`.

To ensure compatibility, update all references in your codebase to use the new `ThryveHealthConnectDataType` .
{% endhint %}

#### **Apple Health `HKConnectorType` renamed**

{% hint style="danger" %}
Starting with version 5.2.0, `HKConnectorType` enum has been renamed  to `ThryveHealthConnectDataType`.

To ensure compatibility, update all references in your codebase to use the new `ThryveAppleHealthDataType` .
{% endhint %}


# Connect data sources

Integration of Thryve SDK takes barely more than a few minutes to connect data sources up and running including native data sources.

Assuming you have set up your mobile app project as outlined and have added the Thryve SDK via dependency management or manually via framework files, you have everything to get going to get your users to connect their data source with your application.

<figure><img src="/files/qzBiLT1CzGy5kusP0dpL" alt="" width="188"><figcaption><p>Thryve Connection Widget makes it super simple to allow users to connect theiir data sources</p></figcaption></figure>

All data connections and data stored at Thryve are always linked to a Thryve user. A Thryve user will be automatically created or an existing user will be retrieved when initializing the SDK.

## Initialize the Thryve SDK&#x20;

Create the `ThryveSDK` instance using `getOrCreate` and set up the `ThryveSDKConfig` object according to your needs. Initializing  `ThryveSDK`  will automatically create a new Thryve user or get an existing Thryve user based on `endUserAlias`.

{% tabs %}
{% tab title="iOS" %}

<pre class="language-swift"><code class="lang-swift"><strong>import ThryveCore
</strong>import ThryveCommons
import ThryveObservability
import ThryveAppleHealth
import ThryveShenAI
import ThryveBLE

let appleHealthConfig = ThryveAppleHealthConfig(
    dataTypes: ThryveAppleHealthDataType.allConnectorTypes,
    enableBackgroundSync: true // `true` by default
),

let thryveSDKConfig = ThryveSDKConfig(
    authId: "AUTH_ID",
    authSecret: "AUTH_SECRET",
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    endUserId: nil, 
    locale: "de",
    configs: [appleHealthConfig, shenAIConfig, bleConfig],
    observability: ObservabilityConfig(tracingEnabled: true, crashReportingEnabled: true)
)
        
await ThryveSDK.getOrCreate(thryveSDKConfig).getUserInformation()

// Optionally, when ThryveSDK is initialized from a non-async context (AppDelegate, legacy code, etc.), 
// it is recommended to use the getOrCreate(...) callback to know when the SDK is ready.

ThryveSDK.getOrCreate(thryveSDKConfig) { initResult in
    if initResult.successful {
        Logger.i("ThryveSDK ready, you can start calling API methods")
    } else if let error = initResult.errors?.first {
        Logger.e("ThryveSDK init failed: \(error.errorMessage ?? "Unknown error")")
    }
} 
</code></pre>

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk
import com.thryve.sdk.commons
import com.thryve.sdk.healthConnect
import com.thryve.sdk.samsungHealth
import com.thryve.sdk.shenAI
import com.thryve.sdk.ble

val healthConnectConfig = ThryveHealthConnectConfig(
        dataTypes = ThryveHealthConnectDataType.entries.toList(),
        enableBackgroundSync = true,
        enableReadHealthDataHistory = true
    )

val samsungHealthConfig = ThryveSamsungHealthConfig(
        dataTypes = ThryveSamsungHealthDataType.entries.toList(),
        enableBackgroundSync = true
    )
   
val shenAIConfig = ThryveShenAIConfig(
    apiKey = "SHEN_AI_API_KEY",
    eventsListener = object : ThryveShenAIEventListener {
        override fun onEvent(event: ThryveShenAIEvent) {
            when (event) {
                ThryveShenAIEvent.MEASUREMENT_FINISHED -> { /* Shen AI measurement has finished and is about to be uploaded */}
                ThryveShenAIEvent.MEASUREMENT_FAILED -> { /* Shen AI measurement has failed - handle failure */}
                ThryveShenAIEvent.DATA_UPLOAD_FINISHED -> { /* Shen AI has finished uploading data */}
                ThryveShenAIEvent.DATA_UPLOAD_FAILED -> { /* Shen AI has failed uploading data */}
                ThryveShenAIEvent.USER_SUMMARY_FINISHED -> { /* The Shen AI flow has been completed */ }
            }
        }
    }
 )
    
val thryveSDKConfig = ThryveSDKConfig(
    authId = "ASSIGNED_AUTH_ID",
    authSecret = "ASSIGNED_AUTH_SECRET",
    endUserAlias = "XXXXXXXXXXX",
    endUserId = null, 
    locale = "de",
    healthConnectConfig = healthConnectConfig,
    samsungHealthConfig = samsungHealthConfig,
    shenAIConfig = shenAIConfig,
    bleConfig = bleConfig
)
                 
val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context)

/**Android SDK 5.0.5 introduced an optional callback to communicate the status 
  of internal processes of getOrCreate. ThryveSDK instance can now be created 
  with a callback as shown in the sample code below.  
**/
val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context) { thryveResponse ->
       if(thryveResponse.successful){
           //ThyveSDK initialization processes completed successfully
       } else {
           // ThryveSDK initalization process failed. process the ThryveErrors for the specific reason.
           thryveResponse.errors.map { thryveError -> Logger.e(TAG){" getOrCreate ThryveError in onCreate function $thryveError"} }
       }
  }
```

{% endtab %}

{% tab title="ReactNative" %}

```javascript
import {
  Source,
  ThryveSamsungHealthDataType,
  ThryveHealthConnectDataType,
  ThryveAppleHealthDataType,
  ThryveSDK
} from '@thryve/react-native-sdk';

const samsungHealthDataTypes = Object.values(ThryveSamsungHealthDataType);
const appleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
const healthConnectDataTypes = Object.values(ThryveHealthConnectDataType);

export default (authId = AUTH_ID, authSecret = AUTH_SECRET) => {
  const thryveSDK = new ThryveSDK();
  const thryveSDKConfig = {
    authId: appId,
    authSecret: appSecret,
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    locale: 'en',
    configs: [
      {
        source: Source.APPLE,
        dataTypes: appleHealthDataTypes,
      },
      {
        source: Source.HEALTH_CONNECT,
        dataTypes: healthConnectDataTypes,
        enableBackgroundSync: true,
        enableReadHealthDataHistory: true,
      },
      {
        source: Source.SAMSUNG,
        dataTypes: samsungHealthDataTypes,
      },
      {
        source: Source.SHENAI,
        apiKey: "SHEN_AI_API_KEY",
      },
    ],
  };
  thryveSDK.getOrCreate(thryveSDKConfig)
    .then(response => {
      if (response.errors && response.errors.length > 0) {
        console.error('Thryve init error:', response.errors[0].message);
      }
    })
    .catch(e => {
      console.error('Thryve init threw:', e);
    });
  return thryveSDK;

```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:module_apple_health/module_apple_health.dart';
import 'package:module_health_connect/module_health_connect.dart';
import 'package:module_samsung_health/module_samsung_health.dart';
import 'package:module_shen_ai/module_shen_ai.dart';

import 'package:thryve_sdk/thryve_sdk.dart';

final class ThryvePageBloc {
  late ThryveSDK _thryveSDK;
  
  ThryvePageBloc() {
    _thryveSDK = injector<ThryveSDK>();
    _thryveSDK.init(
      ThryveSDKConfig(
          authId: 'ASSIGNED_AUTH_ID',
          authSecret: 'ASSIGNED_AUTH_SECRET',
          endUserAlias: 'XXXXXXXXXXX',
          locale: 'en',
          healthConnectConfig: ThryveHealthConnectConfig(
            dataTypes: ThryveHealthConnectDataType.values,
            enableBackgroundSync: true,
            enableReadHealthDataHistory: true,
          ),
          samsungHealthConfig: ThryveSamsungHealthConfig(
            dataTypes: ThryveSamsungHealthDataType.values,
            enableBackgroundSync: true,
          ),
          appleHealthConnectConfig: ThryveAppleHealthConfig(
            dataTypes: ThryveAppleHealthDataType.values,
          ),
          shenAIConfig: ThryveShenAIConfig(apiKey: 'SHEN_AI_API_KEY')),
    );
  }
  
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
There are two versions of `ThryveSDK` singleton initialization. Synchronous `ThryveSDK.getOrCreate()` and asynchronous `await ThryveSDK.getOrCreate()`. It is recommended to use async version when providing new config using `ThryveSDK.getOrCreate(newConfig)` to ensure `ThryveSDK` awaits user refresh safely
{% endhint %}

<table><thead><tr><th width="218">Parameter</th><th width="381">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>context</code></td><td>default Android context <em>(only relevant for Android integration)</em></td><td>yes</td></tr><tr><td><code>authId</code></td><td>Credentials to authorize your app with the Thryve backend</td><td>yes</td></tr><tr><td><code>authSecret</code></td><td>Credentials to authorize your app with the Thryve backend</td><td>yes</td></tr></tbody></table>

{% hint style="warning" %} <mark style="color:$warning;">`ThryveSDK.getOrCreate`</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">throws a</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">`fatalError`</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">and an</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">`InitializationException`</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">on iOS and Android respectively, that must be handled in your code. Starting from Android SDK 5.0.5,</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">`InitializationException`</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">is handled internally in the SDK and communicated in a</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">`ThryveResponse`</mark> <mark style="color:$warning;"></mark><mark style="color:$warning;">to the host application via an optional callback</mark>
{% endhint %}

## Create a Thryve user

The SDK will automatically take care of creating new users. It will also take care of managing existing users when endUserAlias is set. Therefore we highly encourage usage of endUserAlias as otherwise you will need to manually manage and set the endUserId for existing users. You can retrieve the `endUserId` of the current user using `getEndUserId` method.

<table><thead><tr><th width="218">Parameter</th><th width="381">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>endUserAlias</code></td><td><p>Unique identifier for your user that can be set optionally by you. Make sure to set a secure, non-predictable, unique identifier without personal identifiable information. </p><p></p><p>Maximum length is 80 characters, only alphanumeric characters and dash (<code>-</code>) are supported.</p></td><td>no</td></tr><tr><td><code>endUserId</code></td><td>Identifier used to authenticate your end-user with Thryve in network requests. Only set if you don't use the <code>endUserAlias</code> and want to initialize the SDK for an existing user.</td><td>no</td></tr></tbody></table>

{% hint style="warning" %}
With the introduction of Thryve SDK 5.0.0 former `accessToken` has been renamed to `endUserId` and `partnerUserId` has been renamed to `endUserAlias` for improved clarity. Functionality of parameters has not changed.
{% endhint %}

{% hint style="danger" %}
To avoid iOS SDK race conditions on `endUserId` refresh, please, use async version of `ThryveSDK.getOrCreate()` singleton init. Additionally, iOS SDK provides  `.endUserIdDidUpdate` notification implementation to catch `endUserId` updates if needed: `NotificationCenter.default.addObserver(forName: .endUserIdDidUpdate, ...)`
{% endhint %}

### Set user language

The configured language is used in the UI provided by Thryve, like the Thryve Connection Widget. If not manually set by your app, the SDK will use the language set on the device.

<table><thead><tr><th width="99.75390625">Parameter</th><th width="547.6953125">Description</th><th width="100.40625">Mandatory</th></tr></thead><tbody><tr><td><code>locale</code></td><td>Manually set the language code following <a href="https://www.loc.gov/standards/iso639-2/php/code_list.php">ISO 639-1</a> to set the language that will be used on UI elements, e.g. the Thryve Widget. If empty the SDK will get the phone's language. </td><td>no</td></tr></tbody></table>

## Display the Thryve Connection Widget

Thryve Connection Widget allows your end users to connect and disconnect all enabled data sources configured for your application without you needing to implement any views or logics.

<figure><img src="/files/qzBiLT1CzGy5kusP0dpL" alt="" width="188"><figcaption><p>Thryve Connection Widget makes it super simple to allow users to connect theiir data sources</p></figcaption></figure>

The Thryve Connection Widget will be launched as a web-view and can be implemented within any view of your application by using  `ThryveDataSourceConnectionWidget`.

{% tabs %}
{% tab title="iOS" %}

```swift
struct DataSourceConnectionView: View {
    var body: some View {
        VStack(spacing: 16.0) {
            // 1. Option without a response
            ThryveDataSourceConnectionWidget()
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .clipped()
                
            // 2. Example using callback closure
            ThryveDataSourceConnectionWidget { response in
                Logger.i {
                    "Data source connection response: success=\(response.successful), data=\(response.data ?? false)"
                }
                if let error = response.errors?.first {
                    Logger.e { "Connection error: \(error.errorMessage ?? "")" }
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .clipped()
            
            // 3. Or using SwiftUI binding
            ThryveDataSourceConnectionWidget(responseBinding: $connectionResponse)
                 .frame(maxWidth: .infinity, maxHeight: .infinity)
                 .clipped()
                 .onChange(of: connectionResponse) { response in
                     if let response = response {
                         Logger.i { "Binding response: \(response.successful)" }
                     }
                 }
        }
        .navigationBarTitle("Data Sources", displayMode: .inline)
    }
}

@ViewBuilder
private func mainView() -> some View {
        VStack(alignment: .center, spacing: 16.0) {
             NavigationLink(
                  destination: DataSourceConnectionView()
             ) {
                  Text("Connection Widget")
             }
            .modifier(ButtonModifier())
        }
}
        
```

{% endtab %}

{% tab title="Android" %}

```kotlin
//OPTION 1: adding ThryveDataSourceConnectionWidget in code.
lifecycleScope.launch {
    try {
        val view = ThryveDataSourceConnectionWidget.build(activity, "showthryve://com.thryve.sample")
        withContext(Dispatchers.Main.immediate) {
            binding.dataSourceWidgetLayout.addView(view)
        }
    } catch (e: Exception) {
        withContext(Dispatchers.Main.immediate) {
            Toast.makeText(activity, "Unable to load data source connection widget: ${e.message}", Toast.LENGTH_LONG).show()
        }
    }
}

//OPTION 2: adding ThryveDataSourceConnectionWidget in your layout
<LinearLayout
  android:id="@+id/widget_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">

   <com.thryve.sdk.widget.ThryveDataSourceConnectionLayout
        android:id="@+id/thryve_data_source_widget_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:redirectURL="showthryve://com.thryve.sample"
        android:orientation="vertical"
         android:padding="5dp" />

</LinearLayout>

// Using Android Compose
AndroidView(
    factory = { ctx ->
        try {
            ThryveDataSourceConnectionWidget.build(
                activity = ctx as ComponentActivity,
                redirectUrl = "showthryve://com.thryve.sample",
            )
        } catch (e: Exception) {
            TextView(ctx).apply {
                text = "Unable to load data source connection widget: ${e.message}"
            }
        }
    }
)
```

{% endtab %}

{% tab title="ReactNative" %}
{% code overflow="wrap" %}

```javascript
import React from 'react';
import {ScrollView} from 'react-native';
import {ThryveDataSourceConnectionView} from '@thryve/react-native-sdk';

const DataSourceConnectionWidgetScreen = () => {
  return (
      <ScrollView>
        <ThryveDataSourceConnectionView redirectURL=""  height={'100%' } width={'100%' }/>
      </ScrollView>
  );
};


export default DataSourceConnectionWidgetScreen;
```

{% endcode %}
{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:thryve_sdk/thryve_sdk.dart';

@RoutePage<void>()
class ThryveDataSourceConnectionPage extends StatefulWidget {
  const ThryveDataSourceConnectionPage({
    super.key,
    this.redirectUrl = 'showthryve://com.thryve.sample',
  });

  final String redirectUrl;

  @override
  State<ThryveDataSourceConnectionPage> createState() => _ThryveDataSourceConnectionPageState();
}

class _ThryveDataSourceConnectionPageState extends State<ThryveDataSourceConnectionPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Thryve Data Source Connection'),
      ),
      body: ThryveDataSourceConnectionWidget(redirectUrl: widget.redirectUrl),
    );
  }
}

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Apple Health, Health Connect, and Samsung Health will be shown in the Thryve Connection Widget only if their respective modules are imported and the data source is available on the device.
{% endhint %}

| Parameter     | Description                                                                                                                                                                                                                                                  | Mandatory                                                            |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `redirectURL` | To automatically redirect users after connection or disconnection of web data sources, we recommend configuring a deep link. The specified redirectURI should link the user to the screen where Thryve Connection Widget is embedded within your application | no. applicable to only native, react native and Flutter Android SDKs |

{% hint style="info" %}
For details on configuring the SDK modules for [ThryveAppleHealth, ThryveHealthConnect,ThryveSamsungHealth](/integrate-your-mobile-app/apple-health-health-connect-and-samsung-health#configuration), [ThryveBLE](/integrate-your-mobile-app/direct-bluetooth-device-connection#configure-the-thryveble-module) and [ThryveShenAI](/integrate-your-mobile-app/camera-based-health-data-recording#configure-the-sdk-module) modules, refer to their respective documentation pages.
{% endhint %}


# Build your custom data source connection screen

You want full control over your apps user experience? No problem, the SDK provides all the tools you need to create a powerful UI for data source connections.

<figure><img src="/files/NyBhDC5gLTlMZnvImncA" alt="" width="188"><figcaption><p>If your UX requires a custom data source connection flow, you can easily build such screen using the Thryve SDK helper methods.</p></figcaption></figure>

## Connect/disconnect web data sources

There are two web links you need to allow your users to connect and disconnect their web data sources, respectively. To obtain these, use the `getConnectDataSourceUrl` and `getRevokeDataSourceUrl` methods of the SDK and specify the `dataSourceId` for the data source, you want to connect/disconnect.&#x20;

The following example shows usage of `getConnectDataSourceUrl`  and `getRevokeDataSourceUrl`  for connection/disconnection of Fitbit:

{% tabs %}
{% tab title="iOS" %}

```swift
import UIKit
import ThryveSDK
import ThryveCommons

/**
 Async function that fetches the connect‐URL for Fitbit via ThryveSDK and opens it in the default browser.

 - Data Source ID: `1` is hardcoded for Fitbit. Change if you need to connect a different data source.
 - Redirect URL: Specify your app’s custom URL scheme so the user can be sent back into the app after authorizing.
 - You can find more info about setting up schema url on: `https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app`
 */
@MainActor
func connectFitbit() async {
    // 1) Request the connect URL for Fitbit (dataSourceId = 1)
    let response = await ThryveSDK.get().getConnectDataSourceUrl(
        dataSourceId: 1,
        redirectUrl: "showThryve://"
    )

    if let url = response.data {
    // 2) Open the URL in Safari (or default browser)
      UIApplication.shared.open(url, options: [:], completionHandler: nil)
    } else {
    // 3) Surface or log the error(s)
      if let errors = response.errors {
        for error in errors {
          Logger.i { "Failed to connect \(providerName): \(error.errorMessage ?? "Unknown")" }
        }
      }
}


/**
 Async function that fetches the revoke‐URL for Fitbit via ThryveSDK and opens it in the default browser.

 - Data Source ID: `1` is hardcoded for Fitbit. Change if you need to disconnect a different data source.
 - `requireUserAction`: If `true`, the user will see a confirmation prompt in the browser before revocation.
 - Redirect URL: Specify your app’s custom URL scheme so the user can be sent back into the app after finishing the revocation flow.
 - You can find more info about setting up schema url on: `https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app`
 */
@MainActor
func disconnectFitbit() async {
    // 1) Request the revoke URL for Fitbit (dataSourceId = 1)
    let response = await ThryveSDK.get().getRevokeDataSourceUrl(
        dataSourceId: 1,
        requireUserAction: false,
        redirectUrl: "showThryve://"
    )
    
    if let url = response.data {
    // 2) Open the URL in Safari (or default browser)
      UIApplication.shared.open(url, options: [:], completionHandler: nil)
    } else {
    // 3) Surface or log the error(s)
      if let errors = response.errors {
        for error in errors {
          Logger.i { "Failed to disconnect \(providerName): \(error.errorMessage ?? "Unknown")" }
        }
      }
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.model.ThryveResponse

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // … your layout inflation, etc.
    }

    /**
     * Async function that fetches the “connect” URL for Fitbit via ThryveSDK
     * and opens it in the default browser.
     *
     * - dataSourceId = 1 (Fitbit). Change for other sources.
     * - redirectUrl = "showThryve://" (your app’s deep‐link scheme).
     */
    private fun connectWebDataSource(context: Context) {
        // Launch a coroutine on the IO dispatcher so we don't get a NetworkOnMainThreadException
        viewModelScope.launch(Dispatchers.IO) {
            val response = thryveSDK.getConnectDataSourceUrl(
                dataSourceId = 1, // Use the Id of the preferred Web data source
                redirectUri = "showThryve://",
            )

            if (response.successful) {
                val intent = Intent(Intent.ACTION_VIEW, response.data?.toUri()).apply {
                    if (context !is Activity) {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    }
                }

                // Switch to Main dispatcher for UI operations
                withContext(Dispatchers.Main) {
                    try {
                        context.startActivity(intent)
                    } catch (e: ActivityNotFoundException) {
                        Log.e(TAG, "❌ No browser app to handle connect URL", e)
                    }
                }
            } else {
                Log.e(TAG, "❌ Failed to retrieve connect URL: ${response.errors.joinToString()}")
                return@launch
            }
        }
    }

    /**
     * Async function that fetches the “revoke” URL for Fitbit via ThryveSDK
     * and opens it in the default browser.
     *
     * - dataSourceId = 1 (Fitbit). Change for other sources.
     * - requireUserAction = false (no confirmation prompt in browser).
     * - redirectUrl = "showThryve://".
     */
    private fun disconnectWebDataSource(context: Context) {
        // Launch a coroutine on the IO dispatcher so we don't get a NetworkOnMainThreadException
        viewModelScope.launch(Dispatchers.IO) {
            val response = thryveSDK.getRevokeDataSourceUrl(
                dataSourceId = 1,
                requireUserAction = false,
                redirectUri = "showThryve://"
            )
            }
            }

            if (response.successful) {
                val intent = Intent(Intent.ACTION_VIEW, response.data?.toUri()).apply {
                    if (context !is Activity) {
                        addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    }
                }

                // Switch to Main dispatcher for UI operations
                withContext(Dispatchers.Main) {
                    try {
                        context.startActivity(intent)
                        Log.i(TAG, "✅ Revoke URL launched for ${source.source}")
                    } catch (e: ActivityNotFoundException) {
                        Log.e(TAG, "❌ No browser app to handle revoke URL", e)
                    }
                }
            } else {
                Log.e(TAG, "❌ Failed to retrieve revoke URL: ${response.errors.joinToString()}")
                return@launch
            }
        }
    }
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
// Assumes you have installed and linked: 
//   "thryve-sdk" and you import ThryveSDK from it. 
// Also import Linking from 'react-native'.

import { ThryveSDK } from '@thryve/react-native-sdk-module';
import { Linking } from 'react-native';

/**
 * Async function that fetches the "connect" URL for Fitbit via ThryveSDK
 * and opens it in the default browser.
 *
 * - dataSourceId: 1 (Fitbit). Change for other sources.
 * - redirectUrl: "showThryve://".
 */
export async function connectFitbit() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const response = await sdk.getConnectDataSourceUrl(1, 'showThryve://');
    if (response?.data) {
      const url = response.data; // Should be a string or URL object
      await Linking.openURL(url.toString());
    } else {
      console.error('❌ Failed to retrieve Fitbit connect URL:', response.errors);
      // Optionally:  // Optionally: Alert your users of each error in response.errors
    }
  } catch (err) {
    console.error('❌ Unexpected error in connectFitbit():', err);
  }
}

/**
 * Async function that fetches the "revoke" URL for Fitbit via ThryveSDK
 * and opens it in the default browser.
 *
 * - dataSourceId: 1 (Fitbit). Change for other sources.
 * - requireUserAction: false (no confirmation prompt in browser).
 * - redirectUrl: "showThryve://".
 */
export async function disconnectFitbit() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);

  try {
    const response = await sdk.getRevokeDataSourceUrl(1, false, 'showThryve://');
    if (response?.data) {
      const url = response.data;
      await Linking.openURL(url.toString());
    } else {
      console.error('❌ Failed to retrieve Fitbit revoke URL:', response.errors);
      // Optionally: Alert your users of each error in response.errors
    }
  } catch (err) {
    console.error('❌ Unexpected error in disconnectFitbit():', err);
  }
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:flutter/material.dart';
import 'package:thryve_sdk/thryve_sdk.dart';
import 'package:url_launcher/url_launcher.dart';

/**
 * Async function that fetches the "connect" URL for Fitbit via ThryveSDK
 * and opens it in the default browser.
 *
 * - dataSourceId: 1 (Fitbit). Change for other sources.
 * - redirectUrl: "showThryve://".
 */
Future<void> connectFitbit() async {
  final sdk = ThryveSDK.getOrCreate();

  final response = await sdk.getConnectDataSourceUrl(
    dataSourceId: 1,
    redirectUrl: 'showThryve://',
  );

  if (response is ThryveResponseSuccess<Uri>) {
    final Uri url = response.value;
    // Open the URL in the default browser
    if (await canLaunchUrl(url)) {
      await launchUrl(url);
    } else {
      debugPrint('⚠️ Could not launch URL: $url');
    }
  } else if (response is ThryveResponseFailure<Uri>) {
    debugPrint('❌ Failed to retrieve Fitbit connect URL: ${response.error}');
  } else {
    debugPrint('❌ Unexpected response type for connectFitbit()');
  }
}

/**
 * Async function that fetches the "revoke" URL for Fitbit via ThryveSDK
 * and opens it in the default browser.
 *
 * - dataSourceId: 1 (Fitbit). Change for other sources.
 * - requireUserAction: false (no confirmation prompt in browser).
 * - redirectUrl: "showThryve://".
 */
Future<void> disconnectFitbit() async {
  final sdk = ThryveSDK.getOrCreate();

  final response = await sdk.getRevokeDataSourceUrl(
    dataSourceId: 1,
    requireUserAction: false,
    redirectUrl: 'showThryve://',
  );

  if (response is ThryveResponseSuccess<Uri>) {
    final Uri url = response.value;
    if (await canLaunchUrl(url)) {
      await launchUrl(url);
    } else {
      debugPrint('⚠️ Could not launch URL: $url');
    }
  } else if (response is ThryveResponseFailure<Uri>) {
    debugPrint('❌ Failed to retrieve Fitbit revoke URL: ${response.error}');
  } else {
    debugPrint('❌ Unexpected response type for disconnectFitbit()');
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
We recommend opening the link in an **external browser** and **not** a web view within your application. Web-views do not support social logins (e.g. Google, Facebook, or Apple sign-ins) that might be used by your end-users for certain data sources.
{% endhint %}

To make sure your user gets automatically forwarded back to your application after successfully connecting, make sure to specify a redirect URI using the `redirect_uri` parameter of the above SDK methods.

## Connect/disconnect native data sources

### Display only available native data source&#x20;

Not all native data sources are available on all devices, either because they are not installed or set up by the end user. Therefore, make sure to use the `isAvailable` method of the SDK to only display the data source if the method returns `true` to avoid errors.

### Connect and disconnect native data sources

Authorization of native data sources is happening on the operating system level. To make your users connect to Apple Health, Health Connect, or Samsung Health, simply call `start` for the corresponding source.&#x20;

{% hint style="info" %}
Ensure you have imported and configured the needed SDK modules.
{% endhint %}

The SDK will request access to the types specified in the `config` object and will take care of everything, and create the connection after authorization by the end-user.

{% tabs %}
{% tab title="iOS" %}

```javascript
import UIKit
import ThryveCore
import HealthKit
import ThryveCommons

/**
 Async function that starts Apple Health integration and requests authorization via ThryveSDK for a given set of HealthKit data types.

 - `source`: Always use `.apple` for HealthKit.
 - `types`: A `Set<AnyHashable>` of `ThryveAppleHealthConnectorDataType` values, e.g. `[.stepCount]`.
            Passing `nil` will default to whatever types were configured in your ThryveSDK configuration object.
 */
@MainActor
func connectAppleHealth(types: Set<AnyHashable>? = nil) async {
    // Passing `nil` here causes the SDK to request permissions for the types defined in its config.
    let response: ThryveResponse<Bool> = await ThryveSDK.get().start(
        dataSource: .apple,
        dataTypes: types
    )

    if response.successful {
      Logger .i { "✅ Apple Health integration started successfully (using configured types)." }
      return
    }

    if let errors = response.errors {
      for error in errors {
        Logger.i { "Failed to start Apple Health: \(error.errorMessage ?? "Unknown")" }
      }
    }
}


/**
 Async function that stops Apple Health integration via ThryveSDK.

 - `source`: Always use `.apple` for HealthKit.
 */
@MainActor
func disconnectAppleHealth() async {
    let response: ThryveResponse<Bool> = await ThryveSDK.get().stop(dataSource: .apple)

    if response.successful {
      Logger.i{ "✅ Apple Health integration stopped successfully." }
      return
    }

    if let errors = response.errors {
      for error in errors {
        Logger.i { "Failed to stop Apple Health: \(error.errorMessage ?? "Unknown")" }
      }
    }
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.healthConnect
import com.thryve.sdk.samsungHealth

...
fun connectHealthConnect(activity: ComponentActivity){
    ThryveSDK.get()?.start(activity, Source.HEALTH_CONNECT) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "Health Connect start successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "Health Connect start error $error" }
            }
        }
    }
}

fun disconnectHealthConnect(){
    ThryveSDK.get()?.stop(Source.HEALTH_CONNECT) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "Health Connect stop successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "Health Connect stop error $error" }
            }
        }
    }
}

fun connectSamsungHealth(activity: ComponentActivity){
    ThryveSDK.get()?.start(activity, Source.SAMSUNG) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "Samsung Health start successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "Samsung Health  start error $error" }
            }
        }
    }
}

fun disconnectSamsungHealth(){
    ThryveSDK.get()?.stop(Source.SAMSUNG) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "Samsung Health stop successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "Samsung Health  stop error $error" }
            }
        }
    }
}
...
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import {ThryveSDK, Source} from '@thryve/react-native-sdk';

function connectAppleHealth() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.start(Source.APPLE, (result) => {
      console.log(`Apple Health start successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Apple Health start error ${error}`);
      });
  });
}

function disconnectAppleHealth() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.stop(Source.APPLE, (result) => {
      console.log(`Apple Health stop successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Apple Health stop error ${error}`);
      });
  });
}
  
function connectHealthConnect() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.start(Source.HEALTH_CONNECT, (result) => {
      console.log(`Health Connect start successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Health Connect start error ${error}`);
      });
  });
}

function disconnectHealthConnect() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.stop(Source.HEALTH_CONNECT, (result) => {
      console.log(`Health Connect stop successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Health Connect stop error ${error}`);
      });
  });
}

function connectSamsungHealth() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.start(Source.SAMSUNG, (result) => {
      console.log(`Samsung Health start successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Samsung Health start error ${error}`);
      });
  });
}

function disconnectSamsungHealth() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.stop(Source.SAMSUNG, (result) => {
      console.log(`Samsung Health stop successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Samsung Health stop error ${error}`);
      });
  });
}

function disconnectShenAI() {
  const thryveSDK = new ThryveSDK().getOrCreate(thryvSDKConfig);
  if (!thryveSDK) return;

  thryveSDK.stop(Source.SHENAI, (result) => {
      console.log(`Shen AI stop successful = ${result.data}`);
      result.errors.forEach((error) => {
        console.log(`Shen AI stop error ${error}`);
      });
  });
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
// Soon to be updated
```

{% endtab %}
{% endtabs %}

To disconnect the data source, simply call `stop` and the SDK will not retrieve any data and no further data will be stored until `start` is called again for the user.

{% hint style="warning" %}
After calling `stop` the connection to your app will still appear active in Apple Health.  Apple does not allow developers to revoke the connection, and only users can manually revoke access inside the Health app. The internal functionalities of the Thryve service, however, will make sure no new data is stored after `stop` is called until `start` is called again.
{% endhint %}

## Obtain the correct connection status

To accurately display the connection status of data sources to users, use `ThryveSDK.get().getUserInformation`. This method returns a list of `connectedSources` their IDs. Additionally, `connectedAt` provides the timestamp of when the user connected to each data source.

<figure><img src="/files/xGuWMfvUc7ygNoK5U66J" alt="" width="188"><figcaption><p>Example of button states that change depending on information returned by <code>getUserInformation</code> </p></figcaption></figure>

Use the retrieved information to update the interface. Modify button actions based on this data: allow users to disconnect from connected data sources and encourage them to connect to those that are not yet linked.


# Apple Health, Health Connect & Samsung Health

Once a user connects Apple Health, Health Connect, or Samsung Health, the Thryve SDK can retrieve and sync data from these native sources either automatically or manually.

We generally recommend manually synchronizing connected native data sources whenever your app comes to the foreground to ensure all data is up-to-date, as automatic background data synchronization is highly dependent on the operating system and its resource and battery management, allowing for regular synchronizations.

{% hint style="info" %}
Web data sources are seamlessly managed by the Thryve backend. This page is only related to data sources where health data is directly retrieved from the end user device via the Thryve SDK.
{% endhint %}

## SDK Module Configuration

When using Apple Health, Health Connect & Samsung Health, you will need the optional SDK modules Apple Health, Health Connect or Samsung Health. Make sure to initialize the corresponding configurations `ThryveAppleHealthConfig`, `ThryveHealthConnectConfig` and `ThryveSamsungHealthConfig` for correct functionality.

<table><thead><tr><th width="99.609375">Parameter</th><th width="547.76953125">Description</th><th width="100.421875">Mandatory</th></tr></thead><tbody><tr><td><code>configs</code></td><td>List of <code>ThryveSDKModulesConfig</code> for imported SDK modules.</td><td>yes</td></tr></tbody></table>

{% tabs %}
{% tab title="Apple Health" %}
When using the Apple Health module, make sure to define the data types in the `ThryveAppleHealthConfig` . *This* is *only relevant for iOS integration.*

<table><thead><tr><th width="198.4617919921875">Parameter</th><th width="458.33642578125">Description</th><th width="99.81640625">Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>The Apple Health data types <code>Set&#x3C;ThryveAppleHealthDataType></code> required by your app. Ensure to <a data-footnote-ref href="#user-content-fn-1">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application. Please refer to this document to understand the data types.</td><td>yes</td></tr><tr><td><code>enableBackgroundSync</code></td><td><p>Configures background data synchronization on SDK initialization (retrieving data when your app is closed or idle).<br><br>Default state is <code>true</code> which requires <a href="/pages/mF5OcudXCdbsedmKWCl9">Background Delivery</a> to be enabled for a <strong>HealthKit Capability.</strong></p><p>Alternatively, <a href="/pages/WJgf11wpT55T53iDeyFx#automatic-background-data-synchronization">use the <code>executeBackgroundSync</code> method</a> in <code>AppDelegate</code></p></td><td>no</td></tr></tbody></table>
{% endtab %}

{% tab title="Health Connect" %}
When using the Health Connect module, make sure to define the data types in the `ThryveHealthConnectConnectorConfig` . *This* is *only relevant for Android integration*

<table><thead><tr><th width="169.7265625">Parameter</th><th width="342.26171875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>Health Connect data types required by your app. Ensure to <a data-footnote-ref href="#user-content-fn-2">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application. Please refer to this document to understand the data types.</td><td>no, defaults to all supported data types</td></tr><tr><td><code>enableBackgroundSync</code></td><td>Will request background data sync permissions. If permissions are granted, <a href="https://developer.android.com/develop/background-work/background-tasks">background tasks</a> using WorkManager will be scheduled by the Thryve SDK.</td><td>no, defaults to <code>true</code></td></tr><tr><td><code>enableReadHealthDataHistory</code></td><td>Will request historical data sync permissions. If permissions are granted, timeframes older than 30 days can be requested when using manual data synchronization methods.</td><td>no, defaults to <code>true</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Samsung Health" %}
When using the Samsung Health module, make sure to define the data types in the `ThryveSamsungHealthConfig` . *This* is *only relevant for Android integration*

<table><thead><tr><th width="169.7265625">Parameter</th><th width="342.26171875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataTypes</code></td><td>The Samsung Health data types required by your app. Please refer to <a href="https://docs.thryve.health/thryve-product-overview/access/data-types-biomarker">this document</a> to understand the data types. Ensure to <a data-footnote-ref href="#user-content-fn-2">limit types to data described in your data privacy policy</a>. Always ensure the configured <code>dataTypes</code> are consistent across your application.</td><td>no, defaults to all supported data types</td></tr><tr><td><code>enableBackgroundSync</code></td><td>Schedules <a href="https://developer.android.com/develop/background-work/background-tasks">background tasks</a> using WorkManager for data synchronization when app is closed or idle.</td><td>no, defaults to <code>true</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Please ensure you have set-up your [iOS](/integrate-your-mobile-app/setup-thryve-sdk/ios) and [Android](/integrate-your-mobile-app/setup-thryve-sdk/android) project with correct configuration for Apple HealthKit, .
{% endhint %}

## Automatic Background Data Synchronization

We utilize different technologies for automatic background data retrieval on iOS and Android. On iOS, the Thryve SDK employs HealthKit’s native background synchronization API. For Android, synchronization is scheduled and managed via [WorkManager](https://developer.android.com/develop/background-work/background-tasks/persistent).

The availability of background data synchronizations is configurable for Apple Healtsh, Samsung Health and Health Connect data sources in the corresponding config objects.

{% hint style="info" %}
The **`ThryveHealthConnect`** and **`ThryveSamsungHealth`** modules perform background synchronization every 30 minutes once `enableBackgroundSync` is enabled in the configuration.

**`ThryveAppleHealth`**, on the other hand, triggers background synchronization whenever new data becomes available in **Apple Health** while the app is running in the background.
{% endhint %}

{% tabs %}
{% tab title="Apple Health" %}
To enable background data synchronization (retrieving data when your app is closed or idle), use the `executeBackgroundSync` method within the `didFinishLaunchingWithOptions` function in `AppDelegate` right after connecting to Apple Health.

Apple mandates that this logic runs within the first few seconds of app startup for data delivery, hence its placement in `AppDelegate`. Refer to the sample code for further details.

```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // When Apple's Health app initiates contact, it triggers your application 
        // via didFinishLaunchingWithOptions. Once activated, HealthKit waits 
        // briefly to determine if your app wishes to renew its query contracts. 
        // Calling the relevant method as early as possible renews these contracts, 
        // enabling the app to fetch new data promptly from Apple Health.
        ThryveSDK.get().executeBackgroundSync(
                  dataSource: .apple,
                  dataTypes: ThryveAppleHealthDataType.allTypes)
        // Override point for customization after application launch.
        return true
    }
```

{% hint style="danger" %}
Ensure your project is configured correctly and `Background Delivery` is enabled in your apps HealthKit Capabilities as documented.
{% endhint %}
{% endtab %}

{% tab title="Health Connect" %}
To enable background data synchronization (retrieving data when your app is closed or idle) in native Android, using Kotlin, enable background sync in the `ThryveHealthConnectConfig` .

```javascript
val healthConnectConfig = ThryveHealthConnectConfig(
        dataTypes = ThryveHealthConnectDataType.entries.toList(),
        enableBackgroundSync = true,
        enableReadHealthDataHistory = true
    ) 
```

{% hint style="danger" %}
Background sync will only execute if the user has granted corresponding Health Connect permission.
{% endhint %}
{% endtab %}

{% tab title="Samsung Health" %}
To enable background data synchronization (retrieving data when your app is closed or idle) in native Android, using Kotlin, enable background sync in the `ThryveSamsungHealthConfig` .

```kotlin
val samsungHealthConfig = ThryveSamsungHealthConfig(
        dataTypes = ThryveSamsungHealthDataType.entries.toList(),
        enableBackgroundSync = true
    )
```

{% endtab %}

{% tab title="React Native (All Sources)" %}
In React Native, using javascript or Typescript, enable enableBackgroundSync[^3] sync in your configuration

<pre class="language-javascript"><code class="lang-javascript">const thryveSDKConfig = {
    authId: appId,
    authSecret: appSecret,
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    locale: 'en',
    config: [
      {
        source: Source.APPLE,
        dataTypes: appleHealthDataTypes,
      },
      {
        source: Source.HEALTH_CONNECT,
        dataTypes: healthConnectDataTypes,
        <a data-footnote-ref href="#user-content-fn-3">enableBackgroundSync</a>: true,
        enableReadHealthDataHistory: true,
      },
      {
        source: Source.SAMSUNG,
        dataTypes: samsungHealthDataTypes,
        enableBackgroundSync = true,
      },
      {
        source: Source.SHENAI,
        apiKey: "SHEN_AI_API_KEY",
      },
    ],
  };
  thryveSDK.getOrCreate(thryveSDKConfig);
   
</code></pre>

{% endtab %}

{% tab title="Flutter(All Sources)" %}
The background data sychronization in the Flutter SDK is enabled in the ThryveSDKConfig durint initialization. Check the [Flutter SDK initialization section](/integrate-your-mobile-app/connect-data-sources#flutter)
{% endtab %}
{% endtabs %}

## Manual Data Synchronization

Manual data synchronization is recommended to ensure all recent data is available when the user opens your app. Therefore, we recommend using `synchronize` whenever your app moves to the foreground.

`synchronize` will ensure that both epoch and daily data added since the last data synchronization will be fetched from Apple Health, Health Connect, or Samsung Health. The initial execution of `synchronize` will fetch all data for today.

{% tabs %}
{% tab title="Apple Health" %}

<pre class="language-swift"><code class="lang-swift">import ThryveCore
import ThryveAppleHealth

<strong>// synchronous function
</strong>func synchronize() {
  ThryveSDK.get().synchronize(
    dataSource: .apple,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
    
// asynchronous function
func synchronize() {
  Task {
    let thryveResponse = await ThryveSDK.get().synchronize(
      dataSource: .apple,
      dataTypes: ThryveAppleHealthDataType.allTypes)
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
</code></pre>

{% endtab %}

{% tab title="Health Connect" %}

```kotlin
ThryveSDK.get().synchronize(dataSource = Source.HEALTH_CONNECT) { thryveResponse ->
    if (thryveResponse.successful) {
        // synchronization was successful
    } else {
        thryveResponse.errors.map { error -> // synchronization failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="Samsung Health" %}

```kotlin
ThryveSDK.get().synchronize(dataSource = Source.SAMSUNG) { thryveResponse ->
    if (thryveResponse.successful) {
        // synchronization was successful
    } else {
        thryveResponse.errors.map { error -> // synchronization failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="React Native (All Sources)" %}

```javascript
import { 
Source,
ThryveSamsungHealthDataType,
ThryveHealthConnectDataType,
ThryveAppleHealthDataType,
ThryveSDK 
} from '@thryve/react-native-sdk';

//Synchronize Apple Health data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.synchronize(Souce.APPLE, allAppleHealthDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//Synchronize Health Connect data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allHealthConnectDataTypes = Object.values(ThryveHealthConnectDataType);
    const response = await sdk.synchronize(Souce.HEALTH_CONNECT, allHealthConnectDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Health Connect synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//Synchronize Samsung Health data
export async function synchronize() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allSamsungHealthDataTypes = Object.values(ThryveSamsungHealthDataType);
    const response = await sdk.synchronize(Souce.SAMSUNG, allSamsungHealthDataTypes);
    if (response?.data) {
      //synchronize was successfull
    } else {
      //synchronize failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Samsung Health synchronize error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}
```

{% endtab %}

{% tab title="Flutter  (All Sources)" %}

```dart
import 'package:module_apple_health/module_apple_health.dart';
import 'package:thryve_sdk/thryve_sdk.dart';

final class AppleHealthPageBloc {
  final ThryveSDK _thryveSDK;
  final Source _dataSource;
  List<HKConnectorType> _hkConnectorTypes;

  AppleHealthPageBloc(this._thryveSDK, this._hkConnectorTypes) : _dataSource = Source.apple;

  Future<ThryveResponse<void>> synchronize() => _thryveSDK.synchronize(_dataSource.id);

  Future<void> synchronizeAppleHealth() async {
    final ThryveResponse<void> response = await synchronize();

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to synchronize all Apple Health data types.');
    }
  }
}

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
The manual data retrieval methods will return a `ThryveResponse`. This response will be `true` if the data is uploaded successfully. If issues occur during retrieval or upload, the response will be `false`, and a list of `ThryveError` will be provided. Each `ThryveError` contains details about the error encountered.
{% endhint %}

### Historic data backfill

To access data predating the initial synchronization, the Thryve SDK provides methods for backfilling historical data. These methods allow synchronization of epoch and daily data within a specified timeframe.

{% hint style="warning" %}
We recommend using `backfill` methods only to fetch historic data, usually during the first connection or for a specific gap. Backfill should be used infrequently and should not run on a regular schedule.
{% endhint %}

{% tabs %}
{% tab title="Apple Health" %}

```swift

import ThryveCore
import ThryveAppleHealth

func backfillEpoch() {
  ThryveSDK.get().backfillEpoch(
    dataSource: .apple,
    startDate: from,
    endDate: to,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}
```

```swift
func backfillDaily() {
  ThryveSDK.get().backfillDaily(
    dataSource: .apple,
    startDate: from,
    endDate: to,
    dataTypes: ThryveAppleHealthDataType.allTypes
  ) { (thryveResponse) in
    guard thryveResponse.successful else {
      thryveResponse.errors?.forEach { error in
        //synchronize failed process errors
        Logger.e { error }
      }
      return
    }
    //synchronize was successful
  }
}

```

{% endtab %}

{% tab title="Health Connect" %}

```kotlin
ThryveSDK.get().backfillEpoch(
    dataSource = Source.HEALTH_CONNECT,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

```kotlin
ThryveSDK.get().backfillDaily(
    dataSource = Source.HEALTH_CONNECT,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="Samsung  Health" %}

```kotlin
ThryveSDK.get().backfillEpoch(
    dataSource = Source.SAMSUNG,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

```kotlin
ThryveSDK.get().backfillDaily(
    dataSource = Source.SAMSUNG,
    startDate = Date().daysAgo(30),
    endDate = Date()
) { thryveResponse ->
    if (thryveResponse.successful) {
        // backfill was successful
    } else {
        thryveResponse.errors.map { error -> // backfill failed, process errors }
        }
    }
}
```

{% endtab %}

{% tab title="React Native (All Sources)" %}
{% code overflow="wrap" %}

```javascript
import { 
Source,
ThryveSamsungHealthDataType,
ThryveHealthConnectDataType,
ThryveAppleHealthDataType,
ThryveSDK 
} from '@thryve/react-native-sdk';

//backfillEpoch Apple Health data
export async function backfillEpoch() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.backfillEpoch(Souce.APPLE, startDate, endDate, allAppleHealthDataTypes);
    if (response?.data) {
      //backfillEpoch was successfull
    } else {
      //backfillEpoch failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health backfillEpoch error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}

//backfillDaily Apple Health data
export async function backfillEpoch() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const allAppleHealthDataTypes = Object.values(ThryveAppleHealthDataType);
    const response = await sdk.backfillDaily(Souce.APPLE, startDate, endDate, allAppleHealthDataTypes);
    if (response?.data) {
      //backfillDaily was successfull
    } else {
      //backfillDaily failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Apple Health backfillDaily error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Flutter (All Sources)" %}

```dart
import 'package:module_apple_health/module_apple_health.dart';
import 'package:thryve_sdk/thryve_sdk.dart';

final class AppleHealthPageBloc {
  final ThryveSDK _thryveSDK;
  final Source _dataSource;
  List<HKConnectorType> _hkConnectorTypes;

  AppleHealthPageBloc(this._thryveSDK, this._hkConnectorTypes) : _dataSource = Source.apple;

  Future<ThryveResponse<void>> backfillEpoch(
    DateTime startDate,
    DateTime endDate,
  ) =>
      _thryveSDK.backfillEpoch(
          _dataSource.id, startDate, endDate, _hkConnectorTypes.map((e) => e.name).toList());

  Future<ThryveResponse<void>> backfillDaily(
    DateTime startDate,
    DateTime endDate,
  ) =>
      _thryveSDK.backfillDaily(
          _dataSource.id, startDate, endDate, _hkConnectorTypes.map((e) => e.name).toList());

  Future<void> backfillEpochAppleHealth(
    DateTime startDate,
    DateTime endDate,
  ) async {
    final ThryveResponse<void> response = await backfillEpoch(startDate, endDate);

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to backfill all Apple Health data types.');
    }
  }
  
 Future<void> backfillDailyAppleHealth(
    DateTime startDate,
    DateTime endDate,
  ) async {
    final ThryveResponse<void> response = await backfillDaily(startDate, endDate);

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to backfill all Apple Health data types.');
    }
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
`backfillEpoch` fetches epoch data for the given timeframe, with a maximum of 30 days. If the difference between `startDate` and `endDate` is more than 30 days, the SDK will count from the end date 30 days back

`backfillDaily` fetches daily data for the given timeframe, with a maximum of 365 days. If the difference between `startDate` and `endDate` is more than 365 days, the SDK will count from the end date 365 days back
{% endhint %}

<table><thead><tr><th width="156.66796875">Parameter</th><th width="427.1875">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>dataSource</code></td><td>The data source to synchronize data from. iOS defaults to <code>.apple</code></td><td>yes, on Android.<br>no, on iOS</td></tr><tr><td><code>dataTypes</code></td><td>The data types to synchronize. It defaults to the data types defined in the data source config.</td><td>no</td></tr><tr><td><code>startDate</code></td><td>The date to start data retrieval and synchronization from. It is applicable only to the backfiill functions</td><td>yes</td></tr><tr><td><code>endDate</code></td><td>The date to end data retrieval and synchronization on. It defaults to today and applicable only to the backfiill functions.</td><td>no</td></tr></tbody></table>

{% hint style="info" %}
The manual data retrieval methods will return a `ThryveResponse`. This response will be `true` if the data is uploaded successfully. If issues occur during retrieval or upload, the response will be `false`, and a list of `ThryveError` will be provided. Each `ThryveError` contains details about the error encountered.
{% endhint %}

[^1]: The use of data types beyond the means described in your privacy policy may lead to your app being rejected by Apple in the App Store.\
    \
    Ensure to explain why your app needs access to the different types and why this is important for the user experience to avoid rejection.

[^2]: The use of data types beyond the means described in your privacy policy may lead to your app being rejected by Google in the Google Play Store.\
    \
    Ensure to explain why your app needs access to the different types and why this is important for user experience to avoid rejection.

[^3]: set to true to Health Connect background synchronization


# Direct bluetooth device connection

{% hint style="warning" %}
Please note that **ThryveBLE** module is in beta; ReactNative and Flutter support will follow.
{% endhint %}

With Thryve, you can connect blood glucose monitors and heart rate monitors directly via Bluetooth Low Energy (BLE). The ThryveBLE module abstracts the complexity of Bluetooth integration by providing:

* **Effortless connectivity:** Automatically handles permissions, device discovery, connections, and communication.
* **Automated data access:** Retrieves health data from connected devices and uploads it to the Thryve data warehouse, ensuring your application always has up-to-date metrics.
* **Comprehensive device handling:** Manages device interactions end-to-end, from connection stability to reliable data acquisition.

<figure><img src="/files/DoOtviIJT3BLn8pOuEXL" alt="" width="188"><figcaption></figcaption></figure>

This guide explains how to let users connect and disconnect devices and includes UI integration examples. For a best-practice implementation, refer to the Thryve Sample App.

{% hint style="info" %}
The module is compatible with [Blood Glucose Monitors](https://www.bluetooth.com/specifications/specs/glp-1-0-1/) and [Heart Rate Monitors](https://www.bluetooth.com/specifications/specs/heart-rate-profile-1-0/) that adhere to open Bluetooth device profiles. Devices from manufacturers that do not follow Bluetooth standards may not function properly.
{% endhint %}

<details>

<summary>Verified Blood Glucose Monitors</summary>

Correct functionality has been verified for the following devices:

* Roche ACCU-CHEK Instant
* Roche ACCU-CHEK Guide
* FORA 6 Connect
* Contour Care

</details>

<details>

<summary>Verified Heart Rate Monitors</summary>

Correct functionality has been verified for the following devices:

* Coros Heart Rate Monitor
* Garmin HRM-Dual
* Polar H7 Heart Rate Sensor
* Polar H9 Heart Rate Sensor
* Polar H10 Heart Rate Sensor
* Suunto Smart Heart Rate Belt
* Whoop 4.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))
* Whoop 5.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))

</details>

## Integrate Thryve BLE with your application

To be able to  integrate `ThryveBLE` module you need to:

{% tabs %}
{% tab title="iOS" %}

1. **Integrate the `ThryveBLE` module**\
   Make sure to also add `ThryveCore` and `ThryveCommons` modules. Follow either the [cocoapods](/integrate-your-mobile-app/setup-thryve-sdk/ios#integration-via-cocoapods) or [framework files](/integrate-your-mobile-app/setup-thryve-sdk/ios#integration-via-frameworks) instructions in the [iOS section](/integrate-your-mobile-app/setup-thryve-sdk/ios).&#x20;

2. **Add Bluetooth Capability**\
   In Xcode: Navigate to *Target → Signing & Capabilities → add (+) → Bluetooth*.

   <figure><img src="/files/6H5mGS9Ge6itxrjos28H" alt=""><figcaption></figcaption></figure>

3. **Add `Privacy - Bluetooth Always Usage Description` to Info.plist**\
   `<key>NSBluetoothAlwaysUsageDescription</key>`

   `<string>Bluetooth permission for Thryve</string>`
   {% endtab %}

{% tab title="Android" %}

1. **Integrate the `thryve_module_ble` module**\
   Make sure to also add `thryve_core_sdk` and `thryve_module_commons` modules. Follow the instructions in either  the [Thryve Repository Dependencies ](/integrate-your-mobile-app/setup-thryve-sdk/android#integrate-using-thryve-repository-dependencies)or  [Thryve .aar Libraries](https://docs.thryve.health/integrate-your-mobile-app/pages/gd15Xn3eNpfQhy8TrHU5#integrate-using-thryve-.aar-libraries) in the [Android section](https://open.gitbook.com/~site/site_WRtC1/mobile-apps/setup-thryve-sdk/android)
2. **Add the following `BLUETOOTH` permissions to the `AndroidManifest.xml`**

   ```
   <uses-permission android:name="android.permission.BLUETOOTH" />
   <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
   <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
   <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
   ```
3. **Add the `ACCESS_FINE_LOCATION` permission to `AndroidManifest.xml`**\
   This is required for all applications targeting Android devices running below Android 12

   ```
   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
   ```

{% endtab %}
{% endtabs %}

### Configure the `ThryveBLE` module

When initializing Thryve SDK make sure to define the `deviceTypes` and an optional `ThryveBLEEventListener` in the `ThryveBLEConfig` .

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveObservability
import ThryveBLE

let bleConfig = ThryveBLEConfig(
    //set the BLE device types. It defaults to all ThryveBLEDeviceTypes
    deviceTypes: Set<ThryveBLEDeviceType> = Set(ThryveBLEDeviceType.allCases),
    eventsListener: self // Optional: Receives callbacks for device found/connected/disconnected/data `ThryveBLEEventListener` protocol and implements `onDeviceFound(response: ThryveResponse<ThryveBLEDevice>)`, `onDeviceConnecting(response: ThryveResponse<ThryveBLEDevice>)`, `onDeviceConnected(response: ThryveResponse<ThryveBLEDevice>)`, onDeviceDisconnected(response: ThryveResponse<ThryveBLEDevice>) and, `onHeartRateDataReceived(device: ThryveBLEDevice, response: ThryveResponse<ThryveBLEHeartRateMeasurement>)` functions
)

let thryveSDKConfig = ThryveSDKConfig(
    authId: "AUTH_ID",
    authSecret: "AUTH_SECRET",
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    endUserId: nil, 
    locale: "de",
    configs: [bleConfig],
    observability: ObservabilityConfig(tracingEnabled: true, crashReportingEnabled: true)
)
        
let thryveSDK = await ThryveSDK.getOrCreate(thryveSDKConfig)

// Optionally, when ThryveSDK is initialized from a non-async context (AppDelegate, legacy code, etc.), it is recommended to use the getOrCreate(...) callback to know when the SDK is ready.

ThryveSDK.getOrCreate(thryveSDKConfig) { initResult in
    if initResult.successful {
        Logger.i("ThryveSDK ready, you can start calling API methods")
    } else if let error = initResult.errors?.first {
        Logger.e("ThryveSDK init failed: \(error.errorMessage ?? "Unknown error")")
    }
} 
```

{% endtab %}

{% tab title="Android" %}

```kotlin
 val bleConfig = ThryveBLEConfig(
    deviceTypes = ThryveBLEDeviceType.entries.toList(),
    eventsListener = object : ThryveBLEEventListener {
            override fun onDeviceFound(response: ThryveResponse<ThryveBLEDevice>) {}
            override fun onDeviceConnecting(response: ThryveResponse<ThryveBLEDevice>) {}
            override fun onDeviceConnected(response: ThryveResponse<ThryveBLEDevice>) {}
            override fun onDeviceDisconnected(response: ThryveResponse<ThryveBLEDevice>) {}
            override fun onHeartRateDataReceived(response: ThryveResponse<ThryveBLEGattData.Measurement>) {}
        }
 )
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="150.45184326171875">Parameter</th><th width="419.3529052734375">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>deviceTypes</code></td><td>Limits the BLE device types the host application supports (e.g. heart rate monitor). Only devices matching the <code>ThryveBLEDeviceType</code>  will appear in discovery.</td><td>no</td></tr><tr><td><code>eventsListener</code></td><td><p>An object of <code>ThryveBLEEventListener</code> that will have to implement  the following functions to receive events from the ThryveBLE  module.</p><pre><code>onDeviceFound(response: ThryveResponse&#x3C;ThryveBLEDevice>) 
onDeviceConnecting(response: ThryveResponse&#x3C;ThryveBLEDevice>) 
onDeviceConnected(response: ThryveResponse&#x3C;ThryveBLEDevice>)
onDeviceDisconnected(response: ThryveResponse&#x3C;ThryveBLEDevice>) 
onHeartRateDataReceived(device: ThryveBLEDevice, response: ThryveResponse&#x3C;ThryveBLEHeartRateMeasurement>)
</code></pre></td><td>no</td></tr></tbody></table>

## Allow users to connect to devices

To enable Bluetooth connectivity for users, implement the following features:

* Display a list of nearby devices available for connection.
* Allow users to connect to and disconnect from devices.
* Provide connection status and troubleshooting information.

Using `ThryveBLE`, these functionalities can be achieved quickly with just a few functions to expedite your initial integration.

### Start device discovery

To discover nearby BLE devices, initiate `startDeviceDiscovery`. Handle any found devices using `onDeviceFound` in the `ThryveBLEEventListener`. The discovery will end when `stopDeviceDiscovery` is called or the discovery process timed out as per configuration.

The Thryve SDK only returns Bluetooth devices that match the configured Bluetooth Device Profiles, automatically filtering out unsupported devices.

{% hint style="info" %}
Be aware that devices may appear compatible if manufacturers advertise open Bluetooth Device Profiles in device discovery, yet choose proprietary integration methods for connection and data access.
{% endhint %}

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryveBLEEventListener {
---
    func startScan() {
        Task { @MainActor in
               let response = await ThryveSDK.get().startDeviceDiscovery()
                guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                
                //returns a list of ThryveBLEDevice found
                let listOfThryveBLEDevices = response.data  
          }
    }
    
    //onDeviceFound method is a ThryveBLEEventListener event listener callback.
    //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is found 
    //during the scanning session in ThryveSDK.get().startDeviceDiscovery()
    func onDeviceFound(response: ThryveResponse<ThryveBLEDevice>) {
            Task { @MainActor in
                guard let bleDevice = response.data else {
                    // Process all [ThryveErrors] in response.errors
                    return
                }
                //process the ThryveBLEDevice found in the startDeviceDiscovery process
                //example update UI with the bleDevice object 
            }
    }
    
    //Call stopDeviceDiscovery to stop the BLE discovery or scanning process
    func stopScan() {
      Task { @MainActor in
          let response = await ThryveSDK.get().stopDeviceDiscovery()
        }
    }
---
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.ble

...
fun startScan(activity: ComponentActivity) {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().startDeviceDiscovery(activity) { response ->
            continuation.resume(response)
        }
    }
                
    if (!response.successful) {
      // Process all [ThryveErrors] in response.errors
      return 
    }   
             
   //returns a list of ThryveBLEDevice found
   val listOfThryveBLEDevices = response.data               
}

 //onDeviceFound method is a ThryveBLEEventListener event listener callback.
 //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is found 
 //during the scanning session in ThryveSDK.get().startDeviceDiscovery(activity)
override fun onDeviceFound(response: ThryveResponse<ThryveBLEDevice>) {
    if (!response.successful) {
       // Process all [ThryveErrors] in response.errors
       return
    } 
    
    val bleDevice = response.data
    //process the ThryveBLEDevice found in the startDeviceDiscovery process
    //example update UI with the bleDevice object 
}

//Call stopDeviceDiscovery to stop the BLE discovery or scanning process
fun stopScan() {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().stopDeviceDiscovery { response ->
            continuation.resume(response)
        }
    }
                
    if (response.successful) {
      // device discovery process has stopped.
    }else{
      // Process all [ThryveErrors] in response.errors
    } 
}
...
```

{% endtab %}
{% endtabs %}

**Recommendation:**

Manage the scanning process carefully. Avoid continuous scanning or high scanning timeouts when no devices are available or users opt not to connect a device. Continuous scanning can significantly drain the smartphone's battery, leading to user frustration and potential app uninstallation.

### Connect to BLE device

To enable users to connect to a BLE device upon a button click, utilize the `connectDevice` method from the `ThryveBLE`. Handle the connection status through the `ThryveBLEEventListener` interface, using the `onDeviceConnecting` and `onDeviceConnected` callback methods for processing connection events effectively.

<figure><img src="/files/BDMlHxv5M58hamqGl51X" alt="Showing Bluetooth Device Pairing Process" width="188"><figcaption><p>Pairing process with Roche ACCU-CHEK Guide</p></figcaption></figure>

Once connected, all available data is automatically retrieved and uploaded to the Thryve backend. For broadcasting devices like heart rate monitors, [heart rate data is accessible locally in real-time](/integrate-your-mobile-app/real-time-heart-rate-data) and is automatically uploaded every 5 minutes, as long as the connection remains active.

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryveBLEEventListener {
---
    func connectDevice() {
        Task { @MainActor in
               let response: ThryveResponse<Bool> = await ThryveSDK.get().connectDevice(device.id)
                guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                
                //process the connection status in the response object 
          }
    }
    
    //onDeviceConnecting method is a ThryveBLEEventListener event listener callback.
    //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is connecting 
    //during the execution of ThryveSDK.get().connectDevice
    func onDeviceConnecting(response: ThryveResponse<ThryveBLEDevice>) {
            guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                
                //process response.data. example update UI
    }
    
    //onDeviceConnected method is a ThryveBLEEventListener event listener callback.
    //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is connected 
    //during the execution of ThryveSDK.get().connectDevice
    //Data is automatically uploaded when a BLE device is connected.
    func onDeviceConnected(response: ThryveResponse<ThryveBLEDevice>) {
            guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                
                //process response.data. example update UI
    }
---
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.ble

...
fun connectDevice(activity: ComponentActivity, bleDevice: ThryveBLEDDevice) {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().connectDevice(activity, bleDevice.id) { response ->
            continuation.resume(response)
        }
    }
                
    if (!response.successful) {
      // Process all [ThryveErrors] in response.errors
      return 
    }   
             
   //bleDevice has connected. update application UI          
}

 //onDeviceConnecting method is a ThryveBLEEventListener event listener callback.
 //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is connecting 
 //during the execution of ThryveSDK.get().connectDevice
 override fun onDeviceConnecting(response: ThryveResponse<ThryveBLEDevice>) {
    if (!response.successful) {
       // Process all [ThryveErrors] in response.errors
       return
    } 
    
    //ThryveBLEDevice is connecting.
}

 //onDeviceConnected method is a ThryveBLEEventListener event listener callback.
 //It is automatically triggered by ThryveSDK each time a ThryveBLEDevice is connected 
 //during the execution of ThryveSDK.get().connectDevice
 //Data is automatically uploaded when a BLE device is connected.
 override fun onDeviceConnected(response: ThryveResponse<ThryveBLEDevice>) {
    if (!response.successful) {
       // Process all [ThryveErrors] in response.errors
       return
    } 
    //ThryveBLEDevice is connected.process response.data. example update UI
}

...
```

{% endtab %}
{% endtabs %}

#### Disconnect BLE device

To enable users to manually disconnect their BLE device, use `disconnectDevice`. Handle the disconnection status with the `ThryveBLEEventListener`'s `onDeviceDisconnected` callback.

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryveBLEEventListener {
---
    func disconnectDevice(device: ThryveBLEDevice) {
        Task { @MainActor in
               let response = await ThryveSDK.get().disconnectDevice(device.id)
                guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                
                //process the disconnection boolean result in response.data
          }
    }
    
    //onDeviceDisconnected method is a ThryveBLEEventListener event listener callback.
    //It is automatically triggered by ThryveSDK when a ThryveBLEDevice is disconnected 
    func onDeviceDisconnected(response: ThryveResponse<ThryveBLEDevice>) {
            Task { @MainActor in
                guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
                //process the ThryveBLEDevice that was disconnected. response.data
            }
    }
---
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.ble

...
fun onDeviceDisconnected(activity: ComponentActivity, bleDevice: ThryveBLEDDevice) {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().disconnectDevice(activity, bleDevice.id) { response ->
            continuation.resume(response)
        }
    }
                
    if (!response.successful) {
      // Process all [ThryveErrors] in response.errors
      return 
    }   
             
   //bleDevice has disconnected. update application UI          
}

//onDeviceDisconnected method is a ThryveBLEEventListener event listener callback.
//It is automatically triggered by ThryveSDK when a ThryveBLEDevice is disconnected
override fun onDeviceDisconnected(response: ThryveResponse<ThryveBLEDevice>) {
    if (!response.successful) {
       // Process all [ThryveErrors] in response.errors
       return
    } 
    //ThryveBLEDevice is disconnected.process response.data. example update UI
}
...
```

{% endtab %}
{% endtabs %}

## Show device connection status

We recommend to transparently display users actively connected devices as well as known, previously connected devices and allow them to re-connect those.

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryveBLEEventListener {
---
    func getActiveBLEDevices() {
        Task { @MainActor in
               let activedDevices = await ThryveSDK.get().getActiveDevices() 
                //Process all active or connected [ThryveBLEDevice] in activeDevices
          }
    }
    
    func getPreviousBLEDevices() {
        Task { @MainActor in
               let previousDevices = await ThryveSDK.get().getPreviousDevices()
                //Process all previous [ThryveBLEDevice] in previousDevices
          }
    }
---
}
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.ble
...

fun getActiveBLEDevices() {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().getActiveDevices { response ->
            continuation.resume(response)
        }
    }
                
    if (!response.successful) {
      // Process all [ThryveErrors] in response.errors
      return 
    }   
    //Process all active or connected [ThryveBLEDevice] in response.data         
}

fun getPreviousBLEDevices() {
    val response = suspendCancellableCoroutine { continuation ->
        ThryveSDK.get().getPreviousDevices { response ->
            continuation.resume(response)
        }
    }
                
    if (!response.successful) {
      // Process all [ThryveErrors] in response.errors
      return 
    }   
    //Process all previous [ThryveBLEDevice] in response.data         
}

...

```

{% endtab %}
{% endtabs %}


# Real-time heart rate data

Access real-time heart rate data on your device using Thryve SDK. Users simply connect their heart rate monitor with Bluetooth broadcasting capabilities. Once connected, the data flows instantly to your mobile application, provided the connection is active.&#x20;

Enhance your health or fitness application with easy access to real-time heart rate data using the Thryve SDK. Users can effortlessly connect their heart rate monitors that support Bluetooth broadcasting and your application will have real-time data available, provided the connection is active.&#x20;

Use the real-time heart rate data availability via Thryve to build experiences for fitness enthusiasts to optimize their workouts using instantaneous heart rate feedback or allow for real-time heart rate monitoring in medical use-cases for improved care journeys.&#x20;

<details>

<summary>Verified Heart Rate Monitors</summary>

Correct functionality has been verified for the following devices:

* Coros Heart Rate Monitor
* Garmin HRM-Dual
* Polar H7 Heart Rate Sensor
* Polar H9 Heart Rate Sensor
* Polar H10 Heart Rate Sensor
* Suunto Smart Heart Rate Belt
* Whoop 4.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))
* Whoop 5.0 (requires [enabled Heart Rate Broadcast](https://support.whoop.com/s/article/Heart-Rate-Broadcast?language=en_US))

</details>

## Connect heart rate monitor

Please refer to the [direct bluetooth device connection](/integrate-your-mobile-app/direct-bluetooth-device-connection) documentation for information on how to connect a heart rate monitor.

## Access real-time data

Capture live heart rate data via the `onHeartRateDataReceived` event in `ThryveBLEEventListener`. This event provides immediate access to data from connected heart rate monitors.

{% tabs %}
{% tab title="iOS" %}

<pre class="language-swift"><code class="lang-swift"><strong>import ThryveCore
</strong>import ThryveCommons
import ThryveBLE

class BLEViewModel: ObservableObject, ThryveBLEEventListener {
---    
    //onHeartRateDataReceived method is a ThryveBLEEventListener event listener callback.
    //It is automatically triggered by ThryveSDK each time a Heart Rate ThryveBLEDevice is connected 
    //The data recorded by Heart Rate monitors is shared with the host application 
    func onHeartRateDataReceived(device: ThryveBLEDevice, response: ThryveResponse&#x3C;ThryveBLEHeartRateMeasurement>) {
            guard response.successful else {
                  // Process all [ThryveErrors] in response.errors
                  return 
                }
               let heartRate = response.data 
               //process heartRate. example update UI
               //process the heart rate value with heartRate.heartRateValue.
               //process the sensor contact value with heartRate.sensorContactDetected
    }
---
}
</code></pre>

{% endtab %}

{% tab title="Android" %}

<pre class="language-kotlin"><code class="lang-kotlin">import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.ble
...
<strong>override fun onHeartRateDataReceived(response: ThryveResponse&#x3C;ThryveBLEGattData.Measurement>) {
</strong>    if (!response.successful) {
       // Process all [ThryveError] in response.errors
       return
    } 
    //process measurement reading in response.data
 }
...
</code></pre>

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Data of connected devices is periodically uploaded to the Thryve backend in batches, rather than in real-time. This approach ensures persistent data storage while minimizing network and battery usage on devices.
{% endhint %}


# Camera-based health data recording

Measure health markers like blood pressure, BMI, heart rate (HR), heart rate variability (HRV), and more in just 30 seconds with a face scan using the technology of our partner Shen.ai.

Allow users to record clinically validated vital signs like blood pressure, heart rate, and heart rate variability by scanning their face within your application, just as if they are FaceTiming with a loved one.

<figure><img src="/files/xpn8QSyE8xllIZXJl1CD" alt="" width="188"><figcaption></figcaption></figure>

You can use the face-scanning technology within your application by adding the `ThryveShenAI` module to the SDK.

{% hint style="info" %}
If you would like to understand more on how to get access to [ShenAI](https://shen.ai/) technology via Thryve, please reach out to our business development team.
{% endhint %}

## Integrate ShenAI with your application

{% tabs %}
{% tab title="iOS" %}
To integrate the camera-based health data with your iOS app, you need to integrate the `ThryveShenAI` module in addition to the `ThryveCore` and `ThryveCommons` modules. Follow either the [cocoapods](/integrate-your-mobile-app/setup-thryve-sdk/ios#integration-via-cocoapods) or [framework files](/integrate-your-mobile-app/setup-thryve-sdk/ios#integration-via-frameworks) instructions in the [iOS section](/integrate-your-mobile-app/setup-thryve-sdk/ios).

{% hint style="info" %}
If `ShenaiSDK` added using `Cocoapods`, `ENABLE_USER_SCRIPT_SANDBOXING` must be set to `NO` in Xcode 15+
{% endhint %}

Since it is Camera based you need to ask the user permission to access the Camera. Add the `Privacy - Camera Usage Description` key entry in your info.plist file with the value as the description of why you need to access the user's Camera. See the screenshot below for reference.

<figure><img src="/files/yOaRB1ARnXecGJsvscST" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Android" %}
To integrate the camera-based health data with your Android app, you need to integrate the `thryve_module_shenai` module in addition to the `thryve_core_sdk` and `thryve_module_commons` modules. Integrate following either  the [Thryve Repository Dependencies ](/integrate-your-mobile-app/setup-thryve-sdk/android#integrate-using-thryve-repository-dependencies)or  [Thryve .aar Libraries](https://docs.thryve.health/integrate-your-mobile-app/pages/gd15Xn3eNpfQhy8TrHU5#integrate-using-thryve-.aar-libraries) instructions in the [Android section](https://open.gitbook.com/~site/site_WRtC1/mobile-apps/setup-thryve-sdk/android)
{% endtab %}

{% tab title="React Native" %}
To integrate the camera-based health data with your React Native/Expo app, you need to integrate the `@thryve/react-native-shenai-module` module in addition to the `@thryve/react-native-sdk` . Integrate the following either the [React Native CLI ](/integrate-your-mobile-app/setup-thryve-sdk/react-native#react-native-cli)or  [Expo](/integrate-your-mobile-app/setup-thryve-sdk/react-native#expo) instructions in the [React Native](/integrate-your-mobile-app/setup-thryve-sdk/react-native) section.
{% endtab %}

{% tab title="Flutter" %}
To integrate the camera-based health data with your Flutter app, you need to integrate the `plugin/module_shen_ai` module in addition to the `plugin/thryve_sdk` . Follow the [Flutter integration instructions ](/integrate-your-mobile-app/setup-thryve-sdk/flutter)in the Flutter section.
{% endtab %}
{% endtabs %}

### Configure the `ThryveShenAI` module

When initializing the Thryve SDK ensure to set your ShenAI API key to `shenAIConfig`  and an optional `ThryveShenAIEventListener` in the `ThryveShenAIConfig` .

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveObservability
import ThryveShenAI

let shenAIConfig = ThryveShenAIConfig(
    apiKey: "SHEN_AI_API_KEY",
    eventsListener: self // Optional: make sure your class or struct conform to `ThryveShenAIEventListener` protocol and implements `onEvent(event: ThryveShenAIEvent)` function
)

let thryveSDKConfig = ThryveSDKConfig(
    authId: "AUTH_ID",
    authSecret: "AUTH_SECRET",
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    endUserId: nil, 
    locale: "de",
    configs: [shenAIConfig],
    observability: ObservabilityConfig(tracingEnabled: true,              crashReportingEnabled: true)
)
        
let thryveSDK = await ThryveSDK.getOrCreate(thryveSDKConfig)

// Optionally, when ThryveSDK is initialized from a non-async context (AppDelegate, legacy code, etc.), it is recommended to use the getOrCreate(...) callback to know when the SDK is ready.

ThryveSDK.getOrCreate(thryveSDKConfig) { initResult in
    if initResult.successful {
        Logger.i("ThryveSDK ready, you can start calling API methods")
    } else if let error = initResult.errors?.first {
        Logger.e("ThryveSDK init failed: \(error.errorMessage ?? "Unknown error")")
    }
} 
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk
import com.thryve.sdk.commons
import com.thryve.sdk.shenAI
   
val shenAIConfig = ThryveShenAIConfig(
    apiKey = "SHEN_AI_API_KEY",
    eventsListener = object : ThryveShenAIEventListener {
        override fun onEvent(event: ThryveShenAIEvent) {
            when (event) {
                ThryveShenAIEvent.MEASUREMENT_FINISHED -> { /* Shen AI measurement has finished and is about to be uploaded */}
                ThryveShenAIEvent.MEASUREMENT_FAILED -> { /* Shen AI measurement has failed - handle failure */}
                ThryveShenAIEvent.DATA_UPLOAD_FINISHED -> { /* Shen AI has finished uploading data */}
                ThryveShenAIEvent.DATA_UPLOAD_FAILED -> { /* Shen AI has failed uploading data */}
                ThryveShenAIEvent.USER_SUMMARY_FINISHED -> { /* The Shen AI flow has been completed */ }
            }
        }
    }
 )
    
val thryveSDKConfig = ThryveSDKConfig(
    authId = "ASSIGNED_AUTH_ID",
    authSecret = "ASSIGNED_AUTH_SECRET",
    endUserAlias = "XXXXXXXXXXX",
    endUserId = null, 
    locale = "de",
    bleConfig = bleConfig
)
                 
val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context)

/**Android SDK 5.0.5 introduced an optional callback to communicate the status 
  of internal processes of getOrCreate. ThryveSDK instance can now be created 
  with a callback as shown in the sample code below.  
**/
val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context) { thryveResponse ->
       if(thryveResponse.successful){
           //ThyveSDK initialization processes completed successfully
       } else {
           // ThryveSDK initalization process failed. process the ThryveErrors for the specific reason.
           thryveResponse.errors.map { thryveError -> Logger.e(TAG){" getOrCreate ThryveError in onCreate function $thryveError"} }
       }
  }
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="150.45184326171875">Parameter</th><th width="419.3529052734375">Description</th><th>Mandatory</th></tr></thead><tbody><tr><td><code>apiKey</code></td><td>The apiKey as provided by ShenAI. Please reach out to our support if you're interested in obtaining an api key for ShenAI.</td><td>yes</td></tr><tr><td><code>eventsListener</code></td><td><p>An object of <code>ThryveShenAIEventListener</code> that will be receiving the following events from the ShenAI module.</p><pre><code>MEASUREMENT_FINISHED
MEASUREMENT_FAILED
DATA_UPLOAD_FINISHED
DATA_UPLOAD_FAILED
USER_FLOW_FINISHED
</code></pre></td><td>no</td></tr></tbody></table>

## Trigger camera-based health data measurement

To record and upload all available camera-based health data use the `measure` function

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveShenAI
import ThryveCommons

...
func measure() {
    ThryveSDK.get().measure { response in
        if response.successful, let success = response.data, success {
            Logger.d { "Camera data Measure: Measurement and data upload finished successfully.")
        } else {
            Logger.d { "Camera data Measure failed: \(String(describing: response.errors?.first?.errorMessage ?? "Unknown error"))")")
        }
    }
}
...
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.shenAI

...
fun measure(activity: ComponentActivity){
    ThryveSDK.get()?.measure(activity) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "Camera data Measure successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "Camera data Measure error $error" }
            }
        }
    }
}
...
```

{% endtab %}

{% tab title="React Native" %}

<pre class="language-javascript"><code class="lang-javascript">import { ThryveSDK } from '@thryve/react-native-sdk';
<strong>
</strong>//measure Camera based Health data
export async function measure() {
  const sdk = new ThryveSDK().getOrCreate(thryvSDKConfig);
  try {
    const response = await sdk.measure();
    if (response?.data) {
      //measure was successfull
    } else {
      //measure failed. process all errors.
      response.errors.forEach((error) => {
        console.log(`Camera Health Data measure error ${error}`);
      });
    }
  } catch (err) {
    console.error('❌ Unexpected error', err);
  }finally {
      sdk.finish();
  }
}
</code></pre>

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:thryve_sdk/thryve_sdk.dart';

final class ShenAIPageBloc {
  final ThryveSDK _thryveSDK;
  final Source _dataSource;

  ShenAIPageBloc(this._thryveSDK) : _dataSource = Source.shenAI;

  Future<ThryveResponse<void>> measure() => _thryveSDK.measure(_dataSource.id);

   Future<void> measureCameraHealthData() async {
    final ThryveResponse<void> response = await measure();

    if (!response.isSuccessful) {
      final Iterable<ThryveError> errors = response.errors.whereType<ThryveError>();

      for (final ThryveError error in errors) {
        //process each error here
      }

      throw StateError('Unable to measure health data using ShenAI.');
    }
  }
}
```

{% endtab %}
{% endtabs %}

### Calibration

The ShenAI technology features a calibration option to enhance the accuracy of blood pressure measurements. The feature is triggered using the `calibrate` method of the Thryve SDK. During calibration, users are guided through a process where they provide readings from an external blood pressure monitor. This aids in refining the precision of camera-based measurements. Note that calibration is optional.

{% tabs %}
{% tab title="iOS" %}

```swift
import ThryveCore
import ThryveShenAI
import ThryveCommons

...
func calibrate() {
    ThryveSDK.get().calibrate { response in
        if response.successful, let success = response.data, success {
            Logger.d { "Camera data Calibrate: Measurement and data upload finished successfully.")
        } else {
            Logger.d { "SCamera data Calibrate failed: \(String(describing: response.errors?.first?.errorMessage ?? "Unknown error"))")")
        }
    }
}
...
```

{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk.ThryveSDK
import com.thryve.sdk.shenAI

...
fun calibrate(activity: ComponentActivity){
    ThryveSDK.get()?.calibrate(activity) {
        runOnUiThread {
            Logger.d(this@MainActivity.TAG) { "ShenAI Calibrate successful = ${it.successful} data = ${it.data}" }
            it.errors.map { error ->
                Logger.d(this@MainActivity.TAG) { "ShenAI Calibrate error $error" }
            }
        }
    }
}
...
```

{% endtab %}

{% tab title="React Native" %}
{% hint style="danger" %}
Calibration is not supported in the React Native SDK
{% endhint %}
{% endtab %}

{% tab title="Flutter" %}
{% hint style="danger" %}
Calibration is not supported in the Thryve Flutter SDK
{% endhint %}
{% endtab %}
{% endtabs %}


# Observability

To continuously improve the performance and stability of the Thryve SDK, the framework reports telemetry data like crashes and traces to Thryve's observability backend. Observability data is fully handled by Thryve's own infrastructure and never shared or processed with any 3rd party, ensuring the highest degree of data privacy for your end users.&#x20;

### Integrate Thryve Observability with your application

To integrate Observability into your application, add the `ThryveObservability` module from Thryve's SDK. You can achieve this by adding `ThryveObservability` pods on iOS and dependencies on Android.

{% tabs %}
{% tab title="iOS" %}

```ruby
platform :ios, '13.0'
source 'https://git.thryve.de/thryve/Specs.git'

target 'ThryveConnectorSample' do
 
  use_frameworks!

...
pod 'ThryveObservability', '5.2.2'
...

end
```

{% endtab %}

{% tab title="Android" %}
Using Thryve Maven Repository Dependency:

```kotlin
dependencies {
    ...
    api("com.thryve.sdk:observability:${thryve_sdk_version}")
    ...
}
```

If you are using `.aar` approach, please include below dependencies

```kotlin
dependencies {
    ...
    implementation(files("libs/thryve_module_observability_${thryve_sdk_version}.aar")

    //dependencies for Observability Module
    implementation("io.opentelemetry:opentelemetry-api:$openTelemetryVersion")
    implementation("io.opentelemetry:opentelemetry-sdk:$openTelemetryVersion")
    implementation("io.opentelemetry.semconv:opentelemetry-semconv:$openTelemetrySemanticConventionsVersion")
    implementation("io.opentelemetry:opentelemetry-exporter-otlp:$openTelemetryVersion")// OpenTelemetry Exporters
     ...
}
```

{% endtab %}
{% endtabs %}

### Configure the `ThryveObservability` module

{% tabs %}
{% tab title="iOS" %}

{% code overflow="wrap" %}

```swift
import ThryveCore
import ThryveCommons
import ThryveObservability

let observabilityConfig = ObservabilityConfig(
    tracingEnabled: true, 
    crashReportingEnabled: true
)

let thryveSDKConfig = ThryveSDKConfig(
    authId: "AUTH_ID",
    authSecret: "AUTH_SECRET",
    endUserAlias: "YOUR_UNIQUE_USER_IDENTIFIER",
    endUserId: nil, 
    locale: "de",
    observability: observabilityConfig
)
        
await ThryveSDK.getOrCreate(thryveSDKConfig).getUserInformation()
```

{% endcode %}
{% endtab %}

{% tab title="Android" %}

```kotlin
import com.thryve.sdk
import com.thryve.sdk.commons

val observabilityConfig = ThryveObservabilityConfig(
        tracingEnabled = true,
        crashReportingEnabled = true,
    )
    
val thryveSDKConfig = ThryveSDKConfig(
    authId = "ASSIGNED_AUTH_ID",
    authSecret = "ASSIGNED_AUTH_SECRET",
    endUserAlias = "XXXXXXXXXXX",
    endUserId = null, 
    locale = "de",
    observabilityConfig = observabilityConfig,
)
                 
val thryveSDK = ThryveSDK.getOrCreate(thryveSDKConfig, context) { thryveResponse ->
       if (thryveResponse.successful) {
           // ThryveSDK initialization processes completed successfully
       } else {
           // ThryveSDK initalization process failed, process the ThryveErrors for the specific reason
           thryveResponse.errors.map { thryveError -> Logger.e(TAG) {" getOrCreate ThryveError in onCreate function $thryveError" } }
       }
  }
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
Any updates to the configuration should pass the Observability configuration as well. Failing to pass the configuration to the updated configuration will disable the Observability module.
{% endhint %}

### Module configuration options

When using the Observability module, make sure to define the options in the Observability configuration.&#x20;

<table><thead><tr><th width="218">Parameter</th><th width="381">Description</th><th>Default</th></tr></thead><tbody><tr><td><code>tracingEnabled</code></td><td>When <code>true</code>, information on performance and errors linked to a Thryve user is reported to Thryve's observability backend. Requires import of <code>ThryveObservability</code> module.</td><td>true</td></tr><tr><td><code>crashReportingEnabled</code></td><td>When <code>true</code>, crashes caused by the ThryveSDK will be reported anonymously to Thryve's observability backend.</td><td>true</td></tr></tbody></table>

<details>

<summary>Overview of data shared with Thryve when crash reporting or tracing is enabled</summary>

The following data is processed by Thryve when observability functions are enabled:

#### Crash reporting

When crash reporting is enabled, the following information is sent to Thryve's self-operated observability backend in the event of an app crash:

* crash stack trace
* app information
  * authId
  * bundle/package id
  * state (inactive/active)
  * version
* device information
  * model name
  * operating system
  * operating system version
  * memory size
  * free memory
* session information
  * app start time
  * app uptime
  * app time in foreground
  * timestamps on actions performed by the SDK, e.g. initialization, execution of methods etc.

{% hint style="danger" %}
Crash reports are anonymous and no IP information or other unique identifiers are collected
{% endhint %}

#### Tracing

When tracing is enabled the following information is sent to Thryve's self-operated observability backend:

* app information
  * authId
  * bundle id
  * state (inactive/active)
  * version
* device information
  * model name
  * operating system
  * operating system version
  * memory size
* user information
  * endUserId
* process (trace) information
  * success true/false
  * ThryveErrors
  * start/endTimestamp of process
  * process parameters (e.g. requested HealthKit types, requested timeframes etc.)
  * process metadata (e.g. number of processed data points)

</details>


# Error handling

The `ThryveResponse` class is a generic response interface that provides feedback to the client application. It contains either the `data` parameter, which contains the data requested by the client app, or the `errors` array which contains a list of `ThryveError` objects that should be handled.

The `ThryveError` class contains the following parameters:

| Parameter   | Description                                                                             | Optional |
| ----------- | --------------------------------------------------------------------------------------- | -------- |
| `code`      | The code describing the error.                                                          | No       |
| `httpCode`  | If the related action was a failed network request it may contain the HTTP status code. | Yes      |
| `message`   | Message describing the error                                                            | Yes      |
| `throwable` | `Throwable` providing more details about the error.                                     | Yes      |
| `metadata`  | `MetaData` object providing additional data to clarify the context of `ThryveError`.    | Yes      |

#### Error Codes

When handling responses, the `ThryveError` class uses predefined error codes returned as the `code` parameter to help identify specific issues. These codes are divided in several groups that indicate a specific error

| Code       | Description                                  |
| ---------- | -------------------------------------------- |
| 1xxx       | Errors related to the device or its hardware |
| 2xxx       | Errors related to the device's network       |
| 3xxx       | Errors related to encryption                 |
| 1xxx, 2xxx | Core Thryve SDK errors                       |
| 5xxx       | Thryve Shen AI module errors                 |
| 6xxx       | Thryve Samsung Health module errors          |
| 7xxx       | Thryve Apple Health module errors            |
| 8xxx       | Thryve BLE module errors                     |
| 9xxxx      | Thryve Health Connect module errors          |

Several of these network codes (for example `CoreErrorMap.NO_NETWORK_CONNECTION` which has the code `1000`) can be returned by several functions, since they might be executing a network request to fetch certain data. Understanding and handling these error codes efficiently is crucial for effective error handling and debugging in client applications. Refer to the Thryve Sample App for error handling best practices.


# Create Thryve user

When you integrate Thryve with your web application, you will need to first create a Thryve user. All data connections and data stored at Thryve are always linked to a Thryve user. Unlike mobile apps using the Thryve SDK, where user management is handled automatically, web applications need to manually create a new user or retrieve an existing one using the `accessToken` interface.

{% hint style="warning" %}
Please note that `accessToken/authenticationToken` is used synonymous to `endUserId` and is used in the Thryve API v5. The same is true for `partnerUserId` and `endUserAlias` parameters. With the introduction of Thryve API v6, all interfaces will migrate to use `endUserId`  and `endUserAlias`.
{% endhint %}

We recommend setting an alias for the Thryve user. We call this the `partnerUserID`. (or `endUserAlias` ). Please ensure that the alias is an unguessable string generated, e.g., through a hash function. We suggest at least 32 digits, which may contain both digits, characters, and a dash „-„, as a special character. A `partnerUserID` can have a maximum length of 80 characters.

## Get accessToken of new or existing user

> Retrieve an accessToken for a Thryve user. Automatically creates a user if partnerUserID is empty or no existing user with specified partnerUserID exists.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/accessToken":{"post":{"summary":"Get accessToken of new or existing user","tags":["End User"],"description":"Retrieve an accessToken for a Thryve user. Automatically creates a user if partnerUserID is empty or no existing user with specified partnerUserID exists.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/AccessTokenRequest"}}}},"responses":{"200":{"description":"Request successful. Returns the accessToken of a user.","content":{"text/plain":{"schema":{"$ref":"#/components/schemas/AccessTokenResponse"}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"AccessTokenRequest":{"type":"object","properties":{"partnerUserID":{"type":"string","description":"Set this optional parameter to add your an alias to a Thryve user. If no alias is set, it is not possible to retrieve an accessToken/authenticationToken for an existing user. Newer interfaces call this parameter endUserAlias."}}},"AccessTokenResponse":{"type":"string"},"ErrorResponse":{"type":"string"}}}}
```


# Connect data sources

The Thryve Connection Widget allows end users to seamlessly manage data source connections within your application. There is no need for additional views or logic from your side. Simply embed the widget's URL, provided by the API, into your web application. This will display all available data sources and their connection statuses to your users.

<figure><img src="/files/GYon1FGHKQPneKHozx5C" alt="" width="188"><figcaption><p>Thryve Connection Widget sample for a user connected to Strava</p></figcaption></figure>

{% hint style="info" %}
The Connection Widget must be embedded in your app using an iframe component. Opening the URL in a new tab or window will prevent the widget from properly redirecting users back to your web app.
{% endhint %}

{% hint style="warning" %}
Before requesting the Connection Widget, ensure you [create a Thryve user](/integrate-your-web-app/create-thryve-user). The returned `endUserId` (`accessToken`) is required to generate the Connection Widget.
{% endhint %}

## POST /widget/v6/connection

> Returns Thryve Connection Widget for requesting user

```json
{"openapi":"3.1.0","info":{"title":"Connection Widget API","version":"1.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/widget/v6/connection":{"post":{"tags":["Widgets"],"summary":"Returns Thryve Connection Widget for requesting user","description":null,"parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"description":null,"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestEndUserConnectionWidget"}}}},"responses":{"200":{"description":"Successful response containing URL of Thryve Widget for requesting user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseEndUserConnectionWidget"}}}},"400":{"description":"Bad Request – invalid input parameters."},"500":{"description":"Internal Server Error."}}}}},"components":{"schemas":{"RequestEndUserConnectionWidget":{"type":"object","properties":{"endUserId":{"type":"string","description":"The end user identifier. The data source connected via the Widget session will be linked to this user."},"locale":{"enum":["ar","bg","cs","en","da","de","el","es","et","fi","fr","hu","id","it","ja","ko","lt","lv","nl","pl","pt","ro","ru","sk","sl","sv","tr","uk"],"description":"Manually set the language code following ISO 639-1 to set the language that will be used on UI elements, e.g. the Thryve Widget. If not set it will default to english."}},"required":["endUserId"]},"ResponseEndUserConnectionWidget":{"type":"object","properties":{"type":{"enum":["enduser.widget.connection"]},"data":{"type":"object","properties":{"url":{"type":"string","description":"The URL for the Thryve Connection Widget for the requested user. The URL will expire."}},"required":["url"]}},"required":["type","data"]}}}}
```


# Build your custom data source connection screen

To create a custom UI for data source connections, bypass the default Connection Widget for greater control. This method is ideal if you wish to pre-select data sources or seamlessly integrate connections into existing workflows. The process: display your data sources list, user clicks a source, you generate a direct connection URL, redirect them to authenticate their account (e.g., Fitbit or Strava), and they return to your app.&#x20;

## Implementation

### Step 1: Get the Connection Session Token

To generate a session for your end user, call the connection widget endpoint at [`widget/v6/connection`](/connect-data-sources). The response URL will include a `connectionSessionToken` parameter.

```json
{
    "type": "enduser.widget.connection",
    "data": {
        "url": "https://connect.thryve.de/?connectionSessionToken=1060285265X4247109939067552841&platform=web&lang=en"
    }
}
```

Use the `connectionSessionToken` (in our example `1060285265X4247109939067552841` ) from the URL to generate direct connection URLs to a Thryve web data source, bypassing the connection widget.

### Step 2: Construct Direct Connection URLs

To create URLs for connection and disconnection using the `connectionSessionToken`, follow these guidelines:

**For connecting a data source:**

```
https://service2.und-gesund.de/dataSourceDirectConnection.html?token={{connectionSessionToken}}&dataSource={{dataSourceId}}&redirect_uri={{redirectURL}}
```

**For disconnecting a data source:**

```
https://service2.und-gesund.de/dataSourceDirectRevoke.html?token={{connectionSessionToken}}&dataSource={{dataSourceId}}&direct=true&redirect_uri={{redirectURL}}
```

Set the extracted `connectionSessionToken` in the token parameter. Also, specify the data source you want to connect/disconnect using the id of the data source. (refer [this table](https://docs.thryve.health/thryve-data-sources/overview) for all data source IDs).

#### Set a redirection back to your application

Specify the optional `redirect_uri` parameter to direct users to a desired location in your application after they complete the connection or disconnection of a data source. This parameter helps ensure a smooth transition after users leave your application for authorization.

{% hint style="warning" %}
For security reasons, Thryve stores and validates redirect URLs on the backend. Please notify customer operations about the redirect URLs you plan to use so they can be whitelisted.
{% endhint %}

### Step 3: Open the connection/disconnection URL

To open the constructed URL, follow these guidelines:

* **With `redirect_uri` parameter:** Open the URL in the same window. The user will be directed to the data source authorization process and then returned to your application in the same window.
* **Without `redirect_uri` parameter:** Open the URL in a new tab. The user will see the default Thryve result page and can manually close the tab.

{% hint style="info" %}
For disconnections you do not need to actually make the user open the URL. Simply create a GET request using the constructed URL and the disconnection will be initiated in the background.
{% endhint %}

### Step 4: Handle the Result

After completing the OAuth flow, the Thryve server will automatically redirect to `dataSourceDirectConnectionResult.html`.

The URL parameter `connected` indicates the outcome:

* For connection requests:
  * `connected=true`: Success
  * `connected=false`: Failure or cancellation
* For revoke requests:
  * `connected=false`: Successful disconnection
  * `connected=true`: Failed disconnection<br>

Direct connection result example URL:

```
https://service2.und-gesund.de/dataSourceDirectConnectionResult.html?token=1895281956X7991751761968409822&dataSource=1&connected=true
```

If a redirect URL is included, the connection result will also be forwarded to your specified URL.


# Embed Visualization Widget (Beta)

Embed predefined visualizations of your users' data in your web app with the Thryve Visualization Widget. Request a visualization by specifying the *template ID* and optional parameters in a REST API call. Then embed the returned URL in an iframe.

The API request creates a `visualizationSessionToken` that the widget uses to authorize and identify the user. For security, the token expires after 15 minutes. Your web app must handle expiration and create a new session.

{% hint style="info" %}
Visualization widgets are in **beta**. We plan to add more templates over time. If you want a new template or have feedback on an existing one, contact our product team through the support center.
{% endhint %}

### Templates

| templateId | Name                                                                     |
| ---------- | ------------------------------------------------------------------------ |
| `100`      | [Daily Totals](/thryve-product-overview/visualize-beta#daily-totals)     |
| `101`      | [Social Jet Lag](/thryve-product-overview/visualize-beta#social-jet-lag) |

## Create a visualization session

> Creates a new visualization session for the given end user and template. Returns a short-lived URL to be embedded in an iframe or WebView.<br>

```json
{"openapi":"3.0.3","info":{"title":"Thryve Visualization Widget API","version":"6.0.0"},"servers":[{"url":"https://api.thryve.de","description":"Thryve public API"}],"paths":{"/widget/v6/visualization":{"post":{"summary":"Create a visualization session","description":"Creates a new visualization session for the given end user and template. Returns a short-lived URL to be embedded in an iframe or WebView.\n","parameters":[{"in":"header","name":"Authorization","required":true,"schema":{"type":"string"},"description":"Basic Auth credentials for the customer account. Format: `Basic <base64(username:password)>`.\n"},{"in":"header","name":"AppAuthorization","required":true,"schema":{"type":"string"},"description":"Basic Auth credentials for the app. Format: `Basic <base64(authId:authSecret)>`.\n"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisualizationWidgetRequest"}}}},"responses":{"200":{"description":"Session created. Embed the returned `url` in an iframe or WebView.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VisualizationWidgetResponse"}}}},"400":{"description":"Request validation failed. Typically caused by an invalid `endUserId` format, a missing required field, an unrecognised `config` property, or an invalid field value.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"The specified `templateId` does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"VisualizationWidgetRequest":{"type":"object","required":["endUserId","templateId"],"properties":{"endUserId":{"type":"string","description":"Thryve end user identifier. This is the same identifier returned when the user was created.\n"},"templateId":{"type":"integer","enum":[100,101],"description":"Visualization template to render."},"locale":{"type":"string","description":"ISO 639-1 locale code. Controls the widget's display language. Defaults to `en`. Available languages: `ar`,`bg,`cs`,`da`,`de`,`el`,`en`,`es`,`et`,`fi`,`fr`,`hu`,`id`,`it`,`ja`,`ko`,`lt`,`lv`,`nl`,`pl`,`pt`,`ro` ,`ru`, `sk`, `sl`, `sv`, `tr`, `uk`"},"config":{"type":"object","description":"Template-specific configuration. All fields are optional and fall back to server-side defaults when omitted. Shape depends on `templateId` — see Templates section.\n"}},"title":"VisualizationWidgetRequest"},"VisualizationWidgetResponse":{"type":"object","required":["url","visualizationSessionToken","locale"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri"},"visualizationSessionToken":{"type":"string"},"locale":{"type":"string"}},"title":"VisualizationWidgetResponse"},"ErrorResponse":{"type":"object","required":["error"],"additionalProperties":false,"properties":{"error":{"type":"object","required":["code","message"],"additionalProperties":false,"properties":{"code":{"type":"string","enum":["VALIDATION_ERROR","APP_AUTH_FAILED","END_USER_INVALID","NOT_FOUND","INTERNAL_ERROR","HDA_API_ERROR"],"description":"Stable error code for programmatic handling."},"message":{"type":"string","description":"Human-readable error summary."},"details":{"type":"array","description":"Field-level detail. Present on 400 and 401 responses.","items":{"type":"object","required":["field","issue"],"additionalProperties":false,"properties":{"field":{"type":"string"},"issue":{"type":"string"}}}}}}},"title":"ErrorResponse"}}}}
```

###


# Notifications

Thryve sends, if enabled, proactive notifications for new or updated user data through webhooks. These notifications will be sent as POST requests to a designated HTTPS URL (Port 443). The webhooks are triggered when:

* A user connects or disconnects a data source.
* New epoch or daily data is stored, or existing data is updated.

Ensure to respond to the request with a `200` or `204` within 2 seconds. Failed deliveries will be retried up to 3 times. Recurring failed deliveries within a certain timeframe will lead to the automatic disabling of webhooks.&#x20;

{% hint style="warning" %}
We recommend queuing received payloads by your endpoint before applying any further processing/data storage to ensure adequate response times.
{% endhint %}

## Configuration

Webhooks can be enabled or disabled for each data dimension (epoch/daily/measurement). To enable webhooks, you need a functioning public Webhook URL, which can be set up in the Thryve dashboard. You can also add custom authentication to secure your webhook endpoint using web authentication, configurable through the Thryve Dashboard.

{% hint style="info" %}
If you still use webhooks in old webhook format and would like to switch to the new webhook format, please reach out to our support team.
{% endhint %}

## Data source connection/disconnection webhook

When enabled, this webhook will trigger whenever a user connects or disconnects a data source.

{% tabs %}
{% tab title="ISO timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "iso",
    "type": "notification.source.connect",
    "data": {
        "timestamp": "2022-09-07T17:40:00Z",
        "dataSourceId": 1
    }
}
```

{% endtab %}

{% tab title="Unix timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "unix",
    "type": "notification.source.connect",
    "data": {
        "timestamp": 1662572400000,
        "dataSourceId": 1
    }
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="159.96783447265625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>endUserId</code></td><td>String containing the unique identifier of a user in Thryve's system. Auto-generated upon user creation. Formerly known as <code>accessToken</code>.</td></tr><tr><td><code>endUserAlias</code></td><td>String containing the optional alias set by you when creating a user. Formerly known as <code>partnerUserId</code>. Only returned if not <code>null</code>.</td></tr><tr><td><code>timestampType</code></td><td>String specifying the timestamps to expect in the data object. <code>iso</code> or <code>unix</code>. Can be configured in Thryve Dashboard (coming soon)</td></tr><tr><td><code>type</code></td><td>String specifying the payload structure and event to expect in the <code>data</code> object. <code>webhook.source.connect</code> or <code>webhook.source.disconnect</code>.</td></tr><tr><td><code>timestamp</code></td><td>Specifies when the connection/disconnection happened. Either string with the date and time in utc (<code>iso</code>) or integer with timestamp in milliseconds (<code>unix</code>).</td></tr><tr><td><code>dataSourceId</code></td><td>Integer specifying the <code>dataSourceId</code> new the connection/disconnection has happend for.</td></tr></tbody></table>

## Epoch data creation/update webhook

When enabled, this webhook will trigger whenever new data is stored for a data source or existing data is updated. Updates occur if the `endTimestamp` or `value` of an epoch data point change.

{% tabs %}
{% tab title="ISO timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "iso",
    "type": "notification.data.epoch.createupdate",
    "data": {
        "startTimestamp": "2022-09-07T17:40:00Z",
        "endTimestamp": "2022-09-07T20:05:00Z",
        "dataSourceId": 1,
        "dataTypeIds":
        [
            1000, 1001
        ]
    }
}
```

{% endtab %}

{% tab title="Unix timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "unix",
    "type": "notification.data.epoch.createupdate",
    "data": {
        "startTimestamp": 1662572400000,
        "endTimestamp": 1662581100000,
        "dataSourceId": 1,
        "dataTypeIds":
        [
            1000, 1001
        ]
    }
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="159.546875">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>endUserId</code></td><td>String containing the unique identifier of a user in Thryve's system. Auto-generated upon user creation. Formerly known as <code>accessToken</code>.</td></tr><tr><td><code>endUserAlias</code></td><td>String containing the optional alias set by you when creating a user. Formerly known as <code>partnerUserId</code>. Only returned if not <code>null</code>.</td></tr><tr><td><code>timestampType</code></td><td>String specifying the timestamps to expect in the data object. <code>iso</code> or <code>unix</code>. Can be configured in Thryve Dashboard (coming soon)</td></tr><tr><td><code>type</code></td><td>String specifying the payload structure to expect in the <code>data</code> object. Always <code>notification.data.epoch.createupdate</code>.</td></tr><tr><td><code>startTimestamp</code></td><td>Specifies the start of the period containing new data. Either string with the date and time in utc (<code>iso</code>) or integer with timestamp in milliseconds (<code>unix</code>).</td></tr><tr><td><code>endTimestamp</code></td><td>Specifies the end of the period containing new data. Either string with the date and time in utc (<code>iso</code>) or integer with timestamp in milliseconds (<code>unix</code>).</td></tr><tr><td><code>dataSourceId</code></td><td>Integer specifying the <code>dataSourceId</code> new data has been stored for.</td></tr><tr><td><code>dataTypeIds</code></td><td>Array containing the <code>dataSourceIds</code> new data has been stored for.</td></tr></tbody></table>

## Daily data creation/update webhook

When enabled, this webhook will trigger whenever new data is stored for a data source or existing data is updated. Updates occur if the `value` or `generationType` of a daily data point change.

{% tabs %}
{% tab title="ISO timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "iso",
    "type": "notification.data.daily.createupdate",
    "data": {
        "startDay": "2022-09-07",
        "endDay": "2022-09-07",
        "dataSourceId": 1,
        "dataTypeIds":
        [
            1000, 1001
        ]
    }
}
```

{% endtab %}

{% tab title="Unix timestamp example" %}

```json
{
    "endUserId": "123accessToken",
    "endUserAlias": "YourEndUserAlias",
    "timestampType": "unix",
    "type": "notification.data.daily.createupdate",
    "data": {
        "startDay": 1662572400000,
        "endDay": 1662581100000,
        "dataSourceId": 1,
        "dataTypeIds":
        [
            1000, 1001
        ]
    }
}
```

{% endtab %}
{% endtabs %}

<table><thead><tr><th width="160.32379150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>endUserId</code></td><td>String containing the unique identifier of a user in Thryve's system. Auto-generated upon user creation. Formerly known as <code>accessToken</code>.</td></tr><tr><td><code>endUserAlias</code></td><td>String containing the optional alias set by you when creating a user. Formerly known as <code>partnerUserId</code>. Only returned if not <code>null</code>.</td></tr><tr><td><code>timestampType</code></td><td>String specifying the timestamps to expect in the data object. <code>iso</code> or <code>unix</code>. Can be configured in Thryve Dashboard (coming soon)</td></tr><tr><td><code>type</code></td><td>String specifying the payload structure to expect in the <code>data</code> object. Always <code>notification.data.daily.createupdate</code>. </td></tr><tr><td><code>startDay</code></td><td>Specifies the start of the period containing new data. Either string with the date (<code>iso</code>) or integer with timestamp in milliseconds (<code>unix</code>).</td></tr><tr><td><code>endDay</code></td><td>Specifies the end of the period containing new data. Either string with the date (<code>iso</code>) or integer with timestamp in milliseconds (<code>unix</code>).</td></tr><tr><td><code>dataSourceId</code></td><td>Integer specifying the <code>dataSourceId</code> new data has been stored for.</td></tr><tr><td><code>dataTypeIds</code></td><td>Array containing the <code>dataSourceIds</code> new data has been stored for.</td></tr></tbody></table>


# Data push

Thryve can directly send new and updated end user data to your system through webhooks so that you don't have to do any API calls to receive the newest data.

The data will be sent as POST requests to a designated HTTPS URL (Port 443). The webhook content is compressed using zstd to reduce payload sizes and improve network time.&#x20;

Please ensure your endpoint accepts requests with `"CONTENT-TYPE": "application/json"` and `"CONTENT-ENCODING": "zstd"` . Data integrity and authenticity can be ensured by configuring an HMAC secret.

Respond to the request with a `200` or `204` within 2 seconds. Failed deliveries will be retried up to 3 times. Recurring failed deliveries within a certain timeframe will lead to the automatic disabling of webhooks.&#x20;

{% hint style="warning" %}
We recommend queuing received payloads by your endpoint before applying any further processing/data storage to ensure adequate response times.
{% endhint %}

## Configuration

Data push webhooks can be enabled or disabled for each data dimension (epoch/daily/measurement). To enable webhooks, you need a functioning public Webhook URL. You can also add custom authentication to secure your webhook endpoint using web authentication

In Thryve Dashboards, perform all configurations and trigger test webhook sending to your endpoint.

#### Content configuration

Webhooks can be sent using unix timestamps or timestamps following ISO 8601 depending on your preference. Optional parameters like dataSourceName and additional details can be enabled/disabled to optimize payload size for your needs and to only return the information you actually are interested in.

In Thryve Dashboards, perform all configurations and trigger test webhook sending to your endpoint.

## Epoch data push webhook

When enabled, this webhook will trigger whenever new data is stored for a data source or existing data is updated.&#x20;

{% tabs %}
{% tab title="ISO timestamp example" %}

```json
{
  "endUserId": "123accessToken",
  "endUserAlias": "YourEndUserAlias",
  "timestampType": "ISO",
  "type": "event.data.epoch.create", // or "event.data.epoch.update"
  "data": {
    "dataSourceId": 5,
    "dataSourceName": "Apple",
    "epochData": [
      {
        "startTimestamp": "2022-09-07T19:39:32Z",
        "endTimestamp": "2022-09-07T19:45:02Z",
        "timezoneOffset": 0,
        "dataTypeId": 1000,
        "value": "53.0",
        "additionalDetails": {
          "creationTimestamp": "2022-09-07T19:45:05Z",
          "dataTypeName": "Steps",
          "valueType": "DOUBLE",
          "thirdPartyDataSourceId": 1,
          "thirdPartyDataSourceName": "UNKNOWN",
          "measurementReference": 9007163812253719,
          "generationType": "MANUAL_ENTRY",
          "trustworthiness": "doubt_from_device_source",
          "medicalGrade": false,
          "chronologicalExactness": 15
        }
      }
    ]
  }
}
```

{% endtab %}

{% tab title="Unix timestamp example" %}

```json
{
  "endUserId": "123accessToken",
  "endUserAlias": "YourEndUserAlias",
  "timestampType": "UNIX",
  "type": "event.data.epoch.create", // or "event.data.epoch.update"
  "data": {
    "dataSourceId": 5,
    "dataSourceName": "Apple",
    "epochData": [
      {
        "startTimestamp": 1662579572000,
        "endTimestamp": 1662579902000,
        "timezoneOffset": 0,
        "dataTypeId": 1000,
        "value": "53.0",
        "additionalDetails": {
          "creationTimestamp": 1662579905000,
          "dataTypeName": "Steps",
          "valueType": "DOUBLE",
          "thirdPartyDataSourceId": 1,
          "thirdPartyDataSourceName": "UNKNOWN",
          "measurementReference": 9007163812253719,
          "generationType": "MANUAL_ENTRY",
          "trustworthiness": "doubt_from_device_source",
          "medicalGrade": false,
          "chronologicalExactness": 15
        }
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

### Epoch data push schema

#### Webhook object

<table><thead><tr><th width="160.32379150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>endUserId</code></td><td>String containing the unique identifier of a user in Thryve's system. Auto-generated upon user creation. Formerly known as <code>accessToken</code>.</td></tr><tr><td><code>endUserAlias</code></td><td>Optional. String containing the optional alias set by you when creating a user. Formerly known as <code>partnerUserId</code>. Only returned if configured and not <code>null</code>.</td></tr><tr><td><code>timestampType</code></td><td>String specifying the timestamps to expect in the data object. <code>iso</code> or <code>unix</code>.</td></tr><tr><td><code>type</code></td><td>String specifying the payload structure to expect in the <code>data</code> object. <code>event.data.epoch.create</code> for new data <code>event.data.epoch.update</code> for updated data. </td></tr><tr><td><code>data</code></td><td>Object containing content according to <code>type</code>.</td></tr></tbody></table>

#### Data source object

<table><thead><tr><th width="160.32379150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>dataSourceId</code></td><td>Integer specifying the data source new data has been stored for.</td></tr><tr><td><code>dataSourceName</code></td><td>Optional. String containing the name of the data source.</td></tr><tr><td><code>epochData</code></td><td>Array containing list of new or updated epoch data.</td></tr></tbody></table>

#### Epoch object

<table><thead><tr><th width="168.5833740234375">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>startTimestamp</code></td><td>String when ISO formatted timestamp, Integer when unix timestamp in milliseconds</td></tr><tr><td><code>endTimestamp</code></td><td>String when ISO formatted timestamp, Integer when unix timestamp in milliseconds. Not returned if null.</td></tr><tr><td><code>timezoneOffset</code></td><td>Integer describing the offset to UTC in minutes. Not returned if null.</td></tr><tr><td><code>dataTypeId</code></td><td>Integer specifying the data type.</td></tr><tr><td><code>value</code></td><td>String containing the value of the data point.</td></tr><tr><td><code>additionalDetails</code></td><td>Object containing optional additional information if configured.</td></tr></tbody></table>

#### Additional details object

<table><thead><tr><th width="234.85504150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>creationTimestamp</code></td><td>Timestamp when data was received by Thryve. String when ISO formatted timestamp, Integer when unix timestamp in milliseconds</td></tr><tr><td><code>dataTypeName</code></td><td>String containing the name of the data type.</td></tr><tr><td><code>valueType</code></td><td>String containing what value to expect. </td></tr><tr><td><code>thirdPartyDataSourceId</code></td><td>Integer specifying the third party that recorded the data. Not returned if null</td></tr><tr><td><code>thirdPartyDataSourceName</code></td><td>String containing the name of the third party data source. Not returned if null.</td></tr><tr><td><code>measurementReference</code></td><td>Integer containing the reference of the measurement object this data point belongs to. Not returned if null</td></tr><tr><td><code>generationType</code></td><td>String containing information how data was recorded if available. Not returned if null</td></tr><tr><td><code>trustworthiness</code></td><td>String containing information on data quality if available. Not returned if null</td></tr><tr><td><code>medicalGrade</code></td><td>Boolean indicating if data was recorded by a medical grade sensor, e.g. an FDA-approved medical device. Not returned if null.</td></tr><tr><td><code>chronologicalExactness</code></td><td>Integer indicating potential deviations from timestamps, measured in minutes. Not returned if null.</td></tr></tbody></table>

## Daily data push webhook

When enabled, this webhook will trigger whenever new data is stored for a data source or existing data is updated.&#x20;

{% tabs %}
{% tab title="ISO timestamp example" %}

```json
{
  "endUserId": "123accessToken",
  "endUserAlias": "YourEndUserAlias",
  "timestampType": "ISO",
  "type": "event.data.daily.create", // or "event.data.daily.update"
  "data": {
    "dataSourceId": 5,
    "dataSourceName": "Apple",
    "epochData": [
      {
        "day": "2022-09-07",
        "timezoneOffset": 0,
        "dataTypeId": 1000,
        "value": "11203",
        "additionalDetails": {
          "creationTimestamp": "2022-09-07T19:45:05Z",
          "dataTypeName": "Steps",
          "valueType": "LONG",
          "trustworthiness": "doubt_from_device_source",
          "chronologicalExactness": 15
        }
      }
    ]
  }
}
```

{% endtab %}

{% tab title="Unix timestamp example" %}

```json
{
  "endUserId": "123accessToken",
  "endUserAlias": "YourEndUserAlias",
  "timestampType": "ISO",
  "type": "event.data.daily.create", // or "event.data.daily.update"
  "data": {
    "dataSourceId": 5,
    "dataSourceName": "Apple",
    "epochData": [
      {
        "day": 1662508800000,
        "timezoneOffset": 0,
        "dataTypeId": 1000,
        "value": "11203",
        "additionalDetails": {
          "creationTimestamp": 1662579905000,
          "dataTypeName": "Steps",
          "valueType": "LONG",
          "trustworthiness": "doubt_from_device_source",
          "chronologicalExactness": 15
        }
      }
    ]
  }
}
```

{% endtab %}
{% endtabs %}

### Daily data push schema

#### Webhook object

<table><thead><tr><th width="160.32379150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>endUserId</code></td><td>String containing the unique identifier of a user in Thryve's system. Auto-generated upon user creation. Formerly known as <code>accessToken</code>.</td></tr><tr><td><code>endUserAlias</code></td><td>Optional. String containing the optional alias set by you when creating a user. Formerly known as <code>partnerUserId</code>. Only returned if configured and not <code>null</code>.</td></tr><tr><td><code>timestampType</code></td><td>String specifying the timestamps to expect in the data object. <code>iso</code> or <code>unix</code>.</td></tr><tr><td><code>type</code></td><td>String specifying the payload structure to expect in the <code>data</code> object. <code>event.data.daily.create</code> for new data <code>event.data.daily.update</code> for updated data. </td></tr><tr><td><code>data</code></td><td>Object containing content according to <code>type</code>.</td></tr></tbody></table>

#### Data source object

<table><thead><tr><th width="160.32379150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>dataSourceId</code></td><td>Integer specifying the data source new data has been stored for.</td></tr><tr><td><code>dataSourceName</code></td><td>Optional. String containing the name of the data source.</td></tr><tr><td><code>dailyData</code></td><td>Array containing list of new or updated daily data.</td></tr></tbody></table>

#### Daily object

<table><thead><tr><th width="168.5833740234375">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>day</code></td><td>String when ISO formatted timestamp, Integer when unix timestamp in milliseconds for midnight (day start) in UTC.</td></tr><tr><td><code>timezoneOffset</code></td><td>Integer describing the offset to UTC in minutes. Not returned if null.</td></tr><tr><td><code>dataTypeId</code></td><td>Integer specifying the data type.</td></tr><tr><td><code>value</code></td><td>String containing the value of the data point.</td></tr><tr><td><code>additionalDetails</code></td><td>Object containing optional additional information if configured.</td></tr></tbody></table>

#### Additional details object

<table><thead><tr><th width="234.85504150390625">Parameter</th><th>Description</th></tr></thead><tbody><tr><td><code>creationTimestamp</code></td><td>Timestamp when data was received by Thryve. String when ISO formatted timestamp, Integer when unix timestamp in milliseconds</td></tr><tr><td><code>dataTypeName</code></td><td>String containing the name of the data type.</td></tr><tr><td><code>valueType</code></td><td>String containing what value to expect. </td></tr><tr><td><code>generationType</code></td><td>String containing information how data was recorded if available. Not returned if null</td></tr><tr><td><code>trustworthiness</code></td><td>String containing information on data quality if available. Not returned if null</td></tr><tr><td><code>chronologicalExactness</code></td><td>Integer indicating potential deviations from timestamps, measured in minutes. Not returned if null.</td></tr></tbody></table>


# Get epoch data

`DynamicEpochValues` represents a period that is composed of a start and end timestamp. This data type is available up to second precision. The `DynamicEpochValue` REST-API allows for data retrieval of one user.&#x20;

Please check the [data type documentation](/thryve-product-overview/access/data-types-biomarker) for valueTypes (dataTypeIds) definitions and availability.

## Retrieve DynamicEpochValues for a user

> Retrieve harmonized intraday measurements (e.g., heart rate) for one user within a specified time range.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/dynamicEpochValues":{"post":{"summary":"Retrieve DynamicEpochValues for a user","tags":["Health Data"],"description":"Retrieve harmonized intraday measurements (e.g., heart rate) for one user within a specified time range.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/DynamicEpochValuesRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an array of DynamicEpochValues per user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DynamicEpochValuesResponseItem"}}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DynamicEpochValuesRequest":{"type":"object","required":["authenticationToken"],"oneOf":[{"required":["startTimestamp","endTimestamp"]},{"required":["startTimestampUnix","endTimestampUnix"]}],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"startTimestamp":{"type":"string","description":"ISO 8601 timestamp for the beginning of the period"},"endTimestamp":{"type":"string","description":"ISO 8601 timestamp for the end of the period"},"startTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the beginning of the period"},"endTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the end of the period"},"valueTypes":{"type":"string","description":"Comma-separated Thryve DataType IDs to filter by."},"dataSources":{"type":"string","description":"Comma-separated Thryve data source IDs to filter by."},"detailed":{"type":"boolean","description":"If true, includes additional recording information."},"displayTypeName":{"type":"boolean","description":"If true, includes data type names (STRING) in the response."},"displayPartnerUserID":{"type":"boolean","description":"If true, includes the partnerUserID in the response."}}},"DynamicEpochValuesResponseItem":{"type":"object","properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"partnerUserID":{"type":"string","description":"The optional alias set by the developer when creating a user. Newer interfaces call this parameter endUserAlias."},"dataSources":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the data source (e.g., 8 for Garmin)."},"data":{"type":"array","items":{"type":"object","properties":{"startTimestamp":{"type":"string","description":"Start timestamp as ISO 8601 timespamp in UTC."},"endTimestamp":{"type":"string","description":"End timestamp as ISO 8601 timespamp in UTC (null if instant measurement)."},"createdAt":{"type":"string","description":"ISO 8601 timespamp in UTC when data point was created/updated in the data warehouse."},"startTimestampUnix":{"type":"integer","description":"Start timestamp in Unix milliseconds."},"endTimestampUnix":{"type":"integer","description":"End timestamp in Unix milliseconds (null if instant measurement)."},"createdAtUnix":{"type":"integer","description":"Unix timestamp when data point was created/updated in the data warehouse."},"dynamicValueType":{"type":"integer","description":"Thryve DataTypeID (e.g., 3000 for HeartRate)."},"dynamicValueTypeName":{"type":"string","description":"Name of the dynamic value type (e.g., 'HeartRate')."},"details":{"type":"object","description":"Optional JSON object with additional recording information."},"value":{"type":"string","description":"Value of the measurement."},"valueType":{"type":"string","description":"Type of value provided (LONG, DOUBLE, STRING, DATE, BOOLEAN)."}}}}}}}}},"ErrorResponse":{"type":"string"}}}}
```

{% hint style="warning" %}
When retrieving the desired data period, a startTimestamp(Unix) endTimestamp(Unix) or a createdAfter(Unix) date needs to be added as parameters to the request.\
If both startDay and startTimestampUnix are provided, the system will use the ISO format and ignore the Unix timestamps entirely.\
The query range is set to a maximum of 30 days.
{% endhint %}

{% hint style="info" %}
The response will include all values that overlap with the date range specified in the request. E.g., a user has the epoch values with timestamps 10:00:00 - 10:04:00 and 10:06:00 - 10:10:00, and the timestamps specified in the POST request are 10:02:00 - 10:08:00, the response will contain both epoch values.
{% endhint %}

{% hint style="info" %}
The end timestamp will be `null`, if the epoch entry indicates an instant measurement, such as a weight or heart rate value.
{% endhint %}


# Get daily data

`DailyDynamicValues` represent a direct relation of one day as one value. Due to the nature of this data type, only one data point can exist per Thryve Biomarker per day. `DailyDynamicValues` can be, e.g., the sum of all steps a person took in a day. The value (e.g., the daily steps) of `DailyDynamicValues` are updated throughout the day.

Please check the [data type documentation](/thryve-product-overview/access/data-types-biomarker) for valueTypes (dataTypeIds) definitions and availability.

## Retrieve DailyDynamicValues for a user

> Retrieve harmonized daily aggregated data (e.g., daily steps) for one user within a specified time range.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/dailyDynamicValues":{"post":{"summary":"Retrieve DailyDynamicValues for a user","tags":["Health Data"],"description":"Retrieve harmonized daily aggregated data (e.g., daily steps) for one user within a specified time range.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/DailyDynamicValuesRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an array of DailyDynamicValues per user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DailyDynamicValuesResponseItem"}}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DailyDynamicValuesRequest":{"type":"object","required":["authenticationToken"],"oneOf":[{"required":["startDay","endDay"]},{"required":["startTimestampUnix","endTimestampUnix"]}],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"startDay":{"type":"string","description":"Day timestamp following ISO 8601 for the start of the period."},"endDay":{"type":"string","description":"Day timestamp following ISO 8601 for the end of the period."},"startTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the beginning of the period."},"endTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the end of the period."},"valueTypes":{"type":"string","description":"Comma-separated Thryve DataType IDs to filter by."},"dataSources":{"type":"string","description":"Comma-separated Thryve data source IDs to filter by."},"detailed":{"type":"boolean","description":"If true, includes additional recording information."},"displayPartnerUserID":{"type":"boolean","description":"If true, includes partnerUserID in the response."},"displayTypeName":{"type":"boolean","description":"If true, includes data type names (STRING) in the response."}}},"DailyDynamicValuesResponseItem":{"type":"object","properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"partnerUserID":{"type":"string","description":"The optional alias set by the developer when creating a user. Newer interfaces call this parameter endUserAlias."},"dataSources":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the data source (e.g., 1 for Fitbit)."},"data":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"ISO 8601 timestamp for the day"},"timestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for midnight in UTC for the day."},"createdAt":{"type":"string","description":"ISO 8601 timestamp when data point was created/updated."},"createdAtUnix":{"type":"integer","description":"Unix timestamp when data point was created/updated."},"details":{"type":"object","description":"Optional JSON object containing additional information (e.g., timezoneOffset)."},"dailyDynamicValueType":{"type":"string","description":"Thryve DataTypeID (e.g., 1000 for Steps)."},"dailyDynamicValueTypeName":{"type":"string","description":"Name of the daily dynamic value type (e.g., 'Steps')."},"value":{"type":"string","description":"Value for that day."},"valueType":{"type":"string","description":"Type of value provided (LONG, DOUBLE, STRING, DATE, BOOLEAN)."}}}}}}}}},"ErrorResponse":{"type":"string"}}}}
```

{% hint style="warning" %}
When retrieving the desired data period, a startDay and endDay, startTimestampUnix and endTimestampUnix or a createdAfterUnix date need to be added as parameters to the request. \
If both startDay and startTimestampUnix are provided, the system will use the ISO format and ignore the Unix timestamps entirely.\
The query range is set to a maximum of 364 days.
{% endhint %}


# v5 API reference


# Create or get user

## Get accessToken of new or existing user

> Retrieve an accessToken for a Thryve user. Automatically creates a user if partnerUserID is empty or no existing user with specified partnerUserID exists.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/accessToken":{"post":{"summary":"Get accessToken of new or existing user","tags":["End User"],"description":"Retrieve an accessToken for a Thryve user. Automatically creates a user if partnerUserID is empty or no existing user with specified partnerUserID exists.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/AccessTokenRequest"}}}},"responses":{"200":{"description":"Request successful. Returns the accessToken of a user.","content":{"text/plain":{"schema":{"$ref":"#/components/schemas/AccessTokenResponse"}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"AccessTokenRequest":{"type":"object","properties":{"partnerUserID":{"type":"string","description":"Set this optional parameter to add your an alias to a Thryve user. If no alias is set, it is not possible to retrieve an accessToken/authenticationToken for an existing user. Newer interfaces call this parameter endUserAlias."}}},"AccessTokenResponse":{"type":"string"},"ErrorResponse":{"type":"string"}}}}
```


# Get connection widget URL (deprecated)

## Get (deprecated) data source connection widget

> Returns link to a web-app allowing users to connect to web data sources.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/dataSourceURL":{"post":{"summary":"Get (deprecated) data source connection widget","tags":["Data Source Connection Widget (deprecated)"],"description":"Returns link to a web-app allowing users to connect to web data sources.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/ConnectionWidgetRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an link to data source connection widget.","content":{"text/plain":{"schema":{"$ref":"#/components/schemas/ConnectionWidgetResponse"}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"ConnectionWidgetRequest":{"type":"object","required":["authenticationToken"],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."}}},"ConnectionWidgetResponse":{},"ErrorResponse":{"type":"string"}}}}
```


# Get end user information

## Retrieve UserInformation for one or more users

> Retrieve basic, time-independent information about connected users, including biological data, connected sources, and devices.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/userInformation":{"post":{"summary":"Retrieve UserInformation for one or more users","tags":["End User"],"description":"Retrieve basic, time-independent information about connected users, including biological data, connected sources, and devices.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/UserInformationRetrievalRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an array of UserInformation per user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserInformationRetrievalResponseItem"}}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"UserInformationRetrievalRequest":{"type":"object","required":["authenticationToken"],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."}}},"UserInformationRetrievalResponseItem":{"type":"object","properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"partnerUserID":{"type":"string","description":"The optional alias set by the developer when creating a user. Newer interfaces call this parameter endUserAlias."},"height":{"type":"integer","description":"Height in cm, null if no value stored."},"weight":{"type":"number","format":"float","description":"Weight in kg, null if no value stored."},"birthdate":{"type":"string","format":"date","description":"Birthdate in YYYY-MM-DD format, null if not set."},"gender":{"type":"string","description":"Gender (male, female, genderless), null if not set."},"connectedSources":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the connected data source (e.g., 1 for Fitbit)."},"connectedAt":{"type":"string","format":"date-time","description":"ISO timestamp when the source was connected."}}}},"devices":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the data source for that device."},"deviceName":{"type":"string","description":"Name of the device model (e.g., Versa 3)."},"connectedAt":{"type":"string","format":"date-time","description":"ISO timestamp when the device was connected."},"configuration":{"type":"object","description":"Device-specific configuration object."}}}}}},"ErrorResponse":{"type":"string"}}}}
```


# Update end user information

## Upload or update UserInformation for a user

> Update a user’s basic information (e.g., height, weight, birthdate, gender).<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/userInformation":{"put":{"summary":"Upload or update UserInformation for a user","tags":["End User"],"description":"Update a user’s basic information (e.g., height, weight, birthdate, gender).\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."},{"name":"authenticationToken","in":"header","required":true,"schema":{"type":"string"},"description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInformationUpload"}}}},"responses":{"204":{"description":"Upload successful."},"400":{"description":"Error response (invalid payload, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"UserInformationUpload":{"type":"object","properties":{"height":{"type":"integer","description":"Height in centimeters."},"weight":{"type":"number","format":"float","description":"Weight in kilograms."},"birthdate":{"type":"string","format":"date","description":"Birthdate in YYYY-MM-DD format."},"gender":{"type":"string","description":"Gender as a string (male, female, genderless)."}},"description":"Payload for updating basic user information."},"ErrorResponse":{"type":"string"}}}}
```


# Delete end user

To delete users, use the `UserInformation` interface, which enables the removal of entire end-user accounts along with their associated access tokens and data (such as daily and epoch data). By invoking the `UserInformation` interface with the `DELETE` method, users are placed in a deletion queue. This queue is then processed asynchronously by the Thryve backend.

{% hint style="warning" %}
Users are deleted asynchronously starting at midnight (UTC) following the specified deletion date. Data remains accessible via API until deletion is executed.
{% endhint %}

## Delete one or more users

> Schedule deletion of user accounts along with their associated DynamicEpochValues, DailyDynamicValues, and UserInformation.\
> Uses asynchronous deletion; returns 204 if successfully queued.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/userInformation":{"delete":{"summary":"Delete one or more users","tags":["End User"],"description":"Schedule deletion of user accounts along with their associated DynamicEpochValues, DailyDynamicValues, and UserInformation.\nUses asynchronous deletion; returns 204 if successfully queued.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/UserInformationDeletionRequest"}}}},"responses":{"204":{"description":"Successfully added to deletion queue."},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"UserInformationDeletionRequest":{"type":"object","required":["authenticationToken"],"properties":{"authenticationToken":{"type":"string","description":"Comma-separated unique identifier of users in Thryve's system. Specify list of users to be deleted. Newer interfaces call this parameter endUserId."},"deletionDate":{"type":"string","format":"date-time","description":"Desired deletion date in ISO8601 format. If omitted, deletionDate defaults to seven days in the future."}}},"ErrorResponse":{"type":"string"}}}}
```


# Get daily data

## Retrieve DailyDynamicValues for a user

> Retrieve harmonized daily aggregated data (e.g., daily steps) for one user within a specified time range.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/dailyDynamicValues":{"post":{"summary":"Retrieve DailyDynamicValues for a user","tags":["Health Data"],"description":"Retrieve harmonized daily aggregated data (e.g., daily steps) for one user within a specified time range.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/DailyDynamicValuesRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an array of DailyDynamicValues per user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DailyDynamicValuesResponseItem"}}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DailyDynamicValuesRequest":{"type":"object","required":["authenticationToken"],"oneOf":[{"required":["startDay","endDay"]},{"required":["startTimestampUnix","endTimestampUnix"]}],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"startDay":{"type":"string","description":"Day timestamp following ISO 8601 for the start of the period."},"endDay":{"type":"string","description":"Day timestamp following ISO 8601 for the end of the period."},"startTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the beginning of the period."},"endTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the end of the period."},"valueTypes":{"type":"string","description":"Comma-separated Thryve DataType IDs to filter by."},"dataSources":{"type":"string","description":"Comma-separated Thryve data source IDs to filter by."},"detailed":{"type":"boolean","description":"If true, includes additional recording information."},"displayPartnerUserID":{"type":"boolean","description":"If true, includes partnerUserID in the response."},"displayTypeName":{"type":"boolean","description":"If true, includes data type names (STRING) in the response."}}},"DailyDynamicValuesResponseItem":{"type":"object","properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"partnerUserID":{"type":"string","description":"The optional alias set by the developer when creating a user. Newer interfaces call this parameter endUserAlias."},"dataSources":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the data source (e.g., 1 for Fitbit)."},"data":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","description":"ISO 8601 timestamp for the day"},"timestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for midnight in UTC for the day."},"createdAt":{"type":"string","description":"ISO 8601 timestamp when data point was created/updated."},"createdAtUnix":{"type":"integer","description":"Unix timestamp when data point was created/updated."},"details":{"type":"object","description":"Optional JSON object containing additional information (e.g., timezoneOffset)."},"dailyDynamicValueType":{"type":"string","description":"Thryve DataTypeID (e.g., 1000 for Steps)."},"dailyDynamicValueTypeName":{"type":"string","description":"Name of the daily dynamic value type (e.g., 'Steps')."},"value":{"type":"string","description":"Value for that day."},"valueType":{"type":"string","description":"Type of value provided (LONG, DOUBLE, STRING, DATE, BOOLEAN)."}}}}}}}}},"ErrorResponse":{"type":"string"}}}}
```


# Get epoch data

## Retrieve DynamicEpochValues for a user

> Retrieve harmonized intraday measurements (e.g., heart rate) for one user within a specified time range.<br>

```json
{"openapi":"3.1.0","info":{"title":"Thryve API","version":"5.0.0"},"servers":[{"url":"https://api.thryve.de"}],"paths":{"/v5/dynamicEpochValues":{"post":{"summary":"Retrieve DynamicEpochValues for a user","tags":["Health Data"],"description":"Retrieve harmonized intraday measurements (e.g., heart rate) for one user within a specified time range.\n","parameters":[{"name":"Authorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your username:password. Required for all endpoints"},{"name":"AppAuthorization","in":"header","required":true,"schema":{"type":"string"},"description":"Basic Auth for your authID:authSecret. Required for all endpoints."}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/DynamicEpochValuesRequest"}}}},"responses":{"200":{"description":"Request successful. Returns an array of DynamicEpochValues per user.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DynamicEpochValuesResponseItem"}}}}},"400":{"description":"Error response (invalid parameters, unauthorized, etc.).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}},"components":{"schemas":{"DynamicEpochValuesRequest":{"type":"object","required":["authenticationToken"],"oneOf":[{"required":["startTimestamp","endTimestamp"]},{"required":["startTimestampUnix","endTimestampUnix"]}],"properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"startTimestamp":{"type":"string","description":"ISO 8601 timestamp for the beginning of the period"},"endTimestamp":{"type":"string","description":"ISO 8601 timestamp for the end of the period"},"startTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the beginning of the period"},"endTimestampUnix":{"type":"integer","description":"Unix timestamp in milliseconds for the end of the period"},"valueTypes":{"type":"string","description":"Comma-separated Thryve DataType IDs to filter by."},"dataSources":{"type":"string","description":"Comma-separated Thryve data source IDs to filter by."},"detailed":{"type":"boolean","description":"If true, includes additional recording information."},"displayTypeName":{"type":"boolean","description":"If true, includes data type names (STRING) in the response."},"displayPartnerUserID":{"type":"boolean","description":"If true, includes the partnerUserID in the response."}}},"DynamicEpochValuesResponseItem":{"type":"object","properties":{"authenticationToken":{"type":"string","description":"The unique identifier of a user in Thryve's system. Newer interfaces call this parameter endUserId."},"partnerUserID":{"type":"string","description":"The optional alias set by the developer when creating a user. Newer interfaces call this parameter endUserAlias."},"dataSources":{"type":"array","items":{"type":"object","properties":{"dataSource":{"type":"integer","description":"ID of the data source (e.g., 8 for Garmin)."},"data":{"type":"array","items":{"type":"object","properties":{"startTimestamp":{"type":"string","description":"Start timestamp as ISO 8601 timespamp in UTC."},"endTimestamp":{"type":"string","description":"End timestamp as ISO 8601 timespamp in UTC (null if instant measurement)."},"createdAt":{"type":"string","description":"ISO 8601 timespamp in UTC when data point was created/updated in the data warehouse."},"startTimestampUnix":{"type":"integer","description":"Start timestamp in Unix milliseconds."},"endTimestampUnix":{"type":"integer","description":"End timestamp in Unix milliseconds (null if instant measurement)."},"createdAtUnix":{"type":"integer","description":"Unix timestamp when data point was created/updated in the data warehouse."},"dynamicValueType":{"type":"integer","description":"Thryve DataTypeID (e.g., 3000 for HeartRate)."},"dynamicValueTypeName":{"type":"string","description":"Name of the dynamic value type (e.g., 'HeartRate')."},"details":{"type":"object","description":"Optional JSON object with additional recording information."},"value":{"type":"string","description":"Value of the measurement."},"valueType":{"type":"string","description":"Type of value provided (LONG, DOUBLE, STRING, DATE, BOOLEAN)."}}}}}}}}},"ErrorResponse":{"type":"string"}}}}
```


# Technology overview

Thryve enables you to access health data. But how does the technology look like that makes this happen?

Thryve's service consists of 5 main building blocks:

1. **SDKs** for native (Android & iOS) and cross-platform (Flutter & React Native) enable you to integrate Thryve with any mobile application. Functionalities to enable your users to connect their wearables allow you to get first data in a matter of minutes from web data sources and native data sources, with the SDK taking care of everything.
2. The **data warehouse** stores all your users’ data from all data sources in the highest granularity possible in a harmonized data format. Mechanisms for data privacy make sure only the data that you really need is stored, helping you to achieve maximum compliance for your (medical) applications. All user data is linked to a fully pseudonymized Thryve user token, giving Thryve no information on who your user is.
3. When new data is flowing in, the **analytics platform** calculates relevant scores and biomarkers based on state-of-the-art medical research in real-time. We strive to have as much data available as possible for a user and often enrich data by deriving information that is not directly provided by the data sources and devices.
4. **Webhook notifications** keep your backend informed when users connect or disconnect their data sources as well as inform you about new or updated epoch and daily data. This allows you to draw data effiently from our data warehouse.
5. The **Wearable API** allows you to access all data stored in our data warehouse for your users. By specifying the timeframes, data sources, and data types you are interested in, you can access data without any clutter, allowing you to directly understand your users' fitness and health and build great, digital experiences.


