Skip to content

Quickstart

This guide takes you from a fresh VitaSync installation to your first health data query. By the end you will have:

  • VitaSync running locally with Docker
  • A user created and connected to a wearable provider
  • Real health metrics in the database and queryable via the API
  • Docker Desktop installed
  • A wearable device account (Fitbit, Garmin, WHOOP, or Strava) with some historical data
  • An OAuth developer app for one of the providers (see below)

Step 1 — Create Provider OAuth Credentials

Section titled “Step 1 — Create Provider OAuth Credentials”

Before you can connect a wearable, you need OAuth credentials from the provider’s developer portal.

  1. Go to dev.fitbit.com/apps/new
  2. Fill in the form:
    • Application Type: Personal
    • OAuth 2.0 Application Type: Server
    • Callback URL: http://localhost:3001/v1/oauth/fitbit/callback
  3. After creation, copy the OAuth 2.0 Client ID and Client Secret

Clone the repository and create your environment file:

Terminal window
git clone https://github.com/your-org/vitasync.git
cd vitasync
cp .env.example .env

Edit .env with your credentials:

Terminal window
# Required: generate a 64-character hex string for token encryption
ENCRYPTION_KEY=your-64-hex-chars-here
# Required: your admin API key (prefix must be vs_live_)
ADMIN_API_KEY=vs_live_changeme_replace_in_production
# Required: workspace identifier
ADMIN_WORKSPACE_SLUG=my-workspace
# OAuth redirect base URL
OAUTH_CALLBACK_URL=http://localhost:3000/connections/callback
# Add the provider you created credentials for:
FITBIT_CLIENT_ID=your_fitbit_client_id
FITBIT_CLIENT_SECRET=your_fitbit_client_secret
# GARMIN_CONSUMER_KEY=your_garmin_consumer_key
# GARMIN_CONSUMER_SECRET=your_garmin_consumer_secret
# WHOOP_CLIENT_ID=your_whoop_client_id
# WHOOP_CLIENT_SECRET=your_whoop_client_secret
# STRAVA_CLIENT_ID=your_strava_client_id
# STRAVA_CLIENT_SECRET=your_strava_client_secret

Generate the encryption key with:

Terminal window
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Terminal window
docker compose up -d

This starts PostgreSQL, Redis, the API server, background worker, and web dashboard. Wait about 15 seconds for everything to be ready, then verify:

Terminal window
curl http://localhost:3001/health
# {"status":"ok"}
Terminal window
export API_KEY=vs_live_changeme_replace_in_production
curl -X POST http://localhost:3001/v1/users \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"externalId": "user-001", "displayName": "Test User"}'

Response:

{
"id": "01JA4MNPQR8STUVWXYZ00001",
"externalId": "user-001",
"displayName": "Test User",
"metadata": {},
"createdAt": "2025-06-01T10:00:00.000Z"
}

Save the id — you will need it in the next steps.

Terminal window
export USER_ID=01JA4MNPQR8STUVWXYZ00001

Open this URL in your browser (replace fitbit with your provider if needed):

http://localhost:3001/v1/oauth/fitbit/authorize?userId=01JA4MNPQR8STUVWXYZ00001

You will be redirected to the provider’s login page. After granting access, you will be redirected back and see something like:

http://localhost:3000/connections/callback?connectionId=01JA4MNPQR8STUVWXYZ00002&providerId=fitbit

Save the connection ID:

Terminal window
export CONNECTION_ID=01JA4MNPQR8STUVWXYZ00002
Terminal window
curl -X POST \
"http://localhost:3001/v1/users/$USER_ID/connections/$CONNECTION_ID/sync" \
-H "Authorization: Bearer $API_KEY"

Response:

{"jobId": "sync-job-01JA4...", "status": "queued"}

The sync runs asynchronously and pulls the last 30 days of data. It typically completes in a few seconds to a minute. Watch progress in the worker logs:

Terminal window
docker compose logs -f worker

Once the sync completes, query your data:

Terminal window
# Steps for the last 7 days
curl "http://localhost:3001/v1/users/$USER_ID/health?metricType=steps&limit=7" \
-H "Authorization: Bearer $API_KEY"

Response:

{
"data": [
{
"id": "01JA4...",
"metricType": "steps",
"value": 9823,
"unit": "count",
"recordedAt": "2025-06-06T00:00:00.000Z",
"providerId": "fitbit"
}
],
"total": 7,
"limit": 7,
"offset": 0
}

Try other queries:

Terminal window
# Summary: how many data points per metric type?
curl "http://localhost:3001/v1/users/$USER_ID/health/summary" \
-H "Authorization: Bearer $API_KEY"
# Timeseries: average heart rate by day for June
curl "http://localhost:3001/v1/users/$USER_ID/health/timeseries?metricType=heart_rate&from=2025-06-01&to=2025-06-30&bucket=day" \
-H "Authorization: Bearer $API_KEY"
# Daily summary: steps + calories + resting HR for last week
curl "http://localhost:3001/v1/users/$USER_ID/health/daily-summaries?from=2025-06-01&to=2025-06-07&metricTypes=steps,calories,resting_heart_rate" \
-H "Authorization: Bearer $API_KEY"
# Recent workouts
curl "http://localhost:3001/v1/users/$USER_ID/events?eventType=workout&limit=5" \
-H "Authorization: Bearer $API_KEY"
# Personal records
curl "http://localhost:3001/v1/users/$USER_ID/personal-records" \
-H "Authorization: Bearer $API_KEY"

After the first sync, data is available depending on which provider you connected:

MetricFitbitGarminWHOOPStrava
StepsYesYes
Heart rateYesYesYesYes
SleepYesYesYes
HRVYesYesYes
WorkoutsYesYesYes
Recovery scoreYes
SpO2YesYesYes
Body weightYes

See the Providers section for full coverage tables.