KinesteX

Trainer Chat Endpoint

The unified conversational endpoint. Your users talk to the trainer in natural language — "give me a 30-minute dumbbell chest workout", "make it harder", "let's start" — and the API classifies each message's intent, generates or modifies a workout plan, answers fitness questions, and manages the user's fitness profile.


typescript
1POST https://data.kinestex.com/api/trainer/chat

Integration is minimal by design:

  • One required field per message (message). Everything else is optional.
  • The fitness profile is stored server-side. Send it once and never again.
  • Workout history is stored server-side. The AI plans around recently worked muscle groups automatically.
  • Workout preferences are extracted from the message. "45 minutes, dumbbells, chest and triceps" needs no separate preferences object.

Request fields:


FieldTypeRequiredDescription
messagestringYesThe user's natural-language message
session_idstringNoChat session ID. Omit to use the user's default session (created automatically). Pass the value from a previous response to target a specific session.
stagestringNoClient-declared intent that skips AI classification when you already know it: "CREATE_WORKOUT" (first message of a session) or "RECOMMEND_NEXT" (first message after a completed workout). Anything else falls back to the classifier.
profile_dataobjectNoThe user's fitness profile (see below). Only needed once — it is saved server-side and reused. Sending it again updates the stored profile.
workout_detailsobjectNoExplicit workout preferences (see below). If omitted on a create, preferences are extracted from the message itself.
readinessobjectNoFree-form JSON describing the user's current condition (sleep, soreness, energy…), passed to the AI as context.

Advanced AI controls (model, enable_thinking, thinking_effort: "minimal" / "low" / "medium" / "high") are also accepted — available model identifiers are provided by your KinesteX contact.


Profile object (persists server-side per user, always bound to the authenticated user):


FieldTypeValues / Unit
ageintyears
weightfloatkg
heightfloatcm
genderstring"MALE", "FEMALE", "OTHER"
fitness_goalsstring[]"strength", "muscle_gain", "weight_loss", "cardio_endurance", "general_fitness", "wellness_flexibility"
fitness_level_pushupsstringe.g. "0-5", "6-15", "16+"
fitness_level_cardiostringe.g. "1 mile", "2 mile", "3+ mile"
fitness_level_squatsstringe.g. "0-10", "10-21", "22+"
injuriesobject[]`{ "body_part", "preference": "avoid" \"include", "severity": "severe" \"moderate" \"light" }"avoid" hard-filters exercises targeting that body part; "include"` keeps them but picks light/rehabilitative variants
health_conditionsstring[]free text, e.g. ["Hypertension"]
other_preferencesstringfree text, passed verbatim to the AI
preferred_duration_minutesintdefault workout length (also learned from explicit duration requests)
training_intensityint1–10, intensity ceiling for the plan
structured_programbooltrue = has followed a structured weight-training program (heavier low-rep sets)

Removing an injury restriction via chat (e.g. "my knee is fine now") triggers an are-you-sure confirmation before the profile actually changes.


Workout details object:


FieldTypeDescription
equipmentstring[]e.g. ["dumbbells", "kettlebells"] or ["bodyweight"]
durationintMinutes. If omitted: explicit in message → previous workout in this conversation → profile preference → 30-minute default
body_partsstring[]e.g. ["Chest", "Shoulders", "Triceps"]
include_warmup / include_cooldownboolPrepend warmup / append cooldown exercises
post_workout_feedbackobjectCheck-in from the just-completed workout, sent with stage: "RECOMMEND_NEXT"rpe (1–10, primary progression signal), discomfort ("no_pain" / "mild" / "sharp"), and when sharp: pain_severity (1–10), pain_stopped, pain_body_parts

Intents — every message is classified into one of these (returned in the response so your UI can react). There are no magic strings — "confirm", "let's go", and "start the workout" all classify as START_WORKOUT:


