terra-data

Terra API health data retrieval and management. Use when fetching activity, sleep, body, daily, nutrition, menstruation, or athlete data from wearables.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "terra-data" with this command: npx skills add adaptationio/skrillz/adaptationio-skrillz-terra-data

Terra Data Retrieval

Fetch and manage health data from 150+ wearable devices via Terra API.

Data Types Overview

TypeDescriptionUpdate Frequency
ActivityWorkout sessions with metricsPer workout completion
SleepSleep stages, duration, HRVPer sleep session
BodyWeight, body composition, glucoseMultiple times/day
DailyAggregated daily summariesMultiple times/day
NutritionMeals, macros, caloriesPer meal logged
MenstruationCycle tracking, symptomsPer update
AthleteUser profile, demographicsOn change

Quick Start

from terra import Terra
from datetime import datetime, timedelta

client = Terra(
    dev_id="botaniqalmedtech-testing-SjyfjtG33s",
    api_key="_W7Pm-kAaIf1GA_Se21NnzCaFZjg3Izc"
)

# Get last 7 days of activity data
end_date = datetime.now()
start_date = end_date - timedelta(days=7)

response = client.activity.get(
    user_id="terra_user_abc123",
    start_date=start_date,
    end_date=end_date
)

for activity in response.data:
    print(f"{activity.metadata.type}: {activity.calories_data.total_burned_calories} cal")

Operations

get-activity

Retrieve completed workout sessions.

def get_activity(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime,
    to_webhook: bool = False
) -> list:
    """
    Get activity/workout data.

    Returns sessions with:
    - Duration, calories burned
    - Heart rate (avg, max, min, samples)
    - Distance, steps, floors
    - GPS position/polyline
    - Power, cadence (cycling)
    """
    response = client.activity.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date,
        to_webhook=to_webhook  # True for async processing
    )

    return response.data

Sample Activity Response:

{
  "data": [{
    "metadata": {
      "start_time": "2025-12-05T07:00:00Z",
      "end_time": "2025-12-05T08:00:00Z",
      "type": "running"
    },
    "calories_data": {
      "total_burned_calories": 450,
      "net_activity_calories": 350
    },
    "heart_rate_data": {
      "summary": { "avg_hr_bpm": 145, "max_hr_bpm": 175 }
    },
    "distance_data": { "distance_meters": 8500 },
    "movement_data": { "steps_count": 8500 }
  }]
}

get-sleep

Retrieve sleep sessions with stages.

def get_sleep(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> list:
    """
    Get sleep data.

    Returns sessions with:
    - Sleep stages (deep, light, REM, awake)
    - Duration in bed vs asleep
    - Sleep efficiency
    - HRV, respiratory rate
    - Temperature deviation
    """
    response = client.sleep.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date
    )

    return response.data

Sample Sleep Response:

{
  "data": [{
    "metadata": {
      "start_time": "2025-12-04T22:30:00Z",
      "end_time": "2025-12-05T06:30:00Z"
    },
    "sleep_durations_data": {
      "duration_in_bed_seconds": 28800,
      "duration_asleep_seconds": 26400,
      "sleep_efficiency": 0.92
    },
    "asleep": {
      "duration_deep_sleep_state_seconds": 5400,
      "duration_light_sleep_state_seconds": 14400,
      "duration_REM_sleep_state_seconds": 6600
    },
    "awake": {
      "num_wakeup_events": 2,
      "sleep_latency_seconds": 600
    },
    "heart_rate_data": {
      "summary": { "resting_hr_bpm": 52 }
    }
  }]
}

get-daily

Retrieve aggregated daily summaries.

def get_daily(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> list:
    """
    Get daily aggregated data.

    Returns summaries with:
    - Steps, calories, distance
    - Active minutes, floors
    - Resting heart rate, HRV
    - Recovery scores
    - Stress data

    Note: Sent multiple times/day - always OVERWRITE previous data.
    """
    response = client.daily.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date
    )

    return response.data

Sample Daily Response:

