Skip to main content

Overview

The Synheart Wear CLI is an all-in-one local development tool that combines a command-line interface with an embedded FastAPI server for testing WHOOP, Garmin, and Fitbit integrations. Features:
  • Local FastAPI server with OAuth flows
  • Automatic ngrok tunnel exposure
  • Webhook recording and inspection
  • Token management (list, refresh, revoke)
  • Data pulling from cloud APIs
  • Hot-reload for development

Installation

pip install synheart-wear-cli

# Verify installation
wear version
wear --help

From Source

git clone https://github.com/synheart-ai/synheart-wear-cli.git
cd synheart-wear-cli
pip install -e ".[dev]"

Prerequisites

  • Python 3.11+
  • ngrok account (free): https://ngrok.com/
  • Wearable API credentials (WHOOP, Garmin, etc.)

Quick Start

1. Configure ngrok

# Get your auth token from https://dashboard.ngrok.com/
ngrok config add-authtoken YOUR_TOKEN

2. Create Environment File

Create .env.local:
# WHOOP Credentials
WHOOP_CLIENT_ID=your_whoop_client_id
WHOOP_CLIENT_SECRET=your_whoop_client_secret

# AWS (optional - for production)
AWS_REGION=us-east-1
DYNAMODB_TABLE=synheart-wear-tokens
KMS_KEY_ID=alias/synheart-wear

# Development Mode (auto-enabled)
DEV_MODE=true
WEBHOOK_RECORD=true

3. Start Development Server

# Start WHOOP connector with ngrok
python3 wear.py start dev --vendor whoop --port 8000

# Or with auto-open browser for OAuth:
python3 wear.py start dev --vendor whoop --open-browser
Output:
🚀 Starting Synheart Wear
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

📍 Configuration:
   Mode:           dev
   Vendor:         whoop
   Port:           8000
   Auto-reload:    ✅ enabled
   Webhook record: ✅ enabled

🌐 Endpoints:
   API Docs:      http://localhost:8000/docs
   OAuth Auth:    http://localhost:8000/v1/oauth/authorize
   Webhooks:      http://localhost:8000/v1/webhooks/whoop

🌐 ngrok tunnel: https://abc123-xyz.ngrok-free.app

📱 SDK Configuration:
   Use this URL in your app:
   baseUrl: 'https://abc123-xyz.ngrok-free.app'

Commands

wear start dev - Start Local Server

Start local development server with ngrok tunneling.
# Start WHOOP connector
wear start dev --vendor whoop --port 8000

# Start with auto-open browser
wear start dev --vendor whoop --open-browser

# Start unified service (all vendors)
wear start dev --port 8000

# Use specific environment file
wear start dev --vendor whoop --env .env.production

# Disable auto-reload
wear start dev --vendor whoop --no-reload

# Verbose logging
wear start dev --vendor whoop --verbose
Options:
  • --vendor, -v: Vendor to run (whoop, garmin, or omit for all)
  • --port, -p: Port (default: 8000)
  • --reload/--no-reload: Auto-reload on code changes (default: enabled)
  • --env: Environment file (.env.local, .env.production)
  • --open-browser: Auto-open OAuth URL
  • --webhook-record/--no-webhook-record: Enable webhook recording (default: enabled)
  • --verbose: Enable verbose logging

wear pull once - Fetch Data

Pull data from vendor cloud API (requires OAuth first).
# Pull WHOOP recovery data (last 7 days)
wear pull once --vendor whoop --since 7d

# Pull specific data types
wear pull once --vendor whoop --since 30d --data-types recovery,sleep,workouts

# Pull from specific user
wear pull once --vendor whoop --user-id abc123 --since 14d
Options:
  • --vendor: Vendor to pull from (required)
  • --since: Time range (e.g., 7d, 30d, 2h)
  • --data-types: Comma-separated types (recovery, sleep, workouts, cycles)
  • --user-id: Specific user ID (optional)

wear tokens - Manage OAuth Tokens

