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.
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 public on loopback and do not require a token:
GET /openclaw/statusGET /openclaw/daily-briefGET /status
All other routes require the X-Health-Analyzer-Token header. The token file path is returned by GET /status.
curl -H "X-Health-Analyzer-Token: YOUR_TOKEN" http://127.0.0.1:8765/summary
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,
"app": "Health Data AI Analyzer",
"version": "1.4.2",
"dataset_loaded": true,
"last_import": "2026-03-19T10:30: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. No authentication required.
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 /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,
"app": "Health Data AI Analyzer",
"version": "1.4.2",
"server_version": "1.0.0",
"dataset_loaded": true,
"last_import": "2026-03-19T10:30:00Z",
"token_path": "~/.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.
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,
"data": [
{ "date": "2026-03-13", "steps": 11204 },
{ "date": "2026-03-14", "steps": 8930 },
{ "date": "2026-03-15", "steps": 12045 },
{ "date": "2026-03-16", "steps": 9512 },
{ "date": "2026-03-17", "steps": 10321 },
{ "date": "2026-03-18", "steps": 7576 },
{ "date": "2026-03-19", "steps": 2444 }
]
}
GET /sleep/summary?start=YYYY-MM-DD&end=YYYY-MM-DD
Normalized daily sleep summaries for a date range. 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,
"data": [
{ "date": "2026-03-13", "hours": 7.2 },
{ "date": "2026-03-14", "hours": 6.1 },
{ "date": "2026-03-15", "hours": 8.0 },
{ "date": "2026-03-16", "hours": 5.5 },
{ "date": "2026-03-17", "hours": 6.8 },
{ "date": "2026-03-18", "hours": 6.7 },
{ "date": "2026-03-19", "hours": null }
]
}
GET /workouts/summary?start=YYYY-MM-DD&end=YYYY-MM-DD
Workout totals, minutes, 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,
"data": [
{ "date": "2026-03-13", "count": 1, "total_minutes": 45 },
{ "date": "2026-03-14", "count": 0, "total_minutes": 0 },
{ "date": "2026-03-15", "count": 2, "total_minutes": 72 },
{ "date": "2026-03-16", "count": 1, "total_minutes": 30 },
{ "date": "2026-03-17", "count": 0, "total_minutes": 0 },
{ "date": "2026-03-18", "count": 1, "total_minutes": 55 },
{ "date": "2026-03-19", "count": 0, "total_minutes": 0 }
]
}
GET /heart-rate/trends?start=YYYY-MM-DD&end=YYYY-MM-DD
Average heart rate, resting heart rate, and HRV day series for a date range. Requires X-Health-Analyzer-Token.
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,
"data": [
{ "date": "2026-03-13", "avg_hr": 72, "resting_hr": 58, "hrv": 42 },
{ "date": "2026-03-14", "avg_hr": 75, "resting_hr": 60, "hrv": 38 },
{ "date": "2026-03-15", "avg_hr": 70, "resting_hr": 57, "hrv": 45 },
{ "date": "2026-03-16", "avg_hr": 74, "resting_hr": 59, "hrv": 40 },
{ "date": "2026-03-17", "avg_hr": 71, "resting_hr": 56, "hrv": 44 },
{ "date": "2026-03-18", "avg_hr": 73, "resting_hr": 58, "hrv": 41 },
{ "date": "2026-03-19", "avg_hr": null, "resting_hr": null, "hrv": null }
]
}
Error Handling
All endpoints return a consistent error format when something goes wrong:
{
"ok": false,
"error": "No dataset loaded. Import Apple Health data first.",
"code": "NO_DATASET"
}
Common error scenarios:
| HTTP Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED |
Missing or invalid X-Health-Analyzer-Token header on a protected endpoint. |
| 404 | NOT_FOUND |
Unknown endpoint path. |
| 422 | INVALID_DATE |
Date parameter is missing or not in YYYY-MM-DD format. |
| 503 | NO_DATASET |
The Mac app is running but no Apple Health dataset has been imported or selected for integrations. |
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.1and 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 /openclaw/status and /openclaw/daily-brief. 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"]:
print(f"{day['date']}: {day['steps']} steps")