{
  "data": [{
    "metadata": {
      "start_time": "2025-12-05T00:00:00Z",
      "end_time": "2025-12-05T23:59:59Z"
    },
    "calories_data": {
      "total_burned_calories": 2400,
      "BMR_calories": 1600,
      "net_activity_calories": 800
    },
    "movement_data": {
      "steps_count": 10500,
      "floors_climbed": 12
    },
    "heart_rate_data": {
      "summary": { "resting_hr_bpm": 58 }
    },
    "scores": {
      "recovery": { "score": 82 },
      "activity": { "score": 75 },
      "sleep": { "score": 88 }
    }
  }]
}

get-body

Retrieve body metrics and biometrics.

def get_body(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> list:
    """
    Get body metrics data.

    Returns measurements including:
    - Weight, height, BMI
    - Body fat %, muscle mass
    - Blood glucose (CGM)
    - Blood pressure
    - Temperature
    - SpO2

    Note: Sent multiple times/day - always OVERWRITE previous data.
    """
    response = client.body.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date
    )

    return response.data

Sample Body Response:

{
  "data": [{
    "metadata": {
      "start_time": "2025-12-05T00:00:00Z",
      "end_time": "2025-12-05T23:59:59Z"
    },
    "body_metrics": {
      "weight_kg": 75.5,
      "height_cm": 178,
      "BMI": 23.8,
      "body_fat_percentage": 18.5
    },
    "blood_glucose_data": {
      "blood_glucose_samples": [
        { "glucose_mg_per_dL": 95, "timestamp": "2025-12-05T07:00:00Z" },
        { "glucose_mg_per_dL": 120, "timestamp": "2025-12-05T08:30:00Z" }
      ]
    },
    "blood_pressure_data": {
      "systolic_bp_mmHg": 120,
      "diastolic_bp_mmHg": 80
    }
  }]
}

get-nutrition

Retrieve nutrition and meal data.

def get_nutrition(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> list:
    """
    Get nutrition data.

    Returns meal logs with:
    - Calories, macros (protein, carbs, fat)
    - Micronutrients
    - Individual food items
    - Meal timestamps
    """
    response = client.nutrition.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date
    )

    return response.data

Sample Nutrition Response:

{
  "data": [{
    "metadata": {
      "start_time": "2025-12-05T00:00:00Z",
      "end_time": "2025-12-05T23:59:59Z"
    },
    "summary": {
      "macros": {
        "calories": 2200,
        "protein_g": 120,
        "carbohydrates_g": 250,
        "fat_g": 70,
        "fiber_g": 30
      }
    },
    "meals": [
      {
        "name": "Breakfast",
        "timestamp": "2025-12-05T08:00:00Z",
        "macros": { "calories": 450, "protein_g": 25 }
      }
    ]
  }]
}

get-menstruation

Retrieve menstrual cycle data.

