Skip to content

Quick start guide

All API endpoints require authentication using an API key. The key must be included in the X-API-KEY header of your requests. See examples/authentication for more details.

All API endpoints support the Accept-Encoding: gzip header which will compress the JSON output to a zip format. Please see encoding/examples for more details.

API Key

You can obtain your API key by contacting Nowatch.

To get the user profile data from the API, you need two things:

  • the user_id;
  • your API key;

To get the biometrics data from user from the API, you need four things:

  • the user_id;
  • your API key;
  • the metric name (you can check how to do it for all metrics in API Reference tab);
  • the start and end dates from which you want to collect data (DD-MM-YYYY).

We provide here two examples.

Example 1: obtaining user profile data

cURL
curl -X 'GET' \
  'https://research-api.nowatch.com/v1/user/<user_id>' \
  -H 'X-API-KEY: YOUR_API_KEY'
Python
import requests

headers = {
    "X-API-KEY": "YOUR_API_KEY",
}

response = requests.get("https://research-api.nowatch.com/v1/user/<user_id>", headers=headers)

if response.status_code==200:
    print(response.json())
else:
    print("404 Code: User not found")

print(response.json())
Python Output
response.json()

Out[2]: 
{
    'id': 'xxxxxxxxxxxxxxxxxxxxxx',
    'age': 30,
    'sex': 'MALE',
    'height': 175,
    'weight': 75,
    'watch_hand': 'LEFT',
    'dominant_hand': 'RIGHT',
    'platform': 'ANDROID'
}

Example 2: obtaining heart rate data

For an easy manipulation, you can then convert the JSON response into a dataframe (Pandas or Polars are suggested). Also, don't forget to also fetch the Timezones and adjust them to the data (check out how in Timezone ).

Timeseries endpoints return a paginated envelope. To walk all pages, follow the next_cursor until it is null.

import requests

headers = {
    "X-API-KEY": "YOUR_API_KEY",
}

response_heart_rate = requests.get(
    "https://research-api.nowatch.com/v1/timeline/timeseries/<user_id>/HEART_RATE"
    "?start_date=<start_date>&end_date=<end_date>",
    headers=headers,
)

if response_heart_rate.status_code == 200:
    print(response_heart_rate.json())
else:
    print(f"Error {response_heart_rate.status_code}: {response_heart_rate.json()}")


response_timezones = requests.get(
    "https://research-api.nowatch.com/v1/timeline/events/timezones/<user_id>"
    "?start_date=<start_date>&end_date=<end_date>",
    headers=headers,
)

if response_timezones.status_code == 200:
    print(response_timezones.json())
else:
    print(f"Error {response_timezones.status_code}: {response_timezones.json()}")
Output and converting to a DataFrame
import polars as pl

if response_heart_rate.status_code == 200:
    page = response_heart_rate.json()
    print(pl.DataFrame(page["data"]).head(5))
else:
    print(f"Error {response_heart_rate.status_code}")


shape: (5, 3)
┌─────────────────────┬───────┬─────────┐
 timestamp            value  quality 
 ---                  ---    ---     
 str                  i64    i64     
╞═════════════════════╪═══════╪═════════╡
 2024-04-01T00:00:05  50     4       
 2024-04-01T00:00:15  52     4       
 2024-04-01T00:00:25  51     4       
 2024-04-01T00:00:35  52     4       
 2024-04-01T00:00:45  51     4       
└─────────────────────┴───────┴─────────┘


if response_timezones.status_code == 200:
    print(pl.DataFrame(response_timezones.json()).head(5))

shape: (5, 2)
┌────────────┬────────────────────┐
 date        timezone           
 ---         ---                
 str         struct[2]          
╞════════════╪════════════════════╡
 2025-04-01  {120,"2025-04-01"} 
 2025-04-02  {120,"2025-04-02"} 
 2025-04-03  {120,"2025-04-03"} 
 2025-04-04  {120,"2025-04-04"} 
 2025-04-05  {120,"2025-04-05"} 
└────────────┴────────────────────┘

Example 2b: walking all pages for a multi-day range

Heart rate cursor walk
import requests

BASE_URL = "https://research-api.nowatch.com"
headers = {"X-API-KEY": "YOUR_API_KEY"}

all_timestamps, all_values = [], []
url = f"{BASE_URL}/v1/timeline/timeseries/YOUR_USER_ID/HEART_RATE"
params = {"start_date": "2024-04-01", "end_date": "2024-04-07", "days": 1}

while True:
    resp = requests.get(url, headers=headers, params=params)
    resp.raise_for_status()
    page = resp.json()

    data = page["data"]
    all_timestamps.extend(data["timestamp"])
    all_values.extend(data["value"])

    next_cursor = page.get("next_cursor")
    if not next_cursor:
        break
    params = {"cursor": next_cursor}

print(f"Fetched {len(all_timestamps)} rows")

Example 3: obtaining Overview HRV data

cURL
curl -X 'GET' \
  'https://research-api.nowatch.com/v1/overview/YOUR_USER_ID/HRV?start_date=2023-01-01&end_date=2023-01-31' \
  -H "accept: application/json" \
  -H 'X-API-KEY: YOUR_API_KEY'
Python
import requests

headers = {
    "accept": "application/json",
    "X-API-KEY": "YOUR_API_KEY",
}

response = requests.get(
    "https://research-api.nowatch.com/v1/overview/YOUR_USER_ID/HRV"
    "?start_date=2023-01-01&end_date=2023-01-31",
    headers=headers,
)

if response.status_code == 200:
    print(response.json())
else:
    print(f"Error {response.status_code}: {response.json()}")
Python Output
response.json()

Out[3]:
[
  {
    "date": "2023-01-01",
    "hrv_daily": 40.5,
    "hrv_typical": 42.0,
    "hrv_upper_deviation": 5.0,
    "hrv_lower_deviation": 3.0,
    "hrv_descriptive": "Your HRV is stable."
  }
]

Example 4: obtaining Feelings DAY data

Feelings endpoints return a paginated envelope (data + next_cursor).

cURL
curl -X 'GET' \
  'https://research-api.nowatch.com/v1/feelings/YOUR_USER_ID/DAY?start_date=2023-01-01&end_date=2023-01-31' \
  -H "accept: application/json" \
  -H 'X-API-KEY: YOUR_API_KEY'
Python
import requests

headers = {
    "accept": "application/json",
    "X-API-KEY": "YOUR_API_KEY",
}

response = requests.get(
    "https://research-api.nowatch.com/v1/feelings/YOUR_USER_ID/DAY"
    "?start_date=2023-01-01&end_date=2023-01-31",
    headers=headers,
)

if response.status_code == 200:
    page = response.json()
    print(page["data"])
else:
    print(f"Error {response.status_code}: {response.json()}")
Python Output
page["data"]

Out[4]:
[
  {
    "date": "2023-01-01",
    "value": "GOOD"
  }
]