API Reference

The Health Data AI Analyzer Mac app exposes a read-only localhost API on http://127.0.0.1:8765. Use it to build OpenClaw integrations, Claude Code workflows, Mac Shortcuts, and custom scripts that read your Apple Health data without uploading anything to the cloud.

The API is read-only. Tools can query your health summaries but cannot write, delete, or modify your data.

OpenAPI specification. A machine-readable OpenAPI 3.1 spec for this API is available at /openapi.yaml and /openapi.json (identical content, YAML and JSON). Use it to auto-generate client bindings and adapters.

Overview

The Mac app reads your imported Apple Health dataset and serves compact summaries over 127.0.0.1. The API uses the app's selected integration dataset. Once you import data or choose Use for Integrations on a saved analysis, the dataset stays available across app relaunches.

Base URL http://127.0.0.1:8765
Protocol HTTP (localhost only)
Format JSON
Access Read-only

Authentication

These routes are currently public on loopback and do not require a token:

  • GET /status
  • GET /openclaw/status
  • GET /openclaw/daily-brief
  • GET /openclaw/recent-trends
  • GET /openclaw/weekly-summary

All other routes require the X-Health-Analyzer-Token header. The token file path is returned by GET /status as token_path.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" http://127.0.0.1:8765/summary

Upcoming change (next Mac app update): the three /openclaw/ data endpoints — /openclaw/daily-brief, /openclaw/recent-trends, and /openclaw/weekly-summary — will require the same X-Health-Analyzer-Token header as the rest of the API. Only GET /openclaw/status stays open. Start sending the token on those endpoints now. The token is already accepted today, so any client that sends it will keep working across the update with no changes. Read the token from the token_path returned by GET /status:

curl -H "X-Health-Analyzer-Token: $(cat ~/.health-analyzer/token)" \
  "http://127.0.0.1:8765/openclaw/daily-brief?date=2026-03-19"

Endpoints

GET /openclaw/status

Readiness endpoint for OpenClaw and local AI integrations. Returns app version, whether a dataset is loaded, last import and sync timestamps, and available metrics. No authentication required.

curl http://127.0.0.1:8765/openclaw/status

Example response:

{
  "ok": true,
  "success": true,
  "summary": "Health Data AI Analyzer is ready and has an analyzed health dataset loaded.",
  "data": {
    "app": "Health Data AI Analyzer",
    "app_version": "1.4.2",
    "server_version": "v1",
    "dataset_loaded": true,
    "last_imported_at": "2026-03-19T10:30:00Z",
    "last_synced_at": "2026-03-19T10:35:00Z",
    "available_metrics": [
      "steps", "sleep", "workouts",
      "heart_rate", "hrv"
    ]
  }
}

GET /openclaw/daily-brief?date=YYYY-MM-DD

Compact Apple Health daily summary for AI assistants and scripts. Returns steps, sleep, workouts, heart rate, HRV, signals, sync metadata, and a human-readable context summary. If date is omitted, the most recent available day is used. No authentication required today; see the upcoming change above — send the token now.

curl "http://127.0.0.1:8765/openclaw/daily-brief?date=2026-03-19"

Example response:

{
  "ok": true,
  "success": true,
  "summary": "Daily Apple Health brief from Health Data AI Analyzer.",
  "data": {
    "date": "2026-03-19",
    "steps": {
      "value": 2444,
      "baseline_7d": 10004.57,
      "delta_vs_baseline": -7560.57
    },
    "sleep": {
      "hours": null,
      "baseline_7d": 6.47
    },
    "workouts": {
      "count": 0,
      "total_minutes": 0
    },
    "signals": ["activity_below_baseline"],
    "context_summary": "Daily brief for 2026-03-19, steps 2444"
  }
}

GET /openclaw/recent-trends?days=N

Recent step and sleep trends for the last N days (default 7, minimum 1). Returns average, best, and latest values plus a per-day series for each. No authentication required today; see the upcoming change above — send the token now.

curl "http://127.0.0.1:8765/openclaw/recent-trends?days=7"

Example response:

{
  "ok": true,
  "success": true,
  "summary": "Recent Apple Health step and sleep trends from Health Data AI Analyzer.",
  "data": {
    "days": 7,
    "steps": {
      "average": 8576.0,
      "best": 12045.0,
      "latest": 2444.0,
      "series": [
        { "date": "2026-03-13", "value": 11204.0 },
        { "date": "2026-03-19", "value": 2444.0 }
      ]
    },
    "sleep": {
      "average": 6.72,
      "best": 8.0,
      "latest": null,
      "series": [
        { "date": "2026-03-13", "value": 7.2 },
        { "date": "2026-03-19", "value": null }
      ]
    }
  }
}

GET /openclaw/weekly-summary?days=N

Rolled-up summary over the last N days (default 7, minimum 1): step and sleep averages, total workout minutes and count, average heart rate, plus step and sleep day series. No authentication required today; see the upcoming change above — send the token now.

curl "http://127.0.0.1:8765/openclaw/weekly-summary?days=7"

Example response:

{
  "ok": true,
  "success": true,
  "summary": "Weekly Apple Health summary from Health Data AI Analyzer.",
  "data": {
    "days": 7,
    "steps_average": 8576.0,
    "sleep_average": 6.72,
    "workout_minutes_total": 202.0,
    "workout_count_total": 5,
    "heart_rate_average": 72.5,
    "steps_series": [
      { "date": "2026-03-13", "value": 11204.0 },
      { "date": "2026-03-19", "value": 2444.0 }
    ],
    "sleep_series": [
      { "date": "2026-03-13", "value": 7.2 },
      { "date": "2026-03-19", "value": null }
    ]
  }
}

GET /status

General local API status endpoint for host tools and debugging. Returns app and server version, dataset state, import/sync timestamps, and the token path for protected endpoints. No authentication required on loopback.

curl http://127.0.0.1:8765/status

Example response:

{
  "ok": true,
  "success": true,
  "data": {
    "app_version": "1.4.2",
    "server_version": "v1",
    "dataset_loaded": true,
    "last_imported_at": "2026-03-19T10:30:00Z",
    "last_synced_at": "2026-03-19T10:35:00Z",
    "token_path": "/Users/you/Library/Containers/.../local-api-token.txt"
  }
}

Use the absolute path from token_path to read the token. In examples on this page we abbreviate it as ~/.health-analyzer/token.

GET /summary

Compact human-readable summary of the selected integration dataset. Requires X-Health-Analyzer-Token.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" http://127.0.0.1:8765/summary

GET /steps/daily?start=YYYY-MM-DD&end=YYYY-MM-DD

Normalized daily step counts for a date range. Requires X-Health-Analyzer-Token. Each day exposes its count under value.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" \
  "http://127.0.0.1:8765/steps/daily?start=2026-03-13&end=2026-03-19"

Example response:

{
  "ok": true,
  "success": true,
  "data": {
    "unit": "count",
    "days": [
      { "date": "2026-03-13", "value": 11204 },
      { "date": "2026-03-14", "value": 8930 },
      { "date": "2026-03-15", "value": 12045 },
      { "date": "2026-03-16", "value": 9512 },
      { "date": "2026-03-17", "value": 10321 },
      { "date": "2026-03-18", "value": 7576 },
      { "date": "2026-03-19", "value": 2444 }
    ]
  }
}

GET /sleep/summary?start=YYYY-MM-DD&end=YYYY-MM-DD

Normalized daily sleep summaries for a date range, plus range-level averages. Requires X-Health-Analyzer-Token.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" \
  "http://127.0.0.1:8765/sleep/summary?start=2026-03-13&end=2026-03-19"

Example response:

{
  "ok": true,
  "success": true,
  "data": {
    "avg_hours": 6.72,
    "avg_bedtime": "23:41",
    "avg_wake_time": "06:58",
    "days_detected": 6,
    "days": [
      { "date": "2026-03-13", "hours": 7.2, "asleep_hours": 6.6, "in_bed_hours": 7.2 },
      { "date": "2026-03-18", "hours": 6.7, "asleep_hours": 6.1, "in_bed_hours": 6.7 },
      { "date": "2026-03-19", "hours": null, "asleep_hours": null, "in_bed_hours": null }
    ]
  }
}

GET /workouts/summary?start=YYYY-MM-DD&end=YYYY-MM-DD

Workout totals, a per-type breakdown, and per-session summaries for a date range. Requires X-Health-Analyzer-Token.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" \
  "http://127.0.0.1:8765/workouts/summary?start=2026-03-13&end=2026-03-19"

