Developer docs
Agent API
Give an external AI agent narrow access to training context and confirmed actions. The app stays the source of truth; the agent supplies structured requests and the API validates them.
Authentication
Requests use a bearer token created from Settings. Tokens start withtra_live_and are stored in the database as hashes. The full token is only shown once.
curl https://training.cjarhodes.com/api/agent/today \
-H "Authorization: Bearer tra_live_..." \
-H "Accept: application/json"Create a token
In the app
- 1. Go to Settings.
- 2. Open Agent access.
- 3. Select the scopes the agent needs.
- 4. Store the token in the agent's secret store.
Available scopes
Scopes are independent. Give OpenClaw only the actions it should perform.
Endpoints
GET/api/agent/todayread:todayToday workout and check-in status.
GET/api/agent/weekread:weekCurrent or requested training week.
GET/api/agent/contextread:contextTraining context, upcoming plans, and deterministic target warnings.
POST/api/agent/wodwrite:wodSave a confirmed supplementary-session description.
POST/api/agent/checkinwrite:checkinSubmit confirmed athlete-local daily readiness.
POST/api/agent/completionwrite:completionLog confirmed workout completion status, RPE, and notes.
POST/api/agent/availabilitywrite:availabilityAdd confirmed blackout constraints up to 365 days.
POST/api/agent/sorenesswrite:sorenessLog confirmed soreness after a user check.
POST/api/agent/planner/movewrite:plannerMove a confirmed workout slot without recalibration.
PATCH/api/agent/profilewrite:profileUpdate bounded profile fields and recalculate threshold-dependent TSS.
POST/api/agent/raceswrite:racesCreate a confirmed race entry.
POST/api/agent/syncsync:refreshRefresh Strava, Oura, and WHOOP data with rate limiting.
Confirmation model
The API does not create a normal pending-review queue. When a write is ambiguous or not explicitly confirmed, the route returns 409 confirmation_required. OpenClaw should ask the athlete in chat, then retry the same request withuserConfirmed: true.
{
"ok": false,
"error": "confirmation_required",
"message": "Confirm the extracted supplementary session before saving it.",
"requiresConfirmation": true,
"details": {
"date": "2026-04-27",
"confidence": 0.72,
"uncertainItems": ["Workout date was not visible"]
}
}/api/agent/checkinThe route saves the confirmed athlete-local readiness first, then synchronously generates a workout when requested. A successful response reportsworkoutGeneration: generatedor skipped; it never returns an in-progress state.
If readiness saves but generation fails, the response is non-2xx withok: false,checkinSaved: true, and workoutGeneration: failed. Treat the readiness write as complete and use the generation error to decide whether a retry is appropriate.
/api/agent/todayReturns the athlete-local date, readiness/check-in status, and the workout generated for that date. Responses are marked Cache-Control: no-store.
{
"ok": true,
"date": "2026-04-26",
"timezone": "America/Chicago",
"user": {
"id": "f3b8...",
"email": "alex@example.com"
},
"readiness": {
"submitted": true,
"submittedAt": "2026-04-26T12:03:11.000Z",
"trainedAlready": false,
"overallFatigue": 3,
"motivation": 4,
"currentlyIll": false,
"illnessDays": null,
"returningFromIllness": false,
"notes": "Slept well. Legs a little heavy."
},
"workout": {
"exists": true,
"restDay": false,
"completionStatus": null,
"triSession": {
"type": "run",
"title": "Easy aerobic run",
"durationMinutes": 70,
"tss": 65,
"intensity": "Zone 1-2"
},
"secondTriSession": null,
"wod": null
}
}/api/agent/contextReturns recent fitness, workouts, activities, readiness, soreness, upcoming races, deterministic training-target warnings, and open attention items. Use rangeDaysto request 7 to 90 days of recent history. Upcoming workouts and races are included so the agent can reason about schedule changes before asking for confirmation. A zero-hour discipline target remains authoritative, but the response flags it when an A triathlon enters the 55-day race-proximity window. Coaching continuity is based on the latest swim, bike, or run; supplementary training still contributes load and soreness but cannot hide an endurance gap.
/api/agent/wodThis compatibility endpoint accepts descriptions of strength, conditioning, mobility/recovery, and other booked classes; it does not assume the session is CrossFit. The route and scope retain their legacy names so existing clients keep working. OpenClaw should perform OCR/vision itself, ask for confirmation when details are unclear, then submit text only. The app does not accept screenshots on this endpoint.
{
"date": "2026-04-27",
"source": "openclaw",
"rawText": "exact OCR text from the screenshot",
"cleanText": "cleaned supplementary-session text, preserving original structure",
"confidence": 0.93,
"userConfirmed": true,
"uncertainItems": []
}If confidence is below 0.85 or uncertainItems is not empty, the request returns confirmation_requiredunless userConfirmed is true.
/api/agent/planner/moveMoves a confirmed planner slot. The agent can move the whole day, the primary triathlon session, the secondary triathlon session, or the supplementary slot. Recalibration is not run automatically; moved sessions keep their existing content until the athlete explicitly recalibrates. Completed or synced planner days cannot be moved or overwritten.
{
"fromDate": "2026-04-28",
"toDate": "2026-04-30",
"slot": "tri",
"userConfirmed": true
}Response fields
dateAthlete-local date used for lookup.
readiness.submittedWhether a check-in row exists for the date.
readiness.overallFatigueAthlete-entered fatigue score, or null if not submitted.
workout.existsWhether a generated workout exists for the date.
workout.triSessionPrimary endurance session, including title, content, duration, intensity, and TSS.
workout.secondTriSessionOptional second endurance session.
workout.wodOptional supplementary-session content stored in the legacy WOD field.
workout.completionStatusCurrent workout completion state if logged in the app.
How the right user is selected
The agent does not send an email address, user id, or search query. The bearer token is hashed, matched against the agent_tokenstable, and the matched row supplies the user id. That user id is then used for reads and writes.
Errors
Error responses use the same shape across the endpoint.
{
"ok": false,
"error": "Invalid bearer token"
}401 Missing, invalid, revoked, or expired token.
402 Subscription required.
403 Token does not have the required scope.
429 Generation or refresh rate limit reached; inspect whether a preceding write succeeded.
409 Confirmation required, date conflict, planner collision, or a confirmed resource changed before its write completed.
500 Lookup failed.
Security model
- - Tokens are hashed before storage.
- - Tokens are scoped by capability.
- - Tokens are revocable from Settings.
- - Agent writes are logged to an audit table.
- - Low-confidence or unconfirmed writes return a confirmation-required response.
- - The endpoint does not expose Strava, Oura, WHOOP, billing, or service-role credentials.
- - Store tokens as secrets in the external agent, not in prompts or source control.