# Android (Kotlin)

## Connections

The Android SDK supports the following connection types:

| Value                        | Description                                                       |
| ---------------------------- | ----------------------------------------------------------------- |
| `Connections.SAMSUNG`        | Samsung Health (direct SDK access)                                |
| `Connections.HEALTH_CONNECT` | Health Connect (reads all data sources)                           |
| `Connections.GOOGLE_FIT`     | Google Fit (via Health Connect, filtered to Google Fit data only) |

{% hint style="info" %}
`HEALTH_CONNECT` reads data from **all** apps that write to Health Connect. `SAMSUNG` and `GOOGLE_FIT` filter data to only their respective app package, so you only get data originating from that source.
{% endhint %}

## CustomPermissions

Use these to request a subset of Health Connect permissions instead of all available ones. When not specified, all permissions from your developer scopes are requested.

`WORKOUT_TYPES`, `ACTIVITY_SUMMARY`, `LOCATION`, `CALORIES`, `STEPS`, `HEART_RATE`, `HEART_RATE_VARIABILITY`, `VO2MAX`, `HEIGHT`, `ACTIVE_DURATIONS`, `WEIGHT`, `FLIGHTS_CLIMBED`, `BMI`, `BODY_FAT`, `EXERCISE_DISTANCE`, `GENDER`, `DATE_OF_BIRTH`, `BASAL_ENERGY_BURNED`, `SWIMMING_SUMMARY`, `RESTING_HEART_RATE`, `BLOOD_PRESSURE`, `BLOOD_GLUCOSE`, `BODY_TEMPERATURE`, `LEAN_BODY_MASS`, `OXYGEN_SATURATION`, `SLEEP_ANALYSIS`, `RESPIRATORY_RATE`, `NUTRITION_SODIUM`, `NUTRITION_PROTEIN`, `NUTRITION_CARBOHYDRATES`, `NUTRITION_FIBRE`, `NUTRITION_FAT_TOTAL`, `NUTRITION_SUGAR`, `NUTRITION_VITAMIN_C`, `NUTRITION_VITAMIN_A`, `NUTRITION_CALORIES`, `NUTRITION_WATER`, `NUTRITION_CHOLESTEROL`, `MENSTRUATION`, `INTERBEAT`, `SPEED`, `POWER`

## **Utility functions**

### isHealthConnectAvailable

Checks if Health Connect is available on the device. This is a local check with no network call.

```kotlin
fun isHealthConnectAvailable(context: Context): Boolean
```

* `context: Context` ➡ Activity context.

Returns `true` if the Health Connect SDK is available, `false` if not installed or needs updating. Call this before `initConnection` with Health Connect-based connections to verify availability.

### openHealthConnect

Opens the Health Connect settings screen where users can manage app permissions.

```kotlin
fun openHealthConnect(context: Context): Unit
```

* `context: Context` ➡ Activity context. May throw `ActivityNotFoundException` if Health Connect is not installed.

## **Initialization**

### instance

Creates and authenticates a `TerraManager` instance. This **makes a network call** to Terra's servers to validate your developer ID and retrieve your account configuration (webhook intervals, scopes, existing users).

If existing users are found for this device, the SDK automatically reconnects them and (if `schedulerOn` was enabled) enqueues background data fetch jobs via WorkManager.

```kotlin
fun instance(devId: String, referenceId: String?,
             context: Context,
             completion: (TerraManager, TerraError?) -> Unit)
```