Example response:

{
  "ok": true,
  "success": true,
  "data": {
    "count": 5,
    "total_minutes": 202,
    "by_type": [
      { "type": "Running", "count": 3, "minutes": 127 },
      { "type": "Strength Training", "count": 2, "minutes": 75 }
    ],
    "workouts": [
      {
        "date": "2026-03-13T18:00:00Z",
        "type": "Running",
        "duration_minutes": 45,
        "energy_burned_kcal": 420
      }
    ]
  }
}

GET /heart-rate/trends?start=YYYY-MM-DD&end=YYYY-MM-DD

Average heart rate, resting heart rate, and HRV (SDNN) day series for a date range. Requires X-Health-Analyzer-Token. Each metric is returned as its own array of { date, value } points.

curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" \
  "http://127.0.0.1:8765/heart-rate/trends?start=2026-03-13&end=2026-03-19"

Example response:

{
  "ok": true,
  "success": true,
  "data": {
    "average_heart_rate": [
      { "date": "2026-03-13", "value": 72 },
      { "date": "2026-03-18", "value": 73 }
    ],
    "resting_heart_rate": [
      { "date": "2026-03-13", "value": 58 },
      { "date": "2026-03-18", "value": 58 }
    ],
    "hrv_sdnn": [
      { "date": "2026-03-13", "value": 42 },
      { "date": "2026-03-18", "value": 41 }
    ]
  }
}

Error Handling

When a request fails, the server still responds with HTTP 200 and a JSON body where ok and success are false. The human-readable message is in error; a machine-readable code is nested under errorDetail. (Genuinely malformed HTTP requests are the exception and return HTTP 400.)

{
  "ok": false,
  "success": false,
  "error": "No imported health dataset is available.",
  "errorDetail": {
    "code": "dataset_unavailable",
    "message": "No imported health dataset is available."
  }
}

Common error codes:

Code Description
unauthorized Missing or invalid X-Health-Analyzer-Token header on a protected endpoint.
dataset_unavailable The Mac app is running but no Apple Health dataset has been imported or selected for integrations.
not_found Unknown endpoint path.
method_not_allowed A non-GET method was used. The API is read-only and only supports GET.
timeout The request exceeded the server's internal processing timeout.

Rate Limits and Limitations

  • No formal rate limit -- the API runs on localhost, so there is no external throttling. However, the Mac app processes requests on its main thread, so extremely rapid polling (e.g., multiple requests per second) may cause brief UI lag.
  • Read-only -- there are no POST, PUT, PATCH, or DELETE endpoints. The API cannot modify your health data.
  • Localhost only -- the API binds to 127.0.0.1 and is not accessible from other devices on your network.
  • Mac app must be running -- the API is served by the Mac app process. If the app is closed, requests will fail with a connection refused error.
  • Data freshness -- the API reads from the app's selected integration dataset. To get updated data, import or sync newer data and select the right dataset for integrations when needed.

Use Cases

OpenClaw

Install the apple-health-export-analyzer ClawHub skill to give OpenClaw access to the /openclaw/ endpoints: /openclaw/status, /openclaw/daily-brief, /openclaw/recent-trends, and /openclaw/weekly-summary. See the OpenClaw Integration guide for setup steps and example prompts.

Claude Code

Use curl from Claude Code to read health data directly into your development workflow:

curl -s -H "X-Health-Analyzer-Token: $(cat ~/.health-analyzer/token)" \
  "http://127.0.0.1:8765/steps/daily?start=2026-03-13&end=2026-03-19" | jq .

Mac Shortcuts

Use the Get Contents of URL action in Shortcuts to call any endpoint. Pass the token in the X-Health-Analyzer-Token header and parse the JSON response to build notifications, widgets, or automations.

Custom Scripts

Any language that can make HTTP requests works with this API. Python, Node.js, shell scripts, and Swift are all supported. Example in Python:

import requests

token = open("~/.health-analyzer/token").read().strip()
resp = requests.get(
    "http://127.0.0.1:8765/steps/daily",
    params={"start": "2026-03-13", "end": "2026-03-19"},
    headers={"X-Health-Analyzer-Token": token}
)
data = resp.json()
for day in data["data"]["days"]:
    print(f"{day['date']}: {day['value']} steps")