# Getting Started

## **Welcome to GeroSense Developer Documentation!**

It will help you to learn how to get up and running with GeroSense technologies. If you are unsure what GeroSense is, please visit our [main website](https://gerosense.ai).

{% hint style="info" %}
Before you jump into our API references, we highly recommend that you familiarize yourself with the main concepts by reading the articles in this section.&#x20;
{% endhint %}


# Main Concepts

## What GeroSense can do?

GeroSense API can take your users' history of steps and heart rate measurements from their wearable devices and phones and calculate their **biological age acceleration** and **resilience**.

## What is biological age acceleration?

It's a difference between a user's biological age and chronological age.

{% hint style="info" %}
**Example:** If a user's chronological age is 30 and biological age is 28, the biological age acceleration is -2 years.
{% endhint %}

To turn biological age acceleration to biological age, simply add it to chronological age.

GeroSense can calculate users' biological age acceleration daily and from historical data. See below an example of how a biological age chart might look in your app:

<div align="left"><figure><img src="/files/9vQgBv7xgvCY6HIv8fML" alt="" width="375"><figcaption></figcaption></figure></div>

## What data is required to calculate biological age acceleration?

Each point of biological age acceleration requires 7 days of unaggregated steps history. Optionally, you can provide us with 7 days of heart rate history to improve accuracy.

Additionally, we will require you to provide a user's sex assigned at birth and year of birth.

## Why do we require to specify the year of birth?

It's a legacy that we plan to make optional in the future. We use it to train new, improved models.

## What do we mean by unaggregated data?

To calculate biological age acceleration, our models require raw intra-day data points (we call them **samples**), including each individual heart-rate measurement and steps split into minute-long intervals. This is how data is stored in health data providers like Apple Health and Google Fit, and we expect you to send this data as is without any aggregation.

## What if a user has multiple devices?

At present, we compute biological age accelerations per device per model. Currently, we offer two models to calculate biological age acceleration. One model relies solely on step data, while the other utilizes both step and heart rate data.

{% hint style="info" %}
**Example:** Consider a situation where a user has an iPhone and an Apple Watch. The iPhone can only provide step data, while the Apple Watch can deliver data on both steps and heart rate. Therefore, for this user, we can calculate three biological age accelerations:

1. One based on step data from the iPhone.
2. One based on step data from the Apple Watch.
3. One based on both step and heart rate data from the Apple Watch.
   {% endhint %}

It's up to you to decide which model and device to use for calculations. We recommend selecting a device with the ability to measure heart rate when it's available.

## What is resilience?

Resilience, or recovery rate, shows how quickly users can recover from stressful events, such as a common cold, insufficient sleep, or surgery. Shorter recovery rate predicts longer life expectancy.

GeroSense API returns recovery rate measured in weeks. See below an example of how a resilience chart might look in your app:

<div align="left"><figure><img src="/files/wASDEwxNF3TUvJUbAEkS" alt="" width="375"><figcaption></figcaption></figure></div>

## What data is required to calculate resilience?

At least a 6-month history of biological age accelerations.&#x20;


# Architecture Overview

There are two scenarios for how to integrate with us.

## Default integration path

<figure><img src="/files/CbsE7XstFoiwwVYUmhud" alt="Integration Architecture"><figcaption></figcaption></figure>

GeroSense API assumes server-to-server communication, which usually involves three main elements:

* `Your client application` is something that your users interact with. Usually, a mobile app that has access to users' health data via Apple HealthKit, Health Connect, or any other health data provider.
* `Your API server` is a backend that acts as a proxy between your client application and the GeroSense API. Its responsibilities include authenticating users, sending their health data to GeroSense API, and receiving and caching results from it.
* `GeroSense API` is an API service that we provide to calculate users' health metrics like biological age and resilience based on their longitudinal health data, like a history of steps or heart rate measurements. To send requests to the GeroSense API, you must get authentication credentials from us.

Read [GeroSense API Reference](/gerosense-api-reference) if you prefer this option.

## Integrate via Docker image instead of updating your API

If you use JWT-based authentication, there is a simplified integration path. Instead of updating your API server,  you can host our [premade Docker image](https://hub.docker.com/repository/docker/gerosense/api-proxy/general) as a proxy. It will confirm your users' identity and handle token-based authentications with our API. In this case, you only need to update your mobile application to work directly with the proxy.

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

If you use third-party authentication services like **Firebase** or **Supabase**, this is a recommended way of integrating with us.

Read [GeroSense API Proxy Reference](/gerosense-api-proxy-reference) if you prefer this option.


# Getting Authentication Credentials

To get access to the GeroSense API, you will need to sign a contract with us. After signing, we will provide you with authentication credentials, including your username and password.

{% hint style="info" %}
**Action required:** Email <support@gerosense.ai> to schedule a call with our team to discuss a contract and get authentication credentials.
{% endhint %}


# GeroSense API Proxy Reference

The integration with GeroSense API includes the following steps:

1. [Setup Docker container](/gerosense-api-proxy-reference/setting-up-docker-container).
2. [Check API status](/gerosense-api-proxy-reference/checking-api-status).
3. [Register new users](/gerosense-api-proxy-reference/registering-users).
4. [Send users data](/gerosense-api-proxy-reference/sending-users-data).
5. [Trigger biological age acceleration computations](/gerosense-api-proxy-reference/triggering-biological-age-acceleration-computations).
6. [Receive results](/gerosense-api-proxy-reference/getting-users-biological-age-acceleration).
7. [Request users' resilience](/gerosense-api-proxy-reference/getting-users-resilience).


# Setting Up Docker Container

To set the Docker container for the API Proxy, you need to provide it with a few environment variables. We highly recommend keeping these variables outside of your version control system.

{% code title="EXAMPLE DOCKER-COMPOSE.YAML" %}

```yaml
services:
  gerosense:
    image: gerosense/api-proxy:1.3.0
    env_file: .env
```

{% endcode %}

Below, is the list of supported environment variables:

| Name                                                                | Description                                                                             |
| ------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| GEROSENSE\_API\_HOST<mark style="color:red;">\*</mark>              | The API host assigned to your account                                                   |
| GEROSENSE\_API\_ACCOUNT<mark style="color:red;">\*</mark>           | Your account name                                                                       |
| GEROSENSE\_API\_ACCOUNT\_PASSWORD<mark style="color:red;">\*</mark> | Your account password                                                                   |
| JWT\_SECRET<mark style="color:red;">\*</mark>                       | Configuration for the JWT secret used to authenticate your users. See below for details |
| HOST                                                                | The host on which `api-proxy` will listen. The default is `0.0.0.0`                     |
| PORT                                                                | The port on which `api-proxy` will listen. The default is `8000`                        |

## JWT\_SECRET Configuration

`JWT_SECRET` is an JSON object with the following fields:

| Field                                    | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type                                     | <p>The type of your JWT secret. Don't specify it if you use <code>jwk\_url</code>.<br><br>For Firebase, don't specify it.<br>For Supabase, it's <code>HS256</code>.<br><br>Supported algorithms: <code>HS256</code>, <code>HS384</code>, <code>HS512</code>, <code>ES256</code>, <code>ES384</code>, <code>RS256</code>, <code>RS384</code>, <code>RS512</code>, <code>PS256</code>, <code>PS384</code>, <code>PS512</code>, <code>EdDSA</code>.</p>                                                                                                                                   |
| key                                      | <p>Your JWT secret key. Don't specify it if you use <code>jwk\_url</code>.<br><br>For Firebase, don't specify it.<br>For Supabase, you can find it under <code>Settings > API > JWT Secret</code>.<br><br>For other providers:<br>In the case of a symmetric key (i.e., an HMAC-based key), just the key as is. The key must be long enough for the chosen algorithm (e.g., for HS256, it must be at least 32 characters long).</p><p></p><p>In the case of an asymmetric key (RSA, EdDSA, ECDSA, etc.), only the public key is in a PEM-encoded string or as an X509 certificate.</p> |
| jwk\_url                                 | <p>JSON Web Key URL.<br><br>For Firebase, use:<br><code><https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com></code> <br><br>For Supabse, don't specify it.</p>                                                                                                                                                                                                                                                                                                                                                                                  |
| audience                                 | <p>One or multiple supported audiences.<br><br>For Firebase, use your project ID.<br>For Supabase, by default, authenticated users have <code>authenticated</code> audience.<br><br>Use an array in case you need to support multiple audiences:<br><code>\["audience1", "audience2", ...]</code></p>                                                                                                                                                                                                                                                                                  |
| issuer<mark style="color:red;">\*</mark> | <p>Issuer of the token.<br><br>For Firebase, use: <code>[https://securetoken.google.com/\&#x3C;firebase-project-id>](https://securetoken.google.com/\&#x3C;firebase-project-id>)</code><br><br>For Supabase, use:<br><code>https\://\<project-id>.supabase.co/auth/v1</code></p>                                                                                                                                                                                                                                                                                                       |

{% code title="EXAMPLE .ENV FOR FIREBASE" %}

```bash
GEROSENSE_API_HOST=https://api-b2b.gerosense.ai
GEROSENSE_API_ACCOUNT=<your-account-name>
GEROSENSE_API_ACCOUNT_PASSWORD=<your-account-password>

JWT_SECRET='{"jwk_url":"https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com","audience":"<firebase-project-id>","issuer":"https://securetoken.google.com/<firebase-project-id>"}'
```

{% endcode %}

{% code title="EXAMPLE .ENV FOR SUPABASE" %}

```bash
GEROSENSE_API_HOST=https://api-b2b.gerosense.ai
GEROSENSE_API_ACCOUNT=<your-account-name>
GEROSENSE_API_ACCOUNT_PASSWORD=<your-account-password>

JWT_SECRET='{"type":"HS256","key":"<jwt-secret-from-supabase>","audience":"authenticated","issuer":"https://<project-id>.supabase.co/auth/v1"}'
```

{% endcode %}


# Checking API Status

While we strive to keep our API without downtime, we might need a short maintenance window in some extremely rare cases. Additionally, we might deprecate some of the old API versions with time while some of your users still might be on the old version of your app. To help you handle these scenarios, we have `/status` endpoint. This is how to use it:

* On your client application side, before sending any data to the API, request the `/status` endpoint.
* Check if the status is `Ok`. If it's `Maintenance`, don't send any data to the API until it becomes `Ok` again.&#x20;
* In your client application, specify which API version it supports. If it's lower than `minimal_api_version`, ask your users to upgrade the app.

<mark style="color:blue;">`GET`</mark> `/api/status`

{% tabs %}
{% tab title="200: OK " %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl 'https://<api-proxy-hostname>/api/status'
```

{% endcode %}

{% code title="200 – OK RESPONSE (EXAMPLE)" %}

```json
{
  "status": "Ok",
  "minimal_api_version":"v1.0"
}
```

{% endcode %}

{% code title="200 – MAINTENANCE RESPONSE (EXAMPLE)" %}

```json
{
  "status": "Maintenance",
  "minimal_api_version":"v1.0"
}
```

{% endcode %}


# Registering Users

Before sending a user's data to GeroSense API, you must register this user. Use `/user` endpoint for it:

<mark style="color:green;">`POST`</mark> `/api/v1.1/user`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                              | Type   | Description                                                                                |
| ------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| id<mark style="color:red;">\*</mark>              | String | User's unique identifier                                                                   |
| biological\_sex<mark style="color:red;">\*</mark> | String | <p>User's sex assigned at birth.</p><p>Either <code>Male</code> or <code>Female</code></p> |
| year\_of\_birth<mark style="color:red;">\*</mark> | Int    | User's year of birth                                                                       |

{% tabs %}
{% tab title="200: OK The user was registered successfully" %}

{% endtab %}

{% tab title="400: Bad Request The user was registered previously (in case of a duplicating request)" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://<api-proxy-hostname>/api/v1.1/user' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{
       "id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
       "biological_sex": "Female",
       "year_of_birth": 1990
     }'
```

{% endcode %}


# Sending Users Data

Use `/samples` endpoint to sync users' data with our API. You will need to split data points (samples) into batches of 1000 elements in size. It's okay to send such batches in parallel.\
\
Considering that you'll be sending us numerous batches, we recommend that you create a system to track samples that have already been submitted. As an example, the simplest method to accomplish this is by sending batches in chronological order and keeping a record of the most recent synchronized batch for each device.

<mark style="color:green;">`POST`</mark> `/api/v1.1/samples`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                         | Type      | Description                                                                                                                                                                              |
| -------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data\_type<mark style="color:red;">\*</mark> | String    | <p>Samples type.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p>                                                                                                   |
| data<mark style="color:red;">\*</mark>       | Sample\[] | <p>An array of samples like heart rate measurements or steps. <br><br>The minimal accepted size is <code>3</code> elements. The maximum accepted size is <code>1000</code> elements.</p> |

{% tabs %}
{% tab title="200: OK Every sample has been accepted" %}

{% endtab %}

{% tab title="207: Multi-Status Samples were partially accepted (usually due to bugs with platform health APIs)" %}

{% endtab %}

{% tab title="400: Bad Request No samples were accepted" %}

{% endtab %}
{% endtabs %}

Each `Sample` in the `data` field must follow the following structure:

<table><thead><tr><th width="193">Field</th><th width="98">Type</th><th>Description</th></tr></thead><tbody><tr><td>device_name<mark style="color:red;">*</mark></td><td>String</td><td>A unique device name like <code>iPhone</code> or <code>Apple Watch</code> </td></tr><tr><td>device_version</td><td>String</td><td>The version of the device or firmware</td></tr><tr><td>start_date<mark style="color:red;">*</mark></td><td>String</td><td>Sample's start timestamp in ISO 8601 format</td></tr><tr><td>end_date</td><td>String</td><td>Sample's end timestamp in ISO 8601 format.<br>It must not be earlier than <code>start_date</code></td></tr><tr><td>unit<mark style="color:red;">*</mark></td><td>String</td><td>Sample's unit.<br>Either <code>count</code>, <code>count/min</code>, or <code>count/s</code></td></tr><tr><td>value<mark style="color:red;">*</mark></td><td>Number</td><td>Sample's value.<br>It must be bigger than <code>0</code>.<br>It must be less than or equal to <code>30000</code> when <code>unit</code> is <code>count</code>.<br>It must be less than or equal to <code>300</code> when <code>unit</code> is <code>count/min</code>.</td></tr></tbody></table>

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://<api-proxy-hostname>/api/v1.1/samples' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{
       "data_type": "steps",
       "data": [
         {
           "device_name": "iPhone",
           "device_version": "17.0.3",
           "start_date": "2023-11-01T08:04:51.000+04:00",
           "end_date": "2023-11-01T08:04:58.000+04:00",
           "value": 14,
           "unit": "count"
         },
         {
           "device_name": "iPhone",
           "device_version": "17.0.3",
           "start_date": "2023-11-01T09:47:21.000+04:00",
           "end_date": "2023-11-01T09:47:34.000+04:00",
           "value": 24,
           "unit": "count"
         },
         ...
       ]
     }'     
```

{% endcode %}

See the full example in the json-file below:

{% file src="/files/Vy9igZwQnvgdlzZa1cE7" %}


# Triggering biological age acceleration computations

Since biological age acceleration computations are resource-intensive, we don't start them automatically on each new sample batch received. There are two options on how to trigger them:

1. Biological age accelerations will be calculated automatically 5 minutes after receiving the last batch with a user's data.
2. You can manually trigger these computations when the last batch is sent by calling `/bioage/calculate`.

<mark style="color:green;">`POST`</mark> `/api/v1.1/bioage/calculate`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name        | Type   | Description                                                                                |
| ----------- | ------ | ------------------------------------------------------------------------------------------ |
| model\_type | String | <p>Model to trigger.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |

{% tabs %}
{% tab title="200: OK The request has been accepted" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://<api-proxy-hostname>/api/v1.1/bioage/calculate' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{"model_type": "steps"}'
```

{% endcode %}


# Getting Users Biological Age Acceleration

There are two ways to get biological age acceleration after it was calculated asynchronously (see [Triggering biological age acceleration computations](/gerosense-api-reference/triggering-biological-age-acceleration-computations)):

1. [Receiving results via a webhook](/gerosense-api-proxy-reference/getting-users-biological-age-acceleration/receiving-results-via-a-webhook) (preferred way).
2. [Receiving results via API polling](/gerosense-api-proxy-reference/getting-users-biological-age-acceleration/receiving-results-via-api-polling).


# Receiving results via a webhook

You can create a dedicated API endpoint on your side, which we will trigger after calculating biological age accelerations. Let us know if you would like to use this way of receiving results, and email the endpoint address to <support@gerosense.ai>.

{% code title="WEBHOOK REQUEST BODY (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iPhone",
  "model_type": "steps",
  "bioage": [
    ...
    {"date": "2023-11-06", "value": null},
    {"date": "2023-11-07", "value": 2.68},
    {"date": "2023-11-08", "value": 2.87},
    {"date": "2023-11-09", "value": 2.42},
    {"date": "2023-11-10", "value": 3.21},
    ...
  ]
}
```

{% endcode %}

The `null` value inside `bioage` array is reserved for cases, when it was not enough data to calculate biological age acceleration for this day.


# Receiving results via API polling

Use `/bioage` endpoint to request users' biological age accelerations after it was calculated.

<mark style="color:blue;">`GET`</mark> `/api/v1.1/bioage`

#### Query Parameters

| Name                                           | Type   | Description                                                                            |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| model\_type<mark style="color:red;">\*</mark>  | String | <p>Model to use.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |
| device\_name<mark style="color:red;">\*</mark> | String | A unique device name like `iPhone` or `Apple Watch`                                    |
| from\_date<mark style="color:red;">\*</mark>   | String | <p>Start of the requested period.</p><p>In <code>YYYY-MM-DD</code> format</p>          |
| to\_date<mark style="color:red;">\*</mark>     | String | <p>End of the requested period.<br>In <code>YYYY-MM-DD</code> format</p>               |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

{% tabs %}
{% tab title="200: OK Biological age accelerations calculations were done for user" %}

{% endtab %}

{% tab title="404: Not Found Biological age accelerations calculations were not found for user" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
 curl 'https://<api-proxy-hostname>/api/v1.1/bioage?model_type=steps&device_name=iPhone&from_date=2023-11-01&to_date=2023-11-11' \
      -H 'accept: application/json' \
      -H 'Authorization: Bearer <token>' \
      -H 'Content-Type: application/json'
```

{% endcode %}

{% code title="200 – RESPONSE (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iphone",
  "model_type": "steps",
  "bioage": [
    ...
    {"date": "2023-11-06", "value": null},
    {"date": "2023-11-07", "value": 2.68},
    {"date": "2023-11-08", "value": 2.87},
    {"date": "2023-11-09", "value": 2.42},
    {"date": "2023-11-10", "value": 3.21},
    ...
  ]
}
```

{% endcode %}

The `null` value inside `bioage` array is reserved for cases, when it was not enough data to calculate biological age acceleration for this day.


# Getting Users Resilience

Use `/resilience` endpoint to request a user's resilience:

<mark style="color:blue;">`GET`</mark> `/api/v1.1/resilience`

#### Query Parameters

| Name                                           | Type   | Description                                                                            |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| model\_type<mark style="color:red;">\*</mark>  | String | <p>Model to use.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |
| device\_name<mark style="color:red;">\*</mark> | String | A unique device name like `iPhone` or `Apple Watch`                                    |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

{% tabs %}
{% tab title="200: OK The resilience was calculated" %}

{% endtab %}

{% tab title="404: Not Found Not enough data to calculate the resilience" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl 'https://<api-proxy-hostname>/api/v1.1/resilience?model_type=steps&device_name=iPhone' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json'
```

{% endcode %}

{% code title="200 – RESPONSE (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iphone",
  "model_type": "steps",
  "resilience": 2
}
```

{% endcode %}


# GeroSense API Reference

The integration with GeroSense API includes the following steps:

1. [Set up token-based authentication](/gerosense-api-reference/requests-authentication).
2. [Register new users](/gerosense-api-reference/registering-users).
3. [Send users data](/gerosense-api-reference/sending-users-data).
4. [Trigger biological age acceleration computations](/gerosense-api-reference/triggering-biological-age-acceleration-computations).
5. [Receive results](/gerosense-api-reference/getting-users-biological-age-acceleration).
6. [Request users' resilience](/gerosense-api-reference/getting-users-resilience).


# Requests Authentication

Each request you send to GeroSense API must be signed with an authentication token. To receive a new token, use `/login/access-token` endpoint.

<mark style="color:green;">`POST`</mark> `https://api-b2b.gerosense.ai/api/v1.0/login/access-token`

#### Headers

| Name                                           | Type   | Description                       |
| ---------------------------------------------- | ------ | --------------------------------- |
| Content-Type<mark style="color:red;">\*</mark> | String | application/x-www-form-urlencoded |

#### Request Body

| Name                                       | Type   | Description                            |
| ------------------------------------------ | ------ | -------------------------------------- |
| username<mark style="color:red;">\*</mark> |        | The username that we provided you with |
| password<mark style="color:red;">\*</mark> | String | The password that we provided you with |

{% tabs %}
{% tab title="200: OK The token was successfully created " %}

{% endtab %}

{% tab title="403: Forbidden The token is expired. Request a new token" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://api-b2b.gerosense.ai/api/v1.0/login/access-token' \
     -H 'Content-Type: application/x-www-form-urlencoded' \
     -d 'username=<username>&password=<password>'
```

{% endcode %}

{% code title="200 – RESPONSE (EXAMPLE)" %}

```json
{
  "access_token": "<token>",
  "token_type": "Bearer"
}
```

{% endcode %}

Once you have the token, add it in the `Authorization` header of all subsequent requests as shown below:

```bash
curl -X 'POST' 'https://api-b2b.gerosense.ai/api/v1.0/login/test-token' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>'
```


# Registering Users

Before sending a user's data to GeroSense API, you must register this user. Use `/user` endpoint for it:

<mark style="color:green;">`POST`</mark> `https://api-b2b.gerosense.ai/api/v2.2/user`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                              | Type   | Description                                                                                |
| ------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| id<mark style="color:red;">\*</mark>              | String | User's unique identifier                                                                   |
| biological\_sex<mark style="color:red;">\*</mark> | String | <p>User's sex assigned at birth.</p><p>Either <code>Male</code> or <code>Female</code></p> |
| year\_of\_birth<mark style="color:red;">\*</mark> | Int    | User's year of birth                                                                       |

{% tabs %}
{% tab title="200: OK The user was registered successfully" %}

{% endtab %}

{% tab title="400: Bad Request The user was registered previously (in case of a duplicating request)" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://api-b2b.gerosense.ai/api/v2.2/user' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{
       "id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
       "biological_sex": "Female",
       "year_of_birth": 1990
     }'
```

{% endcode %}


# Sending Users Data

Use `/samples` endpoint to sync users' data with our API. You will need to split data points (samples) into batches of 1000 elements in size. It's okay to send such batches in parallel.\
\
Considering that you'll be sending us numerous batches, we recommend that you create a system to track samples that have already been submitted. As an example, the simplest method to accomplish this is by sending batches in chronological order and keeping a record of the most recent synchronized batch for each device.

<mark style="color:green;">`POST`</mark> `https://api-b2b.gerosense.ai/api/v2.2/samples`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                         | Type      | Description                                                                                                                                                                              |
| -------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| user\_id<mark style="color:red;">\*</mark>   | String    | User's unique identifier                                                                                                                                                                 |
| data\_type<mark style="color:red;">\*</mark> | String    | <p>Samples type.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p>                                                                                                   |
| data<mark style="color:red;">\*</mark>       | Sample\[] | <p>An array of samples like heart rate measurements or steps. <br><br>The minimal accepted size is <code>3</code> elements. The maximum accepted size is <code>1000</code> elements.</p> |

{% tabs %}
{% tab title="200: OK Every sample has been accepted" %}

{% endtab %}

{% tab title="207: Multi-Status Samples were partially accepted (usually due to bugs with platform health APIs)" %}

{% endtab %}

{% tab title="400: Bad Request No samples were accepted" %}

{% endtab %}
{% endtabs %}

Each `Sample` in the `data` field must follow the following structure:

<table><thead><tr><th width="193">Field</th><th width="98">Type</th><th>Description</th></tr></thead><tbody><tr><td>device_name<mark style="color:red;">*</mark></td><td>String</td><td>A unique device name like <code>iPhone</code> or <code>Apple Watch</code> </td></tr><tr><td>device_version</td><td>String</td><td>The version of the device or firmware</td></tr><tr><td>start_date<mark style="color:red;">*</mark></td><td>String</td><td>Sample's start timestamp in ISO 8601 format</td></tr><tr><td>end_date</td><td>String</td><td>Sample's end timestamp in ISO 8601 format.<br>It must not be earlier than <code>start_date</code></td></tr><tr><td>unit<mark style="color:red;">*</mark></td><td>String</td><td>Sample's unit.<br>Either <code>count</code>, <code>count/min</code>, or <code>count/s</code></td></tr><tr><td>value<mark style="color:red;">*</mark></td><td>Number</td><td>Sample's value.<br>It must be bigger than <code>0</code>.<br>It must be less than or equal to <code>30000</code> when <code>unit</code> is <code>count</code>.<br>It must be less than or equal to <code>300</code> when <code>unit</code> is <code>count/min</code>.</td></tr></tbody></table>

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://api-b2b.gerosense.ai/api/v2.2/samples' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{
       "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
       "data_type": "steps",
       "data": [
         {
           "device_name": "iPhone",
           "device_version": "17.0.3",
           "start_date": "2023-11-01T08:04:51.000+04:00",
           "end_date": "2023-11-01T08:04:58.000+04:00",
           "value": 14,
           "unit": "count"
         },
         {
           "device_name": "iPhone",
           "device_version": "17.0.3",
           "start_date": "2023-11-01T09:47:21.000+04:00",
           "end_date": "2023-11-01T09:47:34.000+04:00",
           "value": 24,
           "unit": "count"
         },
         ...
       ]
     }'     
```

{% endcode %}

See the full example in the json-file below:

{% file src="/files/Vy9igZwQnvgdlzZa1cE7" %}


# Triggering biological age acceleration computations

Since biological age acceleration computations are resource-intensive, we don't start them automatically on each new sample batch received. There are two options on how to trigger them:

1. Biological age accelerations will be calculated automatically 5 minutes after receiving the last batch with a user's data.
2. You can manually trigger these computations when the last batch is sent by calling `/bioage/calculate`.

<mark style="color:green;">`POST`</mark> `https://api-b2b.gerosense.ai/api/v2.2/bioage/calculate`

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

#### Request Body

| Name                                       | Type   | Description                                                                                |
| ------------------------------------------ | ------ | ------------------------------------------------------------------------------------------ |
| user\_id<mark style="color:red;">\*</mark> | String | User's unique identifier                                                                   |
| model\_type                                | String | <p>Model to trigger.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |

{% tabs %}
{% tab title="200: OK The request has been accepted" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl -X 'POST' 'https://api-b2b.gerosense.ai/api/v2.2/bioage/calculate' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json' \
     -d '{
       "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
       "model_type": "steps"
     }'
```

{% endcode %}


# Getting Users Biological Age Acceleration

There are two ways to get biological age acceleration after it was calculated asynchronously (see [Triggering biological age acceleration computations](/gerosense-api-reference/triggering-biological-age-acceleration-computations)):

1. [Receiving results via a webhook](/gerosense-api-reference/getting-users-biological-age-acceleration/receiving-results-via-a-webhook) (preferred way).
2. [Receiving results via API polling](/gerosense-api-reference/getting-users-biological-age-acceleration/receiving-results-via-api-polling).


# Receiving results via a webhook

You can create a dedicated API endpoint on your side, which we will trigger after calculating biological age accelerations. Let us know if you would like to use this way of receiving results, and email the endpoint address to <support@gerosense.ai>.

{% code title="WEBHOOK REQUEST BODY (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iPhone",
  "model_type": "steps",
  "bioage": [
    {"date": "2023-11-06", "value": null},
    {"date": "2023-11-07", "value": 2.68},
    {"date": "2023-11-08", "value": 2.87},
    {"date": "2023-11-09", "value": 2.42},
    {"date": "2023-11-10", "value": 3.21},
    ...
  ]
}
```

{% endcode %}

The `null` value inside `bioage` array is reserved for cases, when it was not enough data to calculate biological age acceleration for this day.


# Receiving results via API polling

Use `/bioage` endpoint to request users' biological age accelerations after it was calculated.

<mark style="color:blue;">`GET`</mark> `https://api-b2b.gerosense.ai/api/v2.2/bioage`

#### Query Parameters

| Name                                           | Type   | Description                                                                            |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| user\_id<mark style="color:red;">\*</mark>     | String | User's unique identifier                                                               |
| model\_type<mark style="color:red;">\*</mark>  | String | <p>Model to use.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |
| device\_name<mark style="color:red;">\*</mark> | String | A unique device name like `iPhone` or `Apple Watch`                                    |
| from\_date<mark style="color:red;">\*</mark>   | String | <p>Start of the requested period.</p><p>In <code>YYYY-MM-DD</code> format</p>          |
| to\_date<mark style="color:red;">\*</mark>     | String | <p>End of the requested period.<br>In <code>YYYY-MM-DD</code> format</p>               |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

{% tabs %}
{% tab title="200: OK Biological age accelerations calculations were done for user" %}

{% endtab %}

{% tab title="404: Not Found Biological age accelerations calculations were not found for user" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
 curl 'https://api-b2b.gerosense.ai/api/v2.2/bioage?user_id=85b4453a-46de-484c-bbc2-12666ebc7ed9&model_type=steps&device_name=iPhone&from_date=2023-11-01&to_date=2023-11-11' \
      -H 'accept: application/json' \
      -H 'Authorization: Bearer <token>' \
      -H 'Content-Type: application/json'
```

{% endcode %}

{% code title="200 – RESPONSE (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iphone",
  "model_type": "steps",
  "bioage": [
    ...
    {"date": "2023-11-06", "value": null},
    {"date": "2023-11-07", "value": 2.68},
    {"date": "2023-11-08", "value": 2.87},
    {"date": "2023-11-09", "value": 2.42},
    {"date": "2023-11-10", "value": 3.21},
    ...
  ]
}
```

{% endcode %}

The `null` value inside `bioage` array is reserved for cases, when it was not enough data to calculate biological age acceleration for this day.


# Getting Users Resilience

Use `/resilience` endpoint to request a user's resilience:

<mark style="color:blue;">`GET`</mark> `https://api-b2b.gerosense.ai/api/v2.2/resilience`

#### Query Parameters

| Name                                           | Type   | Description                                                                            |
| ---------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| user\_id<mark style="color:red;">\*</mark>     | String | User's unique identifier                                                               |
| model\_type<mark style="color:red;">\*</mark>  | String | <p>Model to use.<br>Either <code>steps</code> or <code>bpm</code> (for heart rate)</p> |
| device\_name<mark style="color:red;">\*</mark> | String | A unique device name like `iPhone` or `Apple Watch`                                    |

#### Headers

| Name                                            | Type   | Description      |
| ----------------------------------------------- | ------ | ---------------- |
| Authorization<mark style="color:red;">\*</mark> | String | Bearer \<token>  |
| Content-Type<mark style="color:red;">\*</mark>  | String | application/json |

{% tabs %}
{% tab title="200: OK The resilience was calculated" %}

{% endtab %}

{% tab title="404: Not Found Not enough data to calculate the resilience" %}

{% endtab %}
{% endtabs %}

{% code title="REQUEST (EXAMPLE)" %}

```bash
curl 'https://api-b2b.gerosense.ai/api/v2.2/resilience?user_id=85b4453a-46de-484c-bbc2-12666ebc7ed9&model_type=steps&device_name=iPhone' \
     -H 'accept: application/json' \
     -H 'Authorization: Bearer <token>' \
     -H 'Content-Type: application/json'
```

{% endcode %}

{% code title="200 – RESPONSE (EXAMPLE)" %}

```json
{
  "user_id": "85b4453a-46de-484c-bbc2-12666ebc7ed9",
  "device_name": "iphone",
  "model_type": "steps",
  "resilience": 2
}
```

{% endcode %}