IntentTriggered byEffect
CREATE_WORKOUT"make me a workout…"Semantic search + AI plan generation
MODIFY_WORKOUT"make it harder", "remove the squats"AI edits the current plan
START_WORKOUT"let's start", "confirm", "looks good"Returns the final plan with workout_plan.action = "CONFIRMED"
UNDO / REDO"undo" / "redo"Instant plan history navigation (no AI call)
ASK_QUESTION"what's a superset?"Conversational answer
DISCUSS_RESULTS"how did I do yesterday?"Discusses the user's saved workout results
RECOMMEND_NEXTfirst message after a completed workoutRecovery-aware next workout using stored history + feedback
UPDATE_PROFILE"I weigh 78kg now", "my knee hurts"Updates the stored profile
OFF_TOPICanything non-fitnessPolite redirect

Response — 200 OK:


json
1{
2  "message": "Here's your 30-minute upper-body dumbbell workout! ...",
3  "intent": "CREATE_WORKOUT",
4  "action": "WORKOUT_UPDATED",
5  "session_id": "9c1e37a2-4b7f-4f6e-9a2d-1f2e3d4c5b6a",
6  "workout_plan": {
7    "step": "PLAN_REFINEMENT",
8    "action": null,
9    "data": {
10      "turn_action": "WORKOUT_UPDATED",
11      "can_undo": false,
12      "can_redo": false,
13      "estimated_duration_seconds": 1820,
14      "sequences": [ ... ],
15      "exercises": [ ... ]
16    }
17  }
18}

FieldDescription
messageThe trainer's reply — render this in your chat UI
intentThe classified intent (table above)
actionWhat this turn actually didWORKOUT_UPDATED (plan content changed), NO_CHANGE, QUESTION (trainer awaits a reply), PROFILE_UPDATED (refresh cached profile data), INFO (plain reply)
session_idThe persistent chat session ID — store it and send it on subsequent requests
workout_planPresent only on turns that involve a plan. workout_plan.action is "CONFIRMED" once the user starts/confirms the workout.

⚠️ Two different IDs: the top-level session_id is the persistent chat session — the one you store and send back. The response may also carry a nested workout_plan.session_id; that is internal planning state and you never need to send it.

workout_plan.data.sequences is the ordered plan: each item is an "exercise", "warmup", "cooldown" (with exercise_id, repeats) or a "rest" (with rest_countdown seconds). workout_plan.data.exercises holds the full exercise objects referenced by the sequences, including media URLs and per-language translations — pick the entry matching your requested language, falling back to "en".


Error responses:


StatusCause
400Missing message, invalid JSON, unsupported advanced option
401Missing or invalid JWT
403{ "error": "Subscription required to generate workouts", "code": "not_subscribed" } — only for generation intents when your company manages subscriptions (see Session Auth & Managed Subscriptions)
404session_id doesn't exist or belongs to another user
429Rate limit exceeded (see Sessions, Profile & Limits)
500AI call or session storage failure — { "error": "Failed to process trainer chat", "details": "..." }

Example — create, refine, confirm:


bash
1# 1. First message (profile inline, preferences in the message)
2curl -X POST "https://data.kinestex.com/api/trainer/chat" \
3  -H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \
4  -d '{
5    "message": "Create a 30-minute dumbbell workout for chest and triceps",
6    "stage": "CREATE_WORKOUT",
7    "profile_data": { "age": 28, "weight": 75.0, "height": 180.0, "gender": "MALE", "fitness_goals": ["strength"] }
8  }'
9
10# 2. Refine (session_id from the previous response)
11curl -X POST "https://data.kinestex.com/api/trainer/chat" \
12  -H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \
13  -d '{ "session_id": "<session_id>", "message": "make it harder and add more core work" }'
14
15# 3. Confirm — natural language, no magic string required
16curl -X POST "https://data.kinestex.com/api/trainer/chat" \
17  -H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \
18  -d '{ "session_id": "<session_id>", "message": "looks good, let'\''s start" }'
19
20# 4. Next workout after completing one (recovery-aware, with post-workout feedback)
21curl -X POST "https://data.kinestex.com/api/trainer/chat" \
22  -H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \
23  -d '{
24    "session_id": "<session_id>",
25    "stage": "RECOMMEND_NEXT",
26    "message": "what should I do next?",
27    "workout_details": {
28      "post_workout_feedback": { "rpe": 8, "discomfort": "no_pain" }
29    }
30  }'

See the full TypeScript lifecycle example in Guides & Examples.