{
  "openapi": "3.0.0",
  "info": {
    "title": "WorkoutX API",
    "version": "1.0.0",
    "description": "## The most comprehensive exercise API\n\n**WorkoutX API** gives you instant access to **1,400+ exercises** with high-quality GIF animations,\ndetailed instructions, muscle targeting data, effort levels, mechanics, force type, calorie estimates, and more.\n\n### Authentication\n\nPass your API key via header (recommended):\n```\nX-WorkoutX-Key: wx_your_api_key\n```\nOr as a query parameter:\n```\n?api-key=wx_your_api_key\n```\n\n### Response Headers\n\nEvery authenticated response includes quota and rate limit headers:\n\n| Header | Description |\n|--------|-------------|\n| `X-WorkoutX-Plan` | Your current plan ID |\n| `X-RateLimit-Limit` | Max requests per rate limit window |\n| `X-RateLimit-Remaining` | Requests remaining this window |\n| `X-Quota-Limit` | Monthly quota |\n| `X-Quota-Remaining` | Monthly requests remaining |\n| `X-Quota-Reset` | Date quota resets |\n\n### Plans\n\n| Plan | Price | Monthly Requests | Rate Limit | GIF Access |\n|------|-------|-----------------|------------|------------|\n| Free | $0/mo | 500 | 30/min | Full library |\n| Basic | $9.99/mo | 3,000 | 150/min | 500 unique GIFs |\n| Pro | $15.99/mo | 10,000 | 300/min | Full library |\n| Ultra | $24.99/mo | 35,000 | 600/min | Full library |\n\nGet your API key at [workoutxapp.com](https://workoutxapp.com)",
    "contact": {
      "name": "WorkoutX Support",
      "url": "https://workoutxapp.com",
      "email": "support@workoutxapp.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://workoutxapp.com/terms.html"
    }
  },
  "servers": [
    {
      "url": "https://api.workoutxapp.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Exercises",
      "description": "Browse and filter exercises"
    },
    {
      "name": "Meta",
      "description": "Filter value lists and API status"
    },
    {
      "name": "GIFs",
      "description": "Exercise GIF serving"
    },
    {
      "name": "Supplements",
      "description": "Curated supplement database (Pro & Ultra)"
    },
    {
      "name": "Workout Generator",
      "description": "Generate workouts and multi-week programs"
    }
  ],
  "paths": {
    "/v1/exercises": {
      "get": {
        "summary": "Get all exercises",
        "description": "Returns the full exercise list. Optional filters can be combined and are\ncase-insensitive (`chest`, `Chest`, `CHEST` all match).\n",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "bodyPart",
            "schema": {
              "type": "string"
            },
            "example": "Chest"
          },
          {
            "in": "query",
            "name": "target",
            "schema": {
              "type": "string"
            },
            "example": "Pectorals"
          },
          {
            "in": "query",
            "name": "equipment",
            "schema": {
              "type": "string"
            },
            "example": "Barbell"
          },
          {
            "in": "query",
            "name": "name",
            "schema": {
              "type": "string"
            },
            "description": "Partial name match"
          },
          {
            "in": "query",
            "name": "muscle",
            "schema": {
              "type": "string"
            },
            "description": "Searches both target and secondaryMuscles"
          },
          {
            "in": "query",
            "name": "effortLevel",
            "schema": {
              "type": "string",
              "enum": [
                "beginner",
                "intermediate",
                "advanced"
              ]
            }
          },
          {
            "in": "query",
            "name": "mechanics",
            "schema": {
              "type": "string",
              "enum": [
                "compound",
                "isolation"
              ]
            }
          },
          {
            "in": "query",
            "name": "force",
            "schema": {
              "type": "string",
              "enum": [
                "push",
                "pull",
                "hold",
                "carry"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 10
            },
            "description": "Number of results (0 = all, plan limits apply)"
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "in": "query",
            "name": "sortMethod",
            "schema": {
              "type": "string",
              "enum": [
                "id",
                "name",
                "bodyPart",
                "target",
                "equipment",
                "effortLevel",
                "mechanics",
                "force",
                "popularityRank",
                "caloriesBurnPerMin"
              ]
            }
          },
          {
            "in": "query",
            "name": "sortOrder",
            "schema": {
              "type": "string",
              "enum": [
                "ascending",
                "descending"
              ],
              "default": "ascending"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of exercises",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExerciseList"
                }
              }
            }
          }
        }
      }
    },
    "/v1/exercises/bodyPartList": {
      "get": {
        "summary": "Get all available body parts",
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "Array of body part strings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "example": [
                    "Back",
                    "Cardio",
                    "Chest"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/exercises/targetList": {
      "get": {
        "summary": "Get all available target muscles",
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "Array of target muscle strings"
          }
        }
      }
    },
    "/v1/exercises/equipmentList": {
      "get": {
        "summary": "Get all available equipment types",
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "Array of equipment strings"
          }
        }
      }
    },
    "/v1/exercises/secondaryMuscleList": {
      "get": {
        "summary": "Get all available secondary muscles",
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "Array of strings"
          }
        }
      }
    },
    "/v1/exercises/search": {
      "get": {
        "summary": "Multi-filter search (WorkoutX exclusive)",
        "description": "Filter by multiple criteria simultaneously. Requires Basic plan or higher.",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "bodyPart",
            "schema": {
              "type": "string"
            },
            "example": "Chest"
          },
          {
            "in": "query",
            "name": "target",
            "schema": {
              "type": "string"
            },
            "example": "Pectorals"
          },
          {
            "in": "query",
            "name": "equipment",
            "schema": {
              "type": "string"
            },
            "example": "Barbell"
          },
          {
            "in": "query",
            "name": "name",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "muscle",
            "schema": {
              "type": "string"
            },
            "description": "Searches both target and secondaryMuscles"
          },
          {
            "in": "query",
            "name": "effortLevel",
            "schema": {
              "type": "string",
              "enum": [
                "beginner",
                "intermediate",
                "advanced"
              ]
            },
            "description": "Filter by difficulty level"
          },
          {
            "in": "query",
            "name": "mechanics",
            "schema": {
              "type": "string",
              "enum": [
                "compound",
                "isolation"
              ]
            },
            "description": "Filter by movement mechanics"
          },
          {
            "in": "query",
            "name": "force",
            "schema": {
              "type": "string",
              "enum": [
                "push",
                "pull",
                "hold",
                "carry"
              ]
            },
            "description": "Filter by force type"
          },
          {
            "in": "query",
            "name": "isUnilateral",
            "schema": {
              "type": "boolean"
            },
            "description": "Filter unilateral (single-sided / alternating) exercises"
          },
          {
            "in": "query",
            "name": "jointFocus",
            "schema": {
              "type": "string",
              "enum": [
                "shoulder",
                "elbow",
                "wrist",
                "hip",
                "knee",
                "ankle",
                "lumbar_spine",
                "thoracic_spine",
                "cervical_spine",
                "spine"
              ]
            },
            "description": "Ultra plan — Joint & Rehab Metadata. Filter by the primary joint the movement's target muscle acts through (a derived, anatomical field — not a clinical or rehab recommendation). Useful for joint-based shortlists in physical therapy / mobility / senior-fitness apps.\n",
            "example": "knee"
          },
          {
            "in": "query",
            "name": "intensityLevel",
            "schema": {
              "type": "string",
              "enum": [
                "gentle",
                "moderate",
                "vigorous"
              ]
            },
            "description": "Ultra plan — Joint & Rehab Metadata. Derived overall-exertion band computed from the exercise's MET value.\n"
          },
          {
            "in": "query",
            "name": "movementTag",
            "schema": {
              "type": "string",
              "enum": [
                "beginner-friendly",
                "controlled-movement",
                "minimal-equipment",
                "low-intensity",
                "joint-friendly"
              ]
            },
            "description": "Ultra plan — Joint & Rehab Metadata. Filter by a derived descriptive movement tag (e.g. \"joint-friendly\" surfaces beginner-level, single-joint, gentle-pace movements tied to a specific joint).\n"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "sortMethod",
            "schema": {
              "type": "string",
              "enum": [
                "id",
                "name",
                "bodyPart",
                "target",
                "equipment",
                "effortLevel",
                "mechanics",
                "force",
                "popularityRank",
                "caloriesBurnPerMin"
              ]
            }
          },
          {
            "in": "query",
            "name": "sortOrder",
            "schema": {
              "type": "string",
              "enum": [
                "ascending",
                "descending"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered exercise list",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExerciseList"
                }
              }
            }
          }
        }
      }
    },
    "/v1/exercises/changes": {
      "get": {
        "summary": "Dataset-sync changelog — exercises added/updated since a date (Ultra only)",
        "description": "Returns exercises added or updated on or after the `since` date, newest\nfirst, each annotated with `addedAt`, `updatedAt`, and `changeType`\n(added | updated). Keep a local mirror of the dataset in sync and pick up\nnew exercises and GIFs added during your subscription without re-pulling\neverything. Ultra plan only.\n\n**How change detection works:** an exercise is reported here only if its\nstored `updatedAt` timestamp is on or after `since`. There is no content\ndiffing — a catalog edit that does not bump the record's `updatedAt`\n(e.g. a bulk data-quality pass applied directly to the dataset) will not\nappear in this feed.\n\n**Fallback signal — `datasetETag`:** every response includes a\n`datasetETag` field holding the current dataset hash. It is the exact\nsame value returned as the `ETag` header on `GET /v1/exercises`, and it\nchanges whenever the underlying catalog file changes at all — including\nedits that did not bump any record's `updatedAt`. Store the\n`datasetETag` you last synced with and compare it on each poll: if it\ndiffers but `total` is 0, something in the catalog changed that\nper-record timestamps did not capture, and a full re-pull is advisable.\n",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "since",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "example": "2026-01-01",
            "description": "ISO date/datetime. Returns items changed on or after this."
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Changed exercises since the given date"
          },
          "403": {
            "description": "Plan upgrade required (Ultra plan needed)"
          },
          "422": {
            "description": "Missing or invalid 'since' parameter"
          }
        }
      }
    },
    "/v1/exercises/bodyPart/{bodyPart}": {
      "get": {
        "summary": "Get exercises by body part",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "bodyPart",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Chest"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered exercises"
          }
        }
      }
    },
    "/v1/exercises/target/{target}": {
      "get": {
        "summary": "Get exercises by target muscle",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "target",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Biceps"
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered exercises"
          }
        }
      }
    },
    "/v1/exercises/equipment/{equipment}": {
      "get": {
        "summary": "Get exercises by equipment",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "equipment",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Barbell"
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered exercises"
          }
        }
      }
    },
    "/v1/exercises/name/{name}": {
      "get": {
        "summary": "Get exercises by name (partial match)",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "curl"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching exercises"
          }
        }
      }
    },
    "/v1/exercises/exercise/{id}": {
      "get": {
        "summary": "Get a single exercise by ID",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0001"
          }
        ],
        "responses": {
          "200": {
            "description": "Single exercise object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Exercise"
                }
              }
            }
          },
          "404": {
            "description": "Exercise not found"
          }
        }
      }
    },
    "/v1/exercises/{id}/similar": {
      "get": {
        "summary": "Get similar exercises",
        "description": "Returns exercises that closely match the given one based on target muscle,\nbody part, mechanics, force type, secondary muscles, and effort level.\nEach result includes a `similarityScore` (higher = more similar).\n",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0025"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked list of similar exercises"
          },
          "404": {
            "description": "Source exercise not found"
          }
        }
      }
    },
    "/v1/exercises/{id}/alternatives": {
      "get": {
        "summary": "Get alternative exercises (same target, different equipment)",
        "description": "Finds exercises that hit the same target muscle but use different\nequipment — perfect for \"I don't have a barbell\" scenarios.\nOptionally prefer a specific equipment via `?equipment=dumbbell`\nor exclude one via `?excludeEquipment=machine`.\n",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0025"
          },
          {
            "in": "query",
            "name": "equipment",
            "schema": {
              "type": "string"
            },
            "description": "Prefer alternatives using this equipment"
          },
          {
            "in": "query",
            "name": "excludeEquipment",
            "schema": {
              "type": "string"
            },
            "description": "Exclude alternatives using this equipment (defaults to source exercise's equipment)"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ranked list of alternative exercises"
          },
          "404": {
            "description": "Source exercise not found"
          }
        }
      }
    },
    "/v1/exercises/{id}/calories": {
      "get": {
        "summary": "Estimate calorie burn for an exercise",
        "description": "Returns estimated calories burned based on the exercise's per-minute\ncalorie value (70kg baseline), scaled to the user's weight.\nFormula: `kcal = baseKcalPerMin × (weightKg / 70) × minutes`\n",
        "tags": [
          "Exercises"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0025"
          },
          {
            "in": "query",
            "name": "weightKg",
            "schema": {
              "type": "number",
              "default": 70
            },
            "description": "User's body weight in kilograms"
          },
          {
            "in": "query",
            "name": "minutes",
            "schema": {
              "type": "number",
              "default": 10
            },
            "description": "Duration of activity in minutes"
          }
        ],
        "responses": {
          "200": {
            "description": "Calorie burn estimate"
          },
          "404": {
            "description": "Exercise not found"
          }
        }
      }
    },
    "/v1/gifs/{filename}": {
      "get": {
        "summary": "Get exercise GIF",
        "tags": [
          "GIFs"
        ],
        "description": "Returns the exercise GIF for the given ID.\n- **Free plan**: watermarked GIF\n- **Basic plan**: up to 500 unique exercise GIFs per account\n- **Paid plans**: original high-quality GIF\n\nSubject to the plan's rate limit and monthly request quota\n(both enforced by the auth middleware).\n\nWhen Supabase is configured, streams from CDN.\nOtherwise serves directly from the server filesystem.\n",
        "parameters": [
          {
            "in": "path",
            "name": "filename",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0025.gif"
          }
        ],
        "responses": {
          "200": {
            "description": "GIF image",
            "content": {
              "image/gif": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Basic plan unique GIF limit reached"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/status": {
      "get": {
        "summary": "API health and stats",
        "tags": [
          "Meta"
        ],
        "responses": {
          "200": {
            "description": "API is reachable (see `dependencies` for DB/Redis health)"
          }
        }
      }
    },
    "/v1/supplements": {
      "get": {
        "summary": "List supplements (Pro & Ultra only)",
        "description": "Curated supplement database with goals, timing, typical dosages, and\nevidence levels. Informational content only — not medical advice.\n",
        "tags": [
          "Supplements"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "category",
            "schema": {
              "type": "string"
            },
            "example": "protein",
            "description": "Filter by category (see /supplements/filters)"
          },
          {
            "in": "query",
            "name": "goal",
            "schema": {
              "type": "string",
              "enum": [
                "muscle_gain",
                "strength",
                "fat_loss",
                "endurance",
                "recovery",
                "mobility",
                "general_health"
              ]
            },
            "description": "Filter by training goal"
          },
          {
            "in": "query",
            "name": "timing",
            "schema": {
              "type": "string"
            },
            "example": "pre_workout",
            "description": "Filter by intake timing (pre_workout, post_workout, intra_workout, morning, evening, with_meals, any_time)"
          },
          {
            "in": "query",
            "name": "evidence",
            "schema": {
              "type": "string",
              "enum": [
                "strong",
                "moderate",
                "emerging"
              ]
            },
            "description": "Filter by research evidence level"
          },
          {
            "in": "query",
            "name": "search",
            "schema": {
              "type": "string"
            },
            "description": "Search by name, summary, or category"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of supplements (sorted by evidence level)"
          },
          "403": {
            "description": "Plan upgrade required (Pro or Ultra plan needed)"
          }
        }
      }
    },
    "/v1/supplements/filters": {
      "get": {
        "summary": "Available supplement filter values (Pro & Ultra only)",
        "description": "Lists all categories, goals, timings, and evidence levels with counts.",
        "tags": [
          "Supplements"
        ],
        "responses": {
          "200": {
            "description": "Filter values"
          },
          "403": {
            "description": "Plan upgrade required"
          }
        }
      }
    },
    "/v1/supplements/stack": {
      "get": {
        "summary": "Goal-based supplement stack (Ultra only)",
        "description": "Returns an ordered supplement stack for a training goal, sized by level,\nwith a timing guide grouping each item by when it's typically taken.\nInformational content only — not medical advice.\n",
        "tags": [
          "Supplements"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "goal",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "muscle_gain",
                "strength",
                "fat_loss",
                "endurance",
                "recovery",
                "mobility",
                "general_health"
              ]
            },
            "description": "Training goal"
          },
          {
            "in": "query",
            "name": "level",
            "schema": {
              "type": "string",
              "enum": [
                "essential",
                "standard",
                "comprehensive"
              ],
              "default": "standard"
            },
            "description": "Stack size — essential (3), standard (5), comprehensive (8)"
          }
        ],
        "responses": {
          "200": {
            "description": "Ordered supplement stack with timing guide"
          },
          "403": {
            "description": "Plan upgrade required (Ultra plan needed)"
          },
          "422": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/v1/supplements/exercise/{exerciseId}": {
      "get": {
        "summary": "Supplements relevant to an exercise (Pro & Ultra only)",
        "description": "Maps the exercise's training context (resistance vs cardio) to goals and\nreturns the most relevant supplements, strongest evidence first.\n",
        "tags": [
          "Supplements"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "exerciseId",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "0025"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 6,
              "minimum": 1,
              "maximum": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recommended supplements for the exercise"
          },
          "403": {
            "description": "Plan upgrade required"
          },
          "404": {
            "description": "Exercise not found"
          }
        }
      }
    },
    "/v1/supplements/{id}": {
      "get": {
        "summary": "Get a single supplement by ID (Pro & Ultra only)",
        "tags": [
          "Supplements"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "creatine-monohydrate"
          }
        ],
        "responses": {
          "200": {
            "description": "Supplement details"
          },
          "403": {
            "description": "Plan upgrade required"
          },
          "404": {
            "description": "Supplement not found"
          }
        }
      }
    },
    "/v1/workout/generate": {
      "get": {
        "summary": "Generate a structured workout plan (Pro & Ultra only)",
        "description": "Returns a fully structured workout plan based on your preferences.\nEach call generates a fresh plan — ideal for \"today's workout\" features.\nCounts as 1 API call against your quota.\n",
        "tags": [
          "Workout Generator"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "goal",
            "schema": {
              "type": "string",
              "enum": [
                "muscle_gain",
                "strength",
                "fat_loss",
                "endurance",
                "mobility"
              ],
              "default": "muscle_gain"
            },
            "description": "Training goal"
          },
          {
            "in": "query",
            "name": "duration",
            "schema": {
              "type": "integer",
              "minimum": 20,
              "maximum": 120,
              "default": 45
            },
            "description": "Target workout duration in minutes"
          },
          {
            "in": "query",
            "name": "level",
            "schema": {
              "type": "string",
              "enum": [
                "beginner",
                "intermediate",
                "advanced"
              ],
              "default": "intermediate"
            },
            "description": "Fitness level"
          },
          {
            "in": "query",
            "name": "equipment",
            "schema": {
              "type": "string"
            },
            "example": "barbell,dumbbell",
            "description": "Comma-separated list of available equipment. Omit for any equipment."
          },
          {
            "in": "query",
            "name": "split",
            "schema": {
              "type": "string",
              "enum": [
                "full_body",
                "upper",
                "lower",
                "push",
                "pull",
                "legs",
                "push_pull_legs",
                "upper_lower",
                "core"
              ],
              "default": "full_body"
            },
            "description": "Which body parts to train in this session.\n- full_body: chest, back, shoulders, legs, arms\n- upper: chest, back, shoulders, arms\n- lower: quads, hamstrings, glutes, lower back\n- push: chest, shoulders, triceps\n- pull: back, biceps\n- legs: quads, hamstrings, calves\n- core: abs, lower back\nIgnored if bodyFocus is provided.\n"
          },
          {
            "in": "query",
            "name": "bodyFocus",
            "schema": {
              "type": "string"
            },
            "example": "chest,back",
            "description": "Comma-separated body parts for full custom selection. Overrides split."
          },
          {
            "in": "query",
            "name": "exclude",
            "schema": {
              "type": "string"
            },
            "example": "0001,0034",
            "description": "Comma-separated exercise IDs to exclude (e.g. user dislikes or already did today)"
          },
          {
            "in": "query",
            "name": "seed",
            "schema": {
              "type": "string"
            },
            "description": "Optional. Pass a seed to get a reproducible workout — the same seed +\nparams always returns the same plan. Omit for a fresh plan each call;\nthe response always includes the `seed` used so you can reproduce it.\n"
          }
        ],
        "responses": {
          "200": {
            "description": "Generated workout plan"
          },
          "403": {
            "description": "Plan upgrade required (Pro or Ultra plan needed)"
          },
          "422": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/v1/workout/program": {
      "get": {
        "summary": "Generate a multi-week training program with progressive overload (Ultra only)",
        "description": "Returns a periodised, multi-week program. Exercises are fixed per training\nday so progress can be tracked week to week, while sets and intensity\nfollow a 4-week undulating block (3 build weeks + a deload) that repeats.\nCounts as 1 API call. Ultra plan only.\n",
        "tags": [
          "Workout Generator"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "goal",
            "schema": {
              "type": "string",
              "enum": [
                "muscle_gain",
                "strength",
                "fat_loss",
                "endurance",
                "mobility"
              ],
              "default": "muscle_gain"
            }
          },
          {
            "in": "query",
            "name": "level",
            "schema": {
              "type": "string",
              "enum": [
                "beginner",
                "intermediate",
                "advanced"
              ],
              "default": "intermediate"
            }
          },
          {
            "in": "query",
            "name": "weeks",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 12,
              "default": 4
            },
            "description": "Program length in weeks"
          },
          {
            "in": "query",
            "name": "daysPerWeek",
            "schema": {
              "type": "integer",
              "minimum": 2,
              "maximum": 6,
              "default": 3
            },
            "description": "Training days per week (sets the weekly split)"
          },
          {
            "in": "query",
            "name": "duration",
            "schema": {
              "type": "integer",
              "minimum": 20,
              "maximum": 120,
              "default": 60
            },
            "description": "Per-session target duration in minutes"
          },
          {
            "in": "query",
            "name": "equipment",
            "schema": {
              "type": "string"
            },
            "example": "barbell,dumbbell",
            "description": "Comma-separated available equipment. Omit for any."
          }
        ],
        "responses": {
          "200": {
            "description": "Generated multi-week program"
          },
          "403": {
            "description": "Plan upgrade required (Ultra plan needed)"
          },
          "422": {
            "description": "Invalid parameters"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-WorkoutX-Key",
        "description": "Your WorkoutX API key (starts with wx_)"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api-key",
        "description": "Your WorkoutX API key as a query parameter"
      }
    },
    "schemas": {
      "Exercise": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "0025"
          },
          "name": {
            "type": "string",
            "example": "Barbell Bench Press"
          },
          "bodyPart": {
            "type": "string",
            "example": "Chest"
          },
          "equipment": {
            "type": "string",
            "example": "Barbell"
          },
          "target": {
            "type": "string",
            "example": "Pectorals"
          },
          "secondaryMuscles": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "Triceps",
              "Anterior Deltoid"
            ]
          },
          "instructions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gifUrl": {
            "type": "string",
            "example": "/v1/gifs/0025.gif",
            "description": "Pass your API key to retrieve the GIF. Free plan returns watermarked version."
          },
          "category": {
            "type": "string",
            "example": "strength"
          },
          "description": {
            "type": "string",
            "example": "Barbell Bench Press is a intermediate multi-joint compound pushing exercise targeting the Pectorals in the Chest region."
          },
          "difficulty": {
            "type": "string",
            "enum": [
              "beginner",
              "intermediate",
              "advanced"
            ],
            "example": "intermediate",
            "description": "Filter/sort alias: effortLevel."
          },
          "mechanic": {
            "type": "string",
            "enum": [
              "compound",
              "isolation"
            ],
            "example": "compound",
            "description": "Filter/sort alias: mechanics."
          },
          "force": {
            "type": "string",
            "enum": [
              "push",
              "pull",
              "hold",
              "carry"
            ],
            "example": "push"
          },
          "met": {
            "type": "number",
            "example": 6,
            "description": "Metabolic equivalent of task."
          },
          "caloriesPerMinute": {
            "type": "number",
            "example": 7.3,
            "description": "kcal/min (~70kg baseline). Filter/sort alias: caloriesBurnPerMin."
          },
          "popularityRank": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "example": 5,
            "description": "Derived 1–5 \"common use\" score (mechanic + equipment ubiquity + difficulty). Not engagement data."
          },
          "isUnilateral": {
            "type": "boolean",
            "example": false,
            "description": "True for single-sided / alternating movement variations."
          },
          "recommendedSets": {
            "type": "string",
            "example": "3-4",
            "description": "Default set range for the movement type."
          },
          "recommendedReps": {
            "type": "string",
            "example": "6-10",
            "description": "Default rep range for the movement type."
          },
          "joint_focus": {
            "type": "string",
            "nullable": true,
            "example": "shoulder",
            "description": "Ultra: primary joint the target muscle acts through (anatomical, not clinical)."
          },
          "intensity_level": {
            "type": "string",
            "nullable": true,
            "enum": [
              "gentle",
              "moderate",
              "vigorous"
            ],
            "example": "vigorous",
            "description": "Ultra: exertion band derived from met."
          },
          "movement_tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "beginner-friendly",
              "minimal-equipment"
            ],
            "description": "Ultra: derived descriptive movement labels."
          }
        }
      },
      "ExerciseList": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer",
            "example": 1321
          },
          "count": {
            "type": "integer",
            "example": 20
          },
          "offset": {
            "type": "integer",
            "example": 0
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Exercise"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "Unauthorized"
          },
          "message": {
            "type": "string",
            "example": "API key required."
          }
        }
      },
      "QuotaError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "Monthly Quota Exceeded"
          },
          "message": {
            "type": "string"
          },
          "quota": {
            "type": "object",
            "properties": {
              "used": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "remaining": {
                "type": "integer"
              },
              "resetDate": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "upgrade": {
            "type": "string",
            "example": "https://workoutxapp.com/pricing"
          }
        }
      }
    },
    "parameters": {
      "limitParam": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "default": 20,
          "minimum": 1,
          "maximum": 100
        },
        "description": "Number of results to return"
      },
      "offsetParam": {
        "name": "offset",
        "in": "query",
        "schema": {
          "type": "integer",
          "default": 0,
          "minimum": 0
        },
        "description": "Pagination offset"
      },
      "sortMethodParam": {
        "name": "sortMethod",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "name",
            "effortLevel",
            "mechanics",
            "popularityRank",
            "caloriesBurnPerMin",
            "bodyPart",
            "target",
            "equipment"
          ]
        },
        "description": "Field to sort by"
      },
      "sortOrderParam": {
        "name": "sortOrder",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "ascending",
            "descending"
          ],
          "default": "ascending"
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "QuotaExceeded": {
        "description": "Monthly quota exceeded",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/QuotaError"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "ApiKeyQuery": []
    }
  ],
  "externalDocs": {
    "description": "WorkoutX API documentation",
    "url": "https://workoutxapp.com/docs.html"
  }
}