List, refresh, or revoke OAuth tokens.
# List all tokens
wear tokens list

# List tokens for specific vendor
wear tokens list --vendor whoop

# Refresh expired token
wear tokens refresh --vendor whoop --user-id abc123

# Revoke token (disconnect user)
wear tokens revoke --vendor whoop --user-id abc123

wear webhook - Inspect Webhooks

Inspect webhook events recorded during development.
# Inspect recent webhooks (last 50)
wear webhook inspect --limit 50

# Filter by vendor
wear webhook inspect --vendor whoop --limit 100

# Show webhook details
wear webhook inspect --verbose

Development Workflow

1. Start Local Server

wear start dev --vendor whoop --open-browser

2. Complete OAuth Flow

The browser opens automatically. Log in and authorize.

3. Configure SDK

Use the ngrok URL in your Flutter app:
final whoopProvider = WhoopProvider(
  baseUrl: 'https://abc123-xyz.ngrok-free.app',
  redirectUri: 'synheart://oauth/callback',
);
Or in Swift:
let whoopProvider = WhoopProvider(
    baseUrl: URL(string: "https://abc123-xyz.ngrok-free.app")!,
    redirectUri: "synheart://oauth/callback"
)
Or in Kotlin:
val whoopProvider = WhoopProvider(
    baseUrl = "https://abc123-xyz.ngrok-free.app",
    redirectUri = "synheart://oauth/callback"
)

4. Fetch Data

wear pull once --vendor whoop --since 7d

5. Test Webhooks

Webhooks are auto-recorded to __dev__/webhooks_recent.jsonl:
wear webhook inspect --limit 10

API Endpoints

WHOOP Endpoints

  • GET /v1/oauth/authorize - Get OAuth authorization URL
  • GET /v1/oauth/callback - OAuth callback (GET)
  • POST /v1/oauth/callback - OAuth callback (POST, mobile)
  • POST /v1/webhooks/whoop - Webhook handler
  • DELETE /v1/oauth/disconnect - Disconnect user
  • GET /v1/data/{user_id}/recovery - Fetch recovery data
  • GET /v1/data/{user_id}/sleep - Fetch sleep data
  • GET /v1/data/{user_id}/workouts - Fetch workout data
  • GET /v1/data/{user_id}/cycles - Fetch cycle data

Health Check

  • GET /health - Service health status
API Docs: http://localhost:8000/docs

Troubleshooting

ngrok Issues

Problem: “ngrok endpoint already online” Solution:
# Kill all ngrok processes
pkill -f ngrok

# Or restart with different port
wear start dev --port 8001

Port Already in Use

Problem: “Port 8000 is already in use” Solution:
# Find process using port
lsof -i :8000

# Kill process
kill $(lsof -ti :8000)

# Or use different port
wear start dev --port 8001

OAuth Flow Fails

Problem: “Authentication failed” Solution:
  1. Check environment variables in .env.local
  2. Verify redirect URI matches vendor configuration
  3. Check ngrok URL is correct
  4. Look at server logs for detailed errors

Architecture

synheart-wear-cli/
├── wear.py                  # Main CLI entry point
├── server/                  # Local development server
│   ├── whoop_api.py        # WHOOP OAuth + data endpoints
│   ├── garmin_api.py       # Garmin OAuth + data endpoints
│   ├── unified_api.py      # Unified service (all vendors)
│   └── whoop_connector.py  # WHOOP connector logic
├── libs/
│   ├── py-cloud-connector/ # OAuth token management
│   └── py-normalize/       # Data normalization
└── __dev__/                # Development data (auto-generated)
    ├── webhooks_recent.jsonl
    └── tokens.json

Security

  • Token Storage: DynamoDB with KMS encryption (production)
  • Dev Mode: Tokens stored locally in __dev__/tokens.json
  • Webhook Verification: HMAC signature validation
  • Environment Variables: Never commit .env.local files

Resources


Author: Israel Goytom