def get_menstruation(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> list:
    """
    Get menstruation/cycle data.

    Returns tracking data including:
    - Cycle phase, day in cycle
    - Flow level, symptoms
    - Predictions
    """
    response = client.menstruation.get(
        user_id=user_id,
        start_date=start_date,
        end_date=end_date
    )

    return response.data

get-athlete

Retrieve user profile information.

def get_athlete(
    client: Terra,
    user_id: str
) -> dict:
    """
    Get user profile/athlete data.

    Returns profile including:
    - Name, email (if available)
    - Date of birth, age
    - Sex, gender
    - Location
    - Connected devices
    """
    response = client.athlete.get(user_id=user_id)
    return response.data

Bulk Data Retrieval

Get All Data Types

async def get_all_user_data(
    client: Terra,
    user_id: str,
    start_date: datetime,
    end_date: datetime
) -> dict:
    """Fetch all data types for a user."""

    return {
        "activity": client.activity.get(user_id, start_date, end_date).data,
        "sleep": client.sleep.get(user_id, start_date, end_date).data,
        "daily": client.daily.get(user_id, start_date, end_date).data,
        "body": client.body.get(user_id, start_date, end_date).data,
        "nutrition": client.nutrition.get(user_id, start_date, end_date).data,
    }

Historical Backfill

def backfill_user_data(
    client: Terra,
    user_id: str,
    days_back: int = 90
) -> dict:
    """
    Backfill historical data for newly connected user.

    Note: Requests >28 days are processed asynchronously
    and results sent via webhook.
    """
    end_date = datetime.now()
    start_date = end_date - timedelta(days=days_back)

    # For requests >28 days, use to_webhook=True
    if days_back > 28:
        # Async - results via webhook
        client.activity.get(user_id, start_date, end_date, to_webhook=True)
        client.sleep.get(user_id, start_date, end_date, to_webhook=True)
        client.daily.get(user_id, start_date, end_date, to_webhook=True)
        return {"status": "processing", "message": "Results via webhook"}
    else:
        # Sync - immediate response
        return get_all_user_data(client, user_id, start_date, end_date)

Provider Historical Data Limits

ProviderMax Historical Data
Garmin5 years
Fitbit10 years
Oura3 years
WHOOP2 years
Polar30 days
COROS3 months
Withings2 years

Data Normalization

Terra normalizes all provider data into consistent schemas:

Unique Identifiers

  • Activity/Sleep: start_time + end_time = unique session
  • Daily/Body/Nutrition: Date-based, OVERWRITE on updates

Update Strategy

def handle_data_update(data_type: str, payload: dict):
    """Handle incoming data with proper update strategy."""

    unique_key = f"{payload['user']['user_id']}:{payload['metadata']['start_time']}:{payload['metadata']['end_time']}"

    if data_type in ["daily", "body", "nutrition"]:
        # OVERWRITE - these update multiple times per day
        db.upsert(unique_key, payload)
    else:
        # INSERT OR IGNORE - sessions are unique
        db.insert_if_not_exists(unique_key, payload)

Writing Data (Limited Providers)

Some providers support writing data back:

# Post activity to Wahoo
client.activity.post(
    user_id="terra_user_abc123",
    data={
        "type": "cycling",
        "start_time": "2025-12-05T10:00:00Z",
        "end_time": "2025-12-05T11:00:00Z",
        "calories": 500,
        "distance_meters": 25000
    }
)

# Post nutrition to Fitbit
client.nutrition.post(
    user_id="terra_user_abc123",
    data={
        "meals": [{
            "name": "Lunch",
            "calories": 650,
            "protein_g": 35
        }]
    }
)

# Post planned workout to Apple Health
client.planned_workout.post(
    user_id="terra_user_abc123",
    data={
        "name": "5K Training",
        "type": "running",
        "phases": [
            {"type": "warmup", "duration_seconds": 300},
            {"type": "interval", "duration_seconds": 600}
        ]
    }
)

Database Schema

-- Activity sessions
CREATE TABLE terra_activities (
    id SERIAL PRIMARY KEY,
    terra_user_id VARCHAR(255),
    start_time TIMESTAMP,
    end_time TIMESTAMP,
    activity_type VARCHAR(50),
    calories INTEGER,
    distance_meters FLOAT,
    avg_heart_rate INTEGER,
    data JSONB,
    UNIQUE(terra_user_id, start_time, end_time)
);

-- Daily summaries (UPSERT)
CREATE TABLE terra_daily (
    id SERIAL PRIMARY KEY,
    terra_user_id VARCHAR(255),
    date DATE,
    steps INTEGER,
    calories INTEGER,
    distance_meters FLOAT,
    resting_heart_rate INTEGER,
    data JSONB,
    updated_at TIMESTAMP DEFAULT NOW(),
    UNIQUE(terra_user_id, date)
);

Related Skills

  • terra-auth: Authentication setup
  • terra-connections: Connect users
  • terra-webhooks: Real-time data delivery
  • terra-sdk: SDK integration

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

finnhub-api

No summary provided by upstream source.

Repository SourceNeeds Review
General

auto-updater

No summary provided by upstream source.

Repository SourceNeeds Review
General

todo-management

No summary provided by upstream source.

Repository SourceNeeds Review