SparkyFitness Exercise & Workouts API

The Exercise & Workouts API from SparkyFitness — 23 operation(s) for exercise & workouts.

Operations 25

GET /exercises Retrieve a list of exercises with search, filter, and pagination
GET /exercises/suggested Retrieve a list of suggested exercises
GET /exercises/recent Retrieve a list of recently performed exercises
GET /exercises/top Retrieve a list of top exercises
GET /exercises/search Search for exercises
GET /exercises/search-external Search for exercises from external providers like Wger
GET /exercises/equipment Retrieve a list of available exercise equipment types
GET /exercises/muscle-groups Retrieve a list of available exercise muscle groups
GET /exercises/wger-filters Retrieve unique Wger muscle groups and equipment not present in local database
GET /exercises/names Retrieve exercise names based on muscle and equipment filters
POST /exercises/add-external Add an external exercise (e.g., from Wger) to the user's exercises
POST /exercises/add-nutritionix-exercise Add a Nutritionix exercise to the user's exercises
GET /exercises/{id} Retrieve an exercise by ID
PUT /exercises/{id} Update an existing exercise
DELETE /exercises/{id} Delete an exercise by its ID
POST /exercises/ Create a new exercise
POST /exercises/import Import exercises from a CSV file
POST /exercises/import-json Import exercises from a JSON array
GET /exercises/{id}/deletion-impact Get the impact of deleting an exercise
GET /exercises/needs-review Retrieve a list of exercises needing review
POST /exercises/update-snapshot Update the snapshot of exercise entries for a given exercise
GET /exercises/garmin-activity-details/{exerciseEntryId} Retrieve detailed Garmin activity data for an exercise entry
GET /exercises/activity-details/{exerciseEntryId}/{providerName} Retrieve activity details by exercise entry ID and provider
GET /v2/exercises/search Paginated exercise library search
GET /v2/exercises/{exerciseId}/stats Per-exercise best set + last set stats + recent sessions

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/sparkyfitness-exercise-workouts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

sparkyfitness-exercise-workouts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: SparkyFitness Exercise & Workouts API
  version: 1.0.0
  description: API documentation for the SparkyFitness application, providing a comprehensive guide to all available endpoints. Have caution using the API directly, as improper use may lead to data loss or corruption.  Also note that the API is subject to change without notice due to heavy development, so always refer to the latest documentation for up-to-date information. It might have flaw and due to vite/nginx internal proxy actual end point accessed via front end URL might be different than hitting them directly on the server.
  contact:
    name: SparkyFitness Support
servers:
- url: https://{host}/api
  description: Self-hosted SparkyFitness instance (the operator supplies the host). The upstream spec declares the relative base "/api".
  variables:
    host:
      default: sparkyfitness.example.com
      description: Hostname of your own SparkyFitness deployment. SparkyFitness is self-hosted; there is no vendor-operated API host.
security:
- apiKeyAuth: []
tags:
- name: Exercise & Workouts
paths:
  /exercises:
    get:
      summary: Retrieve a list of exercises with search, filter, and pagination
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: searchTerm
        schema:
          type: string
        description: Search term for exercise names.
      - in: query
        name: categoryFilter
        schema:
          type: string
        description: Filter by exercise category.
      - in: query
        name: ownershipFilter
        schema:
          type: string
        description: Filter by exercise ownership (e.g., 'user', 'public').
      - in: query
        name: equipmentFilter
        schema:
          type: string
        description: Comma-separated list of equipment to filter by.
      - in: query
        name: muscleGroupFilter
        schema:
          type: string
        description: Comma-separated list of muscle groups to filter by.
      - in: query
        name: currentPage
        schema:
          type: integer
          default: 1
        description: The current page number for pagination.
      - in: query
        name: itemsPerPage
        schema:
          type: integer
          default: 10
        description: The number of items to return per page.
      responses:
        '200':
          description: A list of exercises and the total count.
          content:
            application/json:
              schema:
                type: object
                properties:
                  exercises:
                    type: array
                    items:
                      $ref: '#/components/schemas/Exercise'
                  totalCount:
                    type: integer
                    description: Total number of exercises matching the criteria.
        '403':
          description: Forbidden, if the user does not have access.
        '500':
          description: Server error.
  /exercises/suggested:
    get:
      summary: Retrieve a list of suggested exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 5
        description: The maximum number of suggested exercises to return.
      responses:
        '200':
          description: A list of suggested exercises.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Exercise'
        '403':
          description: Forbidden, if the user does not have access.
        '500':
          description: Server error.
  /exercises/recent:
    get:
      summary: Retrieve a list of recently performed exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 5
        description: The maximum number of recent exercises to return.
      responses:
        '200':
          description: A list of recent exercises.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Exercise'
        '403':
          description: Forbidden, if the user does not have access.
        '500':
          description: Server error.
  /exercises/top:
    get:
      summary: Retrieve a list of top exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          default: 5
        description: The maximum number of top exercises to return.
      responses:
        '200':
          description: A list of top exercises.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Exercise'
        '403':
          description: Forbidden, if the user does not have access.
        '500':
          description: Server error.
  /exercises/search:
    get:
      summary: Search for exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: searchTerm
        schema:
          type: string
        description: Term to search for in exercise names.
      - in: query
        name: equipmentFilter
        schema:
          type: string
        description: Comma-separated list of equipment to filter by.
      - in: query
        name: muscleGroupFilter
        schema:
          type: string
        description: Comma-separated list of muscle groups to filter by.
      responses:
        '200':
          description: A list of exercises matching the search criteria.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Exercise'
        '403':
          description: Forbidden, if the user does not have access.
        '500':
          description: Server error.
  /exercises/search-external:
    get:
      summary: Search for exercises from external providers like Wger
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: query
        schema:
          type: string
        description: Search term for external exercise names.
      - in: query
        name: providerId
        schema:
          type: string
        required: true
        description: The ID of the external provider (e.g., Wger).
      - in: query
        name: providerType
        schema:
          type: string
        required: true
        description: The type of the external provider.
      - in: query
        name: equipmentFilter
        schema:
          type: string
        description: Comma-separated list of equipment to filter by.
      - in: query
        name: muscleGroupFilter
        schema:
          type: string
        description: Comma-separated list of muscle groups to filter by.
      - in: query
        name: page
        schema:
          type: integer
          default: 1
        description: Page number (1-based).
      - in: query
        name: pageSize
        schema:
          type: integer
          default: 20
          maximum: 100
        description: Number of results per page.
      responses:
        '200':
          description: Paginated list of external exercises matching the search criteria.
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      description: External search projection (see externalExerciseSearchItemSchema in @workspace/shared). wger and free-exercise-db items include the optional detail fields; nutritionix items carry only the base fields.
                      required:
                      - id
                      - name
                      - source
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        source:
                          type: string
                        category:
                          type:
                          - string
                          - 'null'
                        modality:
                          type: string
                          enum:
                          - weight_reps
                          - reps_only
                          - duration
                          - duration_distance
                          description: Derived from the provider category so import previews can pick a set editor.
                        calories_per_hour:
                          type:
                          - number
                          - 'null'
                        description:
                          type: string
                        force:
                          type:
                          - string
                          - 'null'
                        level:
                          type:
                          - string
                          - 'null'
                        mechanic:
                          type:
                          - string
                          - 'null'
                        equipment:
                          type: array
                          items:
                            type: string
                        primary_muscles:
                          type: array
                          items:
                            type: string
                        secondary_muscles:
                          type: array
                          items:
                            type: string
                        instructions:
                          type: array
                          items:
                            type: string
                        images:
                          type: array
                          items:
                            type: string
                  pagination:
                    type: object
                    properties:
                      page:
                        type: integer
                      pageSize:
                        type: integer
                      totalCount:
                        type: integer
                      hasMore:
                        type: boolean
        '400':
          description: Bad request, if search query/filters or provider details are missing.
        '500':
          description: Server error.
  /exercises/equipment:
    get:
      summary: Retrieve a list of available exercise equipment types
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      responses:
        '200':
          description: A list of equipment types.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
        '500':
          description: Server error.
  /exercises/muscle-groups:
    get:
      summary: Retrieve a list of available exercise muscle groups
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      responses:
        '200':
          description: A list of muscle groups.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
        '500':
          description: Server error.
  /exercises/wger-filters:
    get:
      summary: Retrieve unique Wger muscle groups and equipment not present in local database
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      responses:
        '200':
          description: An object containing lists of unique muscle groups and equipment from Wger.
          content:
            application/json:
              schema:
                type: object
                properties:
                  uniqueMuscles:
                    type: array
                    items:
                      type: string
                    description: List of muscle groups from Wger not present locally.
                  uniqueEquipment:
                    type: array
                    items:
                      type: string
                    description: List of equipment from Wger not present locally.
        '500':
          description: Server error.
  /exercises/names:
    get:
      summary: Retrieve exercise names based on muscle and equipment filters
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: muscle
        schema:
          type: string
        description: Filter by muscle group.
      - in: query
        name: equipment
        schema:
          type: string
        description: Filter by equipment type.
      responses:
        '200':
          description: A list of exercise names.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
        '500':
          description: Server error.
  /exercises/add-external:
    post:
      summary: Add an external exercise (e.g., from Wger) to the user's exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - wgerExerciseId
              properties:
                wgerExerciseId:
                  type: integer
                  description: The ID of the external exercise from Wger.
      responses:
        '201':
          description: The newly created exercise.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Exercise'
        '400':
          description: Bad request, if Wger exercise ID is missing.
        '500':
          description: Server error.
  /exercises/add-nutritionix-exercise:
    post:
      summary: Add a Nutritionix exercise to the user's exercises
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Nutritionix exercise data.
              example:
                name: Dumbbell Bicep Curl
                category: Strength
                equipment:
                - Dumbbell
                muscle_groups:
                - Biceps
                description: Curl dumbbells to work biceps.
                external_id: nutritionix_12345
                external_provider: Nutritionix
      responses:
        '201':
          description: The newly created exercise.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Exercise'
        '400':
          description: Bad request, if Nutritionix exercise data is missing.
        '500':
          description: Server error.
  /exercises/{id}:
    get:
      summary: Retrieve an exercise by ID
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: id
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise to retrieve.
      responses:
        '200':
          description: The exercise object.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Exercise'
        '400':
          description: Bad request, if exercise ID is invalid.
        '403':
          description: Forbidden, if the user does not have access.
        '404':
          description: Exercise not found.
        '500':
          description: Server error.
    put:
      summary: Update an existing exercise
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: id
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise to update.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                exerciseData:
                  type: string
                  description: JSON string of exercise data to update (name, category, modality, equipment, muscle_groups, description, instructions, is_public, images - existing image URLs). modality is one of weight_reps, reps_only, duration, duration_distance; omitted or unrecognized values leave the stored modality untouched, and changing the category alone never re-derives it.
                  example: '{"name": "Updated Push-up", "category": "Strength", "modality": "reps_only", "equipment": ["None"], "muscle_groups": ["Chest", "Triceps"], "description": "An updated classic bodyweight exercise.", "instructions": ["Start in a plank position.", "Lower your body until your chest nearly touches the floor.", "Push back up to the starting position."], "is_public": true, "images": ["http://example.com/old_image.jpg"]}'
                images:
                  type: array
                  items:
                    type: string
                    format: binary
                  description: New image files for the exercise.
      responses:
        '200':
          description: The updated exercise object.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Exercise'
        '400':
          description: Bad request, if exercise ID is invalid or data is malformed.
        '403':
          description: Forbidden, if the user does not have access to update the exercise.
        '404':
          description: Exercise not found.
        '500':
          description: Server error.
    delete:
      summary: Delete an exercise by its ID
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: id
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise to delete.
      - in: query
        name: forceDelete
        schema:
          type: boolean
          default: false
        description: If true, forces deletion even if there are linked entries.
      responses:
        '200':
          description: Exercise deleted successfully.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          description: Bad request, if exercise ID is invalid.
        '403':
          description: Forbidden, if the user does not have access to delete the exercise.
        '404':
          description: Exercise not found.
        '500':
          description: Server error.
  /exercises/:
    post:
      summary: Create a new exercise
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                exerciseData:
                  type: string
                  description: JSON string of exercise data (name, category, modality, equipment, muscle_groups, description, instructions, is_public). modality is one of weight_reps, reps_only, duration, duration_distance; omitted or unrecognized values are derived from the category.
                  example: '{"name": "Push-up", "category": "Strength", "modality": "reps_only", "equipment": ["None"], "muscle_groups": ["Chest", "Triceps"], "description": "A classic bodyweight exercise.", "instructions": ["Start in a plank position.", "Lower your body until your chest nearly touches the floor.", "Push back up to the starting position."], "is_public": true}'
                images:
                  type: array
                  items:
                    type: string
                    format: binary
                  description: Array of image files for the exercise.
      responses:
        '201':
          description: The newly created exercise.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Exercise'
        '400':
          description: Bad request, if exercise data is invalid.
        '500':
          description: Server error.
  /exercises/import:
    post:
      summary: Import exercises from a CSV file
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: CSV file containing exercise data.
      responses:
        '201':
          description: Result of the import operation.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  importedCount:
                    type: integer
                  errors:
                    type: array
                    items:
                      type: string
        '500':
          description: Server error.
  /exercises/import-json:
    post:
      summary: Import exercises from a JSON array
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - exercises
              properties:
                exercises:
                  type: array
                  items:
                    $ref: '#/components/schemas/Exercise'
                  description: Array of exercise objects to import.
      responses:
        '201':
          description: Result of the import operation.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  importedCount:
                    type: integer
                  errors:
                    type: array
                    items:
                      type: string
        '400':
          description: Bad request, if data format is invalid.
        '409':
          description: Conflict, if there are duplicate exercises.
        '500':
          description: Server error.
  /exercises/{id}/deletion-impact:
    get:
      summary: Get the impact of deleting an exercise
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: id
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise to check deletion impact for.
      responses:
        '200':
          description: An object detailing the impact of deletion.
          content:
            application/json:
              schema:
                type: object
                properties:
                  canDelete:
                    type: boolean
                    description: Indicates if the exercise can be safely deleted.
                  linkedEntries:
                    type: integer
                    description: Number of exercise entries linked to this exercise.
                  message:
                    type: string
                    description: A message explaining the deletion impact.
        '400':
          description: Bad request, if exercise ID is invalid.
        '403':
          description: Forbidden, if the user does not have access.
        '404':
          description: Exercise not found.
        '500':
          description: Server error.
  /exercises/needs-review:
    get:
      summary: Retrieve a list of exercises needing review
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      responses:
        '200':
          description: A list of exercises that need review.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Exercise'
        '500':
          description: Server error.
  /exercises/update-snapshot:
    post:
      summary: Update the snapshot of exercise entries for a given exercise
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - exerciseId
              properties:
                exerciseId:
                  type: string
                  format: uuid
                  description: The ID of the exercise for which to update snapshots.
      responses:
        '200':
          description: Result of the snapshot update operation.
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          description: Bad request, if exercise ID is missing.
        '500':
          description: Server error.
  /exercises/garmin-activity-details/{exerciseEntryId}:
    get:
      summary: Retrieve detailed Garmin activity data for an exercise entry
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: exerciseEntryId
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise entry associated with the Garmin activity.
      responses:
        '200':
          description: Detailed activity data from Garmin.
          content:
            application/json:
              schema:
                type: object
        '400':
          description: Invalid exercise entry ID.
        '404':
          description: Garmin activity details not found.
        '500':
          description: Server error.
  /exercises/activity-details/{exerciseEntryId}/{providerName}:
    get:
      summary: Retrieve activity details by exercise entry ID and provider
      tags:
      - Exercise & Workouts
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: exerciseEntryId
        schema:
          type: string
          format: uuid
        required: true
        description: The ID of the exercise entry to retrieve activity details for.
      - in: path
        name: providerName
        schema:
          type: string
        required: true
        description: The name of the external provider (e.g., 'Garmin').
      responses:
        '200':
          description: Activity details from the specified provider.
          content:
            application/json:
              schema:
                type: object
                properties:
                  activityId:
                    type: string
                  activityType:
                    type: string
                  duration:
                    type: number
                  calories:
                    type: number
                  distance:
                    type: number
        '400':
          description: Bad request, if exercise entry ID or provider name is invalid.
        '404':
          description: Activity details not found for this exercise entry and provider.
        '500':
          description: Server error.
  /v2/exercises/search:
    get:
      summary: Paginated exercise library search
      tags:
      - Exercise & Workouts
      description: Returns a paginated slice of the user's exercise library, ordered by name ASC. RLS scopes results to the caller.
      security:
      - apiKeyAuth: []
      parameters:
      - in: query
        name: searchTerm
        schema:
          type: string
        description: Optional substring match against exercise name (ILIKE).
      - in: query
        name: equipmentFilter
        schema:
          type: string
        description: Comma-separated list of equipment to filter by.
      - in: query
        name: muscleGroupFilter
        schema:
          type: string
        description: Comma-separated list of muscle groups (primary or secondary).
      - in: query
        name: page
        schema:
          type: integer
          default: 1
        description: Page number (1-based).
      - in: query
        name: pageSize
        schema:
          type: integer
          default: 20
        description: Items per page (max 100).
      responses:
        '200':
          description: Paginated exercise library results.
        '400':
          description: Invalid query parameters.
        '401':
          description: Unauthenticated.
        '500':
          description: Internal server error.
  /v2/exercises/{exerciseId}/stats:
    get:
      summary: Per-exercise best set + last set stats + recent sessions
      tags:
      - Exercise & Workouts
      description: 'Returns the caller''s all-time best set (heaviest weight; tie-broken by reps DESC, entry_date DESC, created_at DESC),

        most recent set (entry_date + created_at DESC, then highest set_number), and up to 3 most recent sessions

        (entry date + full set list, newest first) for a single exercise. Recent sessions include warmup sets;

        entries with no weight/reps-bearing sets (e.g. cardio) are skipped. Both set fields are null and

        recentSessions is empty when the user has no qualifying history. Scoped to req.userId.

        '
      security:
      - apiKeyAuth: []
      parameters:
      - in: path
        name: exerciseId
        required: true
        schema:
          type: string
          format: uuid
        description: Exercise UUID.
      - in: query
        name: excludePresetEntryId
        required: false
        schema:
          type: string
          format: uuid
        description: 'Optional preset-entry UUID to exclude from the baseline. Used by the live active-workout card so today''s

          in-progress (or pre-persisted planned) sets do not pollute the historical best/last baseline, and by the

          edit-workout screens to exclude the workout being edited. Also applies to recentSessions.

          '
      - in: query
        name: presetId
        required: false
        schema:
          type: integer
          minimum: 1
        description: 'Optional workout preset id to scope recentSessions to. When supplied, only sessions performed as that

          preset are considered, so the live "Previous" placeholders reflect this preset''s own history instead of

          this exercise''s history from a different preset. Does not affect bestSet/lastSet, which stay

          exercise-global (a PR is a PR regardless of which preset it happened under).

          '
      responses:
        '200':
          description: Best set + last set stats + recent sessions.
        '400':
          description: Invalid exerciseId, excludePresetEntryId (not a UUID), or presetId (not a positive integer).
        '401':
          description: Unauthenticated.
        '403':
          description: Forbidden (no diary permission when acting on behalf of another user).
        '500':
          description: Internal server error.
components:
  schemas:
    Exercise:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The unique identifier for the exercise.
        user_id:
          type: string
          format: uuid
          description: The ID of the user who owns the exercise.
        name:
          type: strin

# --- truncated at 32 KB (34 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/sparkyfitness/refs/heads/main/openapi/sparkyfitness-exercise-workouts-api-openapi.yml