---
title: "Get a single exercise by ID or slug"
method: GET
path: "/exercises/{id}"
tags: ["Exercises"]
---

# Get a single exercise by ID or slug

`GET /exercises/{id}`

## Request

- Base URL: `https://exercise-api.ymove.app/api/v2`
- URL: `https://exercise-api.ymove.app/api/v2/exercises/{id}`
- Auth: one of:
  - API key in header `X-API-Key`
  - API key in query parameter `api_key`

## Path parameters

- `id` string, required

## Query parameters

- `excludeVideos` boolean

## Response `200`

Exercise details. Videos are included by default; pass excludeVideos=1 for metadata and thumbnails only, which costs nothing. When the monthly exercise cap is exceeded and this exercise was not previously accessed, the video URLs are removed and a `_warning` is included. Thumbnails accompany any returned video; on Scale they are returned even when no video is.

- object
  - `data` Exercise
    - `id` string, uuid, required
    - `title` string, required
    - `slug` string, required
    - `description` string, nullable
    - `instructions` string[], nullable
    - `importantPoints` string[], nullable
    - `muscleGroup` string, required
    - `secondaryMuscles` string[], nullable
    - `muscleGroups` string[], nullable: Every muscle this exercise works, primary and supporting, at anatomical detail (e.g. ["back","lats","rhomboids","traps","erector_spinae"]). muscleGroup is the single coarse value the filters use; this is the detail behind it, for body maps and analysis. Populated for the whole catalogue.
    - `equipment` string, required
    - `category` string, nullable
    - `difficulty` string, nullable
    - `videoUrl` string, uri, nullable: Pre-signed CDN URL for primary video. Expires after 48 hours.
    - `videoHlsUrl` string, uri, nullable: Pre-signed CDN URL for HLS playlist. Expires after 48 hours.
    - `thumbnailUrl` string, uri, nullable: Default thumbnail (up to 600x800, 3:4) for the primary video, served from ymove.app. Static and cacheable - it does not expire. Same as thumbnails.default. Returned in browse mode too, where the video URLs are not.
    - `thumbnails` Thumbnails: Five framings of one frame from the clip, all served from ymove.app. Unlike the video URLs these are static: no token, no expiry, safe to cache, store and hotlink. They accompany the video whenever one is returned, and never count against your monthly cap. On Scale they are also returned without a video, in browse mode and with excludeVideos; on the capped plans they are not, so the monthly exercise limit stays visible while you build rather than arriving all at once the day you switch video on. The frame is picked from across the clip for a visible face and the most extended pose, so a jump is caught mid-air rather than at the standing rest position the clip opens on. Every crop is centred on the person by face detection, and each one is white-balanced after cropping, so a grid of clips from different shoots reads as one library instead of drifting warm or green between shoots.
      - `default` string, uri, required: Up to 600x800 (3:4). The one to reach for, and what thumbnailUrl points at. A mild portrait holds a standing lift and a lying floor exercise without cramping either.
      - `square` string, uri, required: Up to 600x600 (1:1). List rows, grid tiles, anywhere the layout is already square.
      - `portrait` string, uri, required: Up to 720x1280 (9:16). Matches the video itself, for full-bleed mobile and story-style screens.
      - `landscape` string, uri, required: Up to 1280x720 (16:9). Wide cards, hero strips, and the poster frame of a video player. Tall poses are cropped to the upper body to fit the shape. Sizes are ceilings: the images are never upscaled, so a crop is only as large as the source clip allows, and older clips cap around 720px wide.
      - `original` string, uri, required: The whole frame, uncropped, as shot (portrait, ~9:16). Use it when you want to crop it yourself.
    - `videoDurationSecs` integer, nullable
    - `exerciseType` string[], nullable
    - `hasVideo` boolean, required
    - `hasVideoWhite` boolean, required
    - `hasVideoGym` boolean, required
    - `videos` Video[], required
      - `id` string, uuid, required: Stable unique ID of this video. Use it to tell apart the videos of one exercise, or to store a reference to one specific clip. It does not change when the signed URLs do.
      - `videoUrl` string, uri: Pre-signed CDN URL for MP4 video. Expires after 48 hours.
      - `videoHlsUrl` string, uri: Pre-signed CDN URL for HLS playlist. Expires after 48 hours.
      - `thumbnailUrl` string, uri: The default thumbnail (up to 600x800, 3:4), served from ymove.app. Static and cacheable - it does not expire. Same as thumbnails.default; the other framings are on the thumbnails object.
      - `thumbnails` Thumbnails: Five framings of one frame from the clip, all served from ymove.app. Unlike the video URLs these are static: no token, no expiry, safe to cache, store and hotlink. They accompany the video whenever one is returned, and never count against your monthly cap. On Scale they are also returned without a video, in browse mode and with excludeVideos; on the capped plans they are not, so the monthly exercise limit stays visible while you build rather than arriving all at once the day you switch video on. The frame is picked from across the clip for a visible face and the most extended pose, so a jump is caught mid-air rather than at the standing rest position the clip opens on. Every crop is centred on the person by face detection, and each one is white-balanced after cropping, so a grid of clips from different shoots reads as one library instead of drifting warm or green between shoots.
        - `default` string, uri, required: Up to 600x800 (3:4). The one to reach for, and what thumbnailUrl points at. A mild portrait holds a standing lift and a lying floor exercise without cramping either.
        - `square` string, uri, required: Up to 600x600 (1:1). List rows, grid tiles, anywhere the layout is already square.
        - `portrait` string, uri, required: Up to 720x1280 (9:16). Matches the video itself, for full-bleed mobile and story-style screens.
        - `landscape` string, uri, required: Up to 1280x720 (16:9). Wide cards, hero strips, and the poster frame of a video player. Tall poses are cropped to the upper body to fit the shape. Sizes are ceilings: the images are never upscaled, so a crop is only as large as the source clip allows, and older clips cap around 720px wide.
        - `original` string, uri, required: The whole frame, uncropped, as shot (portrait, ~9:16). Use it when you want to crop it yourself.
      - `tag` 'white-background' | 'gym-shot', required
      - `orientation` 'landscape' | 'portrait': Video aspect orientation. Most exercise clips are PORTRAIT (vertical, ~9:16), shot for mobile. Do not assume landscape. Read this field and size your player to a portrait container (e.g. aspect-ratio 9/16) with object-fit: cover so clips fill the frame instead of letterboxing.
      - `isPrimary` boolean, required
  - `_warning` MonthlyCapWarning: Included as `_warning` in the response body when the monthly exercise cap is exceeded. Exercises not previously accessed will have their video properties (videoUrl, videoHlsUrl, thumbnailUrl, videoDurationSecs, videos) removed entirely from the response. Previously accessed exercises keep their video URLs.
    - `message` string
    - `reason` 'monthly_exercise_cap'
    - `monthlyExercisesUsed` integer
    - `monthlyExerciseLimit` integer
    - `upgradeUrl` string

## Other responses

- `401`: Invalid or missing API key
- `404`: Exercise not found
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/ymove/apis/ymove-fitness-api.md) · [All operations](https://skmtc.dev/ymove/apis/ymove-fitness-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ymove/apis/ymove-fitness-api/revisions/6636f2b4a343?raw)