* `devId: String` ➡ Your developer ID from the [Terra Dashboard](https://dashboard.tryterra.co).
* `referenceId: String?` ➡ An identifier for your app's user. This value appears as `reference_id` in webhook payloads and API responses, allowing you to map Terra users back to your own user system.
* `context: Context` ➡ The activity context. Should be an `AppCompatActivity` for permission dialog support.
* `completion: (TerraManager, TerraError?) -> Unit` ➡ Called when initialization completes. **You must wait for this callback before calling any other SDK function.** Check the `TerraError?` parameter — a `TerraManager` is always returned, but it may not be functional if an error occurred.

{% hint style="warning" %}
**Must be called before the Activity reaches `onResume()`** — the SDK registers `ActivityResultContracts` for Health Connect permissions during initialization, which Android requires to happen before the Activity is resumed.
{% endhint %}

**Possible errors:**

| Error             | Cause                                         |
| ----------------- | --------------------------------------------- |
| `InvalidDevId`    | The `devId` is not recognized by Terra        |
| `UnexpectedError` | Network failure or unexpected server response |

## **TerraManager Instance methods**

## **Connection setup/management**

### **initConnection**

Authenticates a new user connection with Terra's servers and triggers the platform permission dialog. This **makes a network call** and shows the **Health Connect permission dialog** (for Samsung/Google Fit/Health Connect connections).

This function should only be called **once** per user/connection type. On subsequent app launches, `Terra.instance` will automatically reconnect existing users.

```kotlin
fun initConnection(connection: Connections,
                   token: String,
                   context: Context,
                   customPermissions: Set<CustomPermissions> = setOf(),
                   schedulerOn: Boolean = true,
                   completion: (Boolean, TerraError?) -> Unit = { _, _ -> })
```

* `connection: Connections` ➡ The connection type to initialize.
* `token: String` ➡ A **single-use** authentication token generated from your backend server via the [Generate Authentication Token](https://docs.tryterra.co/reference/generate-authentication-token) endpoint. Each token can only be used once.
* `context: Context` ➡ Activity context (required for the permission dialog).
* (Optional) `customPermissions: Set<CustomPermissions>` ➡ Request specific Health Connect permissions. When empty, defaults to all permissions from your developer scopes.
* `schedulerOn: Boolean` ➡ Enables automatic background data fetching. Defaults to `true`. When enabled, the SDK uses WorkManager to periodically fetch new data and send it to your webhook. Default intervals: activity every 20 minutes, daily/body/sleep/nutrition every 8 hours. Intervals are configurable server-side.
* `completion: (Boolean, TerraError?) -> Unit` ➡ Called when the connection is established (or fails).

**Possible errors:**

| Error                      | Cause                                        |
| -------------------------- | -------------------------------------------- |
| `InvalidDevId`             | Developer ID not recognized                  |
| `InvalidAuthToken`         | Token is invalid or already used             |
| `UserLimitExceeded`        | Your plan's user limit has been reached      |
| `NoInternet`               | Network request failed                       |
| `HealthConnectUnavailable` | Health Connect is not installed or available |
| `TerraClassNotInitiated`   | `Terra.instance` was not called first        |

### getUserId

Returns the Terra user ID for a connection, or `null` if no connection exists. This is a synchronous, local read with no network call.

The returned `user_id` is the same identifier used in webhook payloads, API requests, and the Terra dashboard.

```kotlin
fun getUserId(type: Connections): String?
```

* `type: Connections` ➡ The connection to retrieve the user ID for.

Returns `null` when:

* `initConnection` was never called for this connection type
* No existing user was found during `Terra.instance` initialization
* The connection failed

### checkAuth

Checks whether a connection is authenticated by **making a network call** to Terra's servers.

```kotlin
fun checkAuth(connection: Connections, callback: (Boolean) -> Unit)
```

* `connection: Connections` ➡ The connection type to check.
* `callback: (Boolean) -> Unit` ➡ `true` if the connection is authenticated on the server, `false` otherwise (including network failures).

### allGivenPermissions

Retrieves the set of Health Connect permissions currently granted to your app. Returns permission name strings like `"READ_HEART_RATE"`, `"READ_STEPS"`, `"WRITE_WEIGHT"`, etc.

```kotlin
fun allGivenPermissions(completion: (Set<String>) -> Unit)
```

* `completion: (Set<String>) -> Unit` ➡ Called with the set of granted permission names.

{% hint style="warning" %}
This only works for Health Connect-based connections (SAMSUNG, GOOGLE\_FIT, HEALTH\_CONNECT). If no Health Connect connection has been initialized, the **callback is never called**.
{% endhint %}

## Data Retrieval

All data retrieval functions **make network calls** — even with `toWebhook = false`, the SDK sends data to Terra's normalization servers and returns the normalized result.

Each function accepts dates as either `Date` or `Long` (Unix timestamp in seconds).

{% hint style="info" %}
**`toWebhook` behavior:**
{% endhint %}

| `toWebhook`      | What happens                                                                                     | Completion returns                                   |
| ---------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------- |
| `true` (default) | Data is fetched from Health Connect and sent to your webhook destination                         | A **reference ID** string only (not the data itself) |
| `false`          | Data is fetched, sent to Terra for normalization, and the normalized payload is returned locally | The **full normalized data payload**                 |

{% hint style="info" %}
Both paths require network connectivity.
{% endhint %}

### **getActivity**

Retrieves workout and exercise session data (heart rate, speed, power, cadence, distance, calories, GPS routes, steps, etc.).

```kotlin
fun getActivity(type: Connections,
             startDate: Date,
             endDate: Date,
             toWebhook: Boolean = true,
             completion: (Boolean, TerraActivityDataPayload?, TerraError?) -> Unit = {_, _, _ ->})
```

### **getDaily**

Retrieves daily summary data (total steps, calories, distance, resting heart rate, HRV, floors climbed, SpO2, etc.).

```kotlin
fun getDaily(type: Connections,
             startDate: Date,
             endDate: Date,
             toWebhook: Boolean = true,
             completion: (Boolean, TerraDailyDataPayload?, TerraError?) -> Unit = {_, _, _ ->})
```

### getSleep

Retrieves sleep session data (sleep stages, duration, heart rate, HRV, SpO2, respiratory rate). Sleep stages: unknown, awake, sleeping, out of bed, light, deep, REM.

```kotlin
fun getSleep(type: Connections,
             startDate: Date,
             endDate: Date,
             toWebhook: Boolean = true,
             completion: (Boolean, TerraSleepDataPayload?, TerraError?) -> Unit = {_, _, _ ->})
```

### getBody

Retrieves body measurement data (weight, height, BMI, body fat, heart rate, HRV, blood pressure, blood glucose, SpO2, lean body mass, bone mass, body temperature, basal metabolic rate).

```kotlin
fun getBody(type: Connections,
             startDate: Date,
             endDate: Date,
             toWebhook: Boolean = true,
             completion: (Boolean, TerraBodyDataPayload?, TerraError?) -> Unit = {_, _, _ ->})
```

### **getNutrition**

Retrieves nutrition and meal data (macronutrients, micronutrients, water intake, individual meals with meal type).

```kotlin
fun getNutrition(type: Connections,
                 startDate: Date,
                 endDate: Date,
                 toWebhook: Boolean = true,
                 completion: (Boolean, TerraNutritionDataPayload?, TerraError?) -> Unit = {_, _, _ ->})
```

**Completion parameters** (same structure for all data getters):

* `Boolean` ➡ `true` if the request succeeded.
* `Payload?` ➡ When `toWebhook = true`, contains only a `reference` string. When `toWebhook = false`, contains the full normalized data. `null` on failure.
* `TerraError?` ➡ Describes the error. Possible values: `Unauthorised` (no connection initialized), `UnSupportedResource` (unsupported data type for this connection).

{% hint style="info" %}
`getMenstruation` and `getAthlete` are **not available** on the Android TerraManager. Menstruation data can be accessed via the server-side REST API if the user's provider supports it.
{% endhint %}

### subscribe

Registers for real-time data updates. Currently **only `STEPS` is fully supported** on Android — other data types are saved to preferences but do not trigger updates at runtime.

```kotlin
fun subscribe(forDataTypes: Set<DataTypes>)
```

* `forDataTypes: Set<DataTypes>` ➡ Data types to subscribe to. Available values: `STEPS`, `HEART_RATE`, `CALORIES`, `DISTANCE`.

For STEPS, the SDK registers a periodic WorkManager job (every 15 minutes) that reads the hardware step counter and calls `Terra.updateHandler` with the step count delta.

**Before calling `subscribe`, you must set the update handler:**

```kotlin
Terra.updateHandler = { type: DataTypes, update: Update ->
    // type: which data type triggered the update
    // update.lastUpdated: Instant — when the previous update was recorded
    // update.samples: List<TerraData> — list of new data points
    //   each TerraData has: value (Double), timestamp (Instant)
}
```

{% hint style="warning" %}
Throws `NoUpdateHandlerDetected` if `Terra.updateHandler` is not set. Throws `NotAuthenticated` if no Health Connect connection is initialized.
{% endhint %}
