KinesteX

Exercises

An exercise is a single movement: demo video, difficulty, target body parts, coaching tips, and the AI model that scores the user's form.




List exercises


text
1GET /api/exercises/client

ParameterTypeDefaultMatches
searchstringnonePartial, case-insensitive match on the English title
body_partsstring[]noneBody part name, case-insensitive
categoriesstring[]noneCategory name, case-insensitive. Deleted categories never match
difficulty_levelstring[]noneeasy, medium, hard. Alias: dif_level. If both are sent, difficulty_level wins
translation_languagesstring[]noneOnly exercises that have a translation in one of these language codes
remove_inactivebooltruefalse also returns deactivated exercises
include_shared_librarybooltruefalse returns only your company's own exercises
langstringenLanguage of the returned text
limitint10Page size, clamped to 100
offsetint0Rows to skip

bash
1curl "https://data.kinestex.com/api/exercises/client?body_parts=Chest,Triceps&categories=Strength&difficulty_level=easy,medium&lang=es&limit=2" \
2  -H "x-api-key: YOUR_API_KEY"

json
1{
2  "exercises": [
3    {
4      "id": 412,
5      "title": "Flexiones",
6      "description": "Ejercicio de empuje para pecho y triceps.",
7      "difficulty_level": "easy",
8      "position": "lying",
9      "calories_per_rep": 0.32,
10      "is_active": true,
11      "body_parts": [{ "name": "Chest" }, { "name": "Triceps" }],
12      "categories": ["Strength", "Muscle Gain"],
13      "contraindications": [],
14      "equipment": [
15        {
16          "id": 3,
17          "title": "Esterilla",
18          "description": "Esterilla de ejercicio estandar.",
19          "thumbnail_url": "https://firebasestorage.googleapis.com/.../mat.png?alt=media"
20        }
21      ],
22      "translation_languages": ["es", "en"],
23      "created_at": "2026-01-14T10:00:00Z",
24      "thumbnail_url": "https://firebasestorage.googleapis.com/.../thumb.png?alt=media",
25      "video_url": "https://firebasestorage.googleapis.com/.../video.mp4?alt=media",
26      "male_thumbnail_url": null,
27      "male_video_url": null,
28      "rest_speech": "descansa-treinta-segundos-abc123",
29      "rest_speech_text": "Descansa 30 segundos",
30      "repeats": 12,
31      "countdown": 3,
32      "correct_second": 1.5,
33      "tips": ["Manten el core activo."],
34      "steps": ["Colocate en posicion de plancha.", "Baja el pecho hacia el suelo."],
35      "common_mistakes": "Dejar caer la cadera.",
36      "created_by": { "id": 1 }
37    }
38  ],
39  "pagination": {
40    "total": 42,
41    "limit": 2,
42    "offset": 0,
43    "total_pages": 21,
44    "current_page": 1,
45    "has_next": true,
46    "has_prev": false
47  }
48}

Exercise fields (list view)


FieldTypeDescription
idnumberExercise identifier
title / descriptionstringLocalized text, falls back to English
difficulty_levelstringeasy, medium, or hard
positionstringstanding, sitting, or lying. Returned, not filterable
calories_per_repnumberEstimated calories per repetition
is_activebool or nullNull is treated as active (legacy rows)
body_partsobject[]Array of { "name": "Chest" } objects
categoriesstring[]Flat array of category names
contraindicationsstring[]Body areas where caution is needed
equipmentobject[]id, title, description, thumbnail_url, localized
translation_languagesstring[]Language codes available for this exercise
thumbnail_url / video_urlstringDefault (female) demo assets
male_thumbnail_url / male_video_urlstring or nullMale demo assets where produced
repeatsnumber or nullDefault repetition count
countdownnumber or nullTimer length in seconds, for timer-based exercises
correct_secondnumber or nullSeconds one correct repetition should take
tipsstring[]Coaching tips, localized
stepsstring[]Step-by-step instructions, localized
common_mistakesstringOmitted when empty
rest_speech / rest_speech_textstringRest-period audio identifier and its text
created_byobject{ "id": <company id> }
created_atstringISO 8601 timestamp

An exercise matching several of your requested categories or body parts appears once, and pagination.total counts distinct exercises, so paging never repeats or skips a row.

Known quirk: on this endpoint translation_languages reports only the language you asked for plus English, because only those translation rows are loaded. To test coverage for another language, filter with translation_languages=<code> instead: that filter queries the full translation table and is accurate. The workout list reports the complete set.



Get one exercise


text
1GET /api/exercises/client/{id}

{id} accepts a numeric ID (412) or a title (Push Ups). Titles are normalized before matching (lowercased, non-alphanumeric characters removed), so Push Ups, push-ups, and pushups all resolve to the same exercise. URL-encode spaces as %20.


ParameterTypeDefaultDescription
langstringenLanguage code, overrides the headers
include_audiobooltruefalse omits the generated audio URLs and returns a lighter payload

bash
1curl "https://data.kinestex.com/api/exercises/client/Push%20Ups?lang=es" \
2  -H "x-api-key: YOUR_API_KEY"

json
1{
2  "id": "412",
3  "ai_model": { "id": "57" },
4  "repeats": 12,
5  "countdown": 3,
6  "thumbnail_url": "https://firebasestorage.googleapis.com/.../thumb.png?alt=media",
7  "video_url": "https://firebasestorage.googleapis.com/.../video.mp4?alt=media",
8  "male_thumbnail_url": null,
9  "male_video_url": null,
10  "difficulty_level": "easy",
11  "position": "lying",
12  "calories_per_rep": 0.32,
13  "body_parts": ["Chest", "Triceps"],
14  "categories": ["Strength", "Muscle Gain"],
15  "contraindications": ["shoulder"],
16  "equipment": [],
17  "is_active": true,
18  "correct_second": 1.5,
19  "non_motivational": false,
20  "translation": {
21    "id": 50,
22    "language": "es",
23    "title": "Flexiones",
24    "description": "Ejercicio de empuje para pecho y triceps.",
25    "tips": ["Manten el core activo."],
26    "exercise_steps": ["Colocate en posicion de plancha.", "Baja el pecho hacia el suelo."],
27    "common_mistakes": "Dejar caer la cadera.",
28    "rest_speech": "descansa-treinta-segundos-abc123",
29    "rest_speech_text": "Descansa 30 segundos",
30    "rest_speech_url_m4a": "https://firebasestorage.googleapis.com/.../rest.m4a?alt=media",
31    "rest_speech_url_webm": "https://firebasestorage.googleapis.com/.../rest.webm?alt=media",
32    "voice_actor": "Glinda"
33  },
34  "created_by": { "id": 1 }
35}

Differences from the list view, worth handling explicitly:


  • id is a string here and a number in the list.
  • body_parts is a flat string[] here and an array of {name} objects in the list.
  • Localized text lives under translation instead of at the root, and it carries the audio URLs, voice_actor, and exercise_steps (the list calls the same data steps).
  • ai_model is reduced to { "id": ... }. Pass that ID to the SDK when you build a fully custom workout UI.
  • Deactivated exercises are still fetchable by ID or title. The remove_inactive filter applies to the list only.

Not found returns 404:


json
1{
2  "message": "Exercise not found",
3  "details": "exercise with normalized title 'unknown' not found in company or library exercises"
4}