Your training data shouldn't be locked in someone else's app.
Every platform says they have an API. Most of them mean "we have a webhook that fires sometimes." We mean you get a real REST API — Bearer token auth, structured workouts, training load analytics, Garmin sync, and tool schemas that plug directly into Claude, GPT, or whatever LLM framework you're using.
Here's how to use it.
The 60-Second Setup
Step 1: Go to Settings → Agent API and generate a key. Copy it — you'll only see it once.
Keys look like this: fse_live_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
Step 2: Make a request.
curl -H "Authorization: Bearer fse_live_YOUR_KEY" \
"https://www.reachflowstate.ai/api/agent/v1/calendar"
That's it. You're in. No OAuth dance, no redirect URIs, no client IDs. One key, one header.
What You Get
The Agent API gives you everything an AI coaching agent needs to be useful:
| Endpoint | What it does |
|---|---|
GET /calendar | Your training calendar with completion status |
GET /workouts/:id | Full workout details including structured steps |
GET /activities | Completed activities from Garmin, Strava, etc. |
GET /training-load | ATL, CTL, TSB — the training load trifecta |
GET /plan | Active training plan, current week, phase |
GET /coach/context | Athlete profile, zones, preferences — everything a coach needs |
GET /coach/insight | AI-ready training summaries with highlights and concerns |
POST /workouts | Create workouts with structured intervals |
PATCH /workouts/:id | Update existing workouts |
DELETE /workouts/:id | Remove workouts |
POST /workouts/:id/notes | Add pre/post-workout notes |
POST /activities/log | Log completed activities manually |
All endpoints live under https://www.reachflowstate.ai/api/agent/v1/.
Building a Coaching Agent
Let's build something real. Here's a Python script that checks your training load, looks at your upcoming week, and tells you if you're doing too much or too little:
import requests
API_KEY = "fse_live_YOUR_KEY"
BASE = "https://www.reachflowstate.ai/api/agent/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1. Get training load
load = requests.get(f"{BASE}/training-load", headers=HEADERS).json()
tsb = load["tsb"]
trend = load["trend"]
compliance = load["compliance_7d"]
# 2. Get this week's calendar
calendar = requests.get(
f"{BASE}/calendar",
params={"from": "2026-03-16", "to": "2026-03-22"},
headers=HEADERS
).json()
upcoming = [e for e in calendar["events"] if not e["completed"]]
# 3. Get athlete context (zones, preferences, goals)
context = requests.get(f"{BASE}/coach/context", headers=HEADERS).json()
goal = context["athlete"]["goal"]
# 4. Make a decision
if tsb < -20:
print(f"⚠️ TSB is {tsb} — you're digging a hole.")
print(f" Consider swapping tomorrow's workout for easy recovery.")
elif tsb > 15:
print(f"🟢 TSB is {tsb} — you're fresh. Time to push.")
elif compliance < 0.6:
print(f"📉 Only {int(compliance*100)}% compliance this week.")
print(f" Life happens, but consistency matters for: {goal}")
else:
print(f"✅ On track. TSB: {tsb}, trend: {trend}")
print(f" {len(upcoming)} workouts remaining this week.")
That's a functional coaching agent in 30 lines. No SDK, no wrapper library — just HTTP.
Structured Workouts
The real power is in structured workout creation. You're not just adding "Run 10K" to a calendar — you're building interval sessions that sync to Garmin watches:
requests.post(f"{BASE}/workouts", headers=HEADERS, json={
"date": "2026-03-17",
"title": "Threshold Intervals",
"sport": "Run",
"duration_minutes": 55,
"steps": [
{
"type": "warmup",
"duration": {"type": "distance", "meters": 1600},
"target": {"type": "pace", "low": 330, "high": 360},
"description": "Easy warmup"
},
{
"type": "repeat",
"iterations": 5,
"steps": [
{
"type": "interval",
"duration": {"type": "distance", "meters": 1000},
"target": {"type": "pace", "low": 240, "high": 255},
"description": "Threshold pace"
},
{
"type": "recovery",
"duration": {"type": "time", "seconds": 90},
"description": "Easy jog recovery"
}
]
},
{
"type": "cooldown",
"duration": {"type": "distance", "meters": 1600},
"target": {"type": "pace", "low": 330, "high": 360},
"description": "Easy cooldown"
}
]
})
That creates a proper structured workout: 1-mile warmup → 5×1K at threshold with 90s recovery → 1-mile cooldown. The API normalizes the step format automatically (pace targets, duration types) so it works correctly when synced to Garmin Connect.
Plugging into LLMs
We ship two files that make AI integration trivial:
Tool Schema (/tool-schema.json)
A JSON file with function definitions for every endpoint. Drop it into any LLM that supports function calling:
import json, requests
# Load the tool schema
tools = requests.get("https://www.reachflowstate.ai/tool-schema.json").json()
# Use with OpenAI
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "What's my training load looking like?"}],
tools=[{"type": "function", "function": t} for t in tools["tools"]],
)
OpenAPI Spec (/openapi.json)
Full OpenAPI 3.0 spec. Works with any code generator, API client, or documentation tool.
Claude MCP
If you're using Claude Desktop or Claude Code, you can mount the entire API as an MCP server:
{
"mcpServers": {
"flowstate": {
"command": "npx",
"args": [
"-y", "@anthropic/openapi-to-mcp",
"--spec", "https://www.reachflowstate.ai/openapi.json"
]
}
}
}
Now Claude can read your calendar, check your training load, and create workouts — all through natural conversation.
Auth & Rate Limits
Authentication is a single Bearer token. Keys have scopes:
read— GET endpoints (calendar, activities, training load, athlete profile)write— POST/PATCH/DELETE (create workouts, log activities, add notes)
You choose which scopes to grant when you create a key. Read-only keys are great for dashboards and monitoring agents. Read+write for coaching agents that create workouts.
Rate limits use a sliding window:
| Tier | Limit |
|---|---|
| Standard | 100 req/min |
| Pro | 1,000 req/min |
| Free | 30 req/min |
Every response includes X-RateLimit-Remaining and X-RateLimit-Reset headers. If you hit the limit, you get a 429 with Retry-After.
For a coaching agent making a few calls per conversation, you'll never come close.
Real Examples
Here are some things people are building:
Morning briefing bot — Fetches training load, today's workout, and yesterday's compliance. Posts to Slack/Discord every morning at 6am.
Adaptive scheduling — Monitors TSB and automatically swaps hard sessions for recovery when fatigue is too high.
Multi-sport dashboard — Pulls activities across running, cycling, and swimming into a custom Grafana dashboard.
Voice coaching — Pipes the coach/context and coach/insight endpoints into a voice agent that gives pre-run briefings.
Garmin auto-sync — Creates structured workouts via the API, then triggers a Garmin sync so they appear on the watch without touching the app.
Error Handling
Every error returns a consistent shape:
{
"error": {
"code": "validation_error",
"message": "'date' and 'title' are required"
}
}
Error codes: unauthorized, forbidden, not_found, rate_limited, validation_error, server_error. Parse the code, not the message — messages are human-readable and may change.
What's Next
The API already covers the full training lifecycle — plan, execute, analyze, adapt. We're actively building:
- Webhook events — get notified when workouts are completed, activities sync, or training load thresholds are crossed
- Batch operations — create a full week of workouts in one call
- Export endpoints — FIT file generation via API for direct device sync
The full API reference has interactive examples in cURL, TypeScript, and Python for every endpoint.
Get Started
- Create a free account (or log in)
- Go to Settings → Agent API
- Generate a key
- Start building
The API is live. The OpenAPI spec and tool schema are public. Go make something cool.