{"openapi":"3.0.3","info":{"title":"YMove Fitness API","version":"2.3.0","description":"Access 698+ professional exercise videos, a comprehensive food & nutrition database, recipe search, and AI-powered meal plan generation. Features include rate limiting, monthly exercise caps, and video access protection. Video URLs are pre-signed and expire after 48 hours. Always fetch fresh exercise data before displaying videos. Sign up at https://ymove.app/exercise-api/signup for a free trial.","contact":{"email":"contact@ymove.app","url":"https://ymove.app/exercise-api"}},"servers":[{"url":"https://exercise-api.ymove.app/api/v2","description":"Production"}],"security":[{"ApiKeyHeader":[]},{"ApiKeyQuery":[]}],"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"},"ApiKeyQuery":{"type":"apiKey","in":"query","name":"api_key"}},"schemas":{"Video":{"type":"object","required":["tag","isPrimary"],"description":"Video URLs are pre-signed and expire after 48 hours. Do not cache these URLs. Always fetch fresh exercise data before displaying videos.","properties":{"videoUrl":{"type":"string","format":"uri","description":"Pre-signed CDN URL for MP4 video. Expires after 48 hours."},"videoHlsUrl":{"type":"string","format":"uri","description":"Pre-signed CDN URL for HLS playlist. Expires after 48 hours."},"thumbnailUrl":{"type":"string","format":"uri","description":"Pre-signed CDN URL for thumbnail image. Expires after 48 hours."},"tag":{"type":"string","enum":["white-background","gym-shot"]},"orientation":{"type":"string","enum":["landscape","portrait"],"description":"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":{"type":"boolean"}}},"Exercise":{"type":"object","required":["id","title","slug","muscleGroup","equipment","hasVideo","hasVideoWhite","hasVideoGym","videos"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string","nullable":true},"instructions":{"type":"array","items":{"type":"string"},"nullable":true},"importantPoints":{"type":"array","items":{"type":"string"},"nullable":true},"muscleGroup":{"type":"string"},"secondaryMuscles":{"type":"array","items":{"type":"string"},"nullable":true},"equipment":{"type":"string"},"category":{"type":"string","nullable":true},"difficulty":{"type":"string","nullable":true},"videoUrl":{"type":"string","format":"uri","nullable":true,"description":"Pre-signed CDN URL for primary video. Expires after 48 hours."},"videoHlsUrl":{"type":"string","format":"uri","nullable":true,"description":"Pre-signed CDN URL for HLS playlist. Expires after 48 hours."},"thumbnailUrl":{"type":"string","format":"uri","nullable":true,"description":"Pre-signed CDN URL for thumbnail. Expires after 48 hours."},"videoDurationSecs":{"type":"integer","nullable":true},"exerciseType":{"type":"array","items":{"type":"string"},"nullable":true},"hasVideo":{"type":"boolean"},"hasVideoWhite":{"type":"boolean"},"hasVideoGym":{"type":"boolean"},"videos":{"type":"array","items":{"$ref":"#/components/schemas/Video"}}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","title":"Barbell Bench Press","slug":"barbell-bench-press","description":"A compound chest exercise performed lying on a flat bench.","instructions":["Lie on a flat bench with feet flat on the floor","Grip the barbell slightly wider than shoulder width","Lower the bar to mid-chest","Press the bar back up to full arm extension"],"importantPoints":["Keep your back flat on the bench","Do not bounce the bar off your chest"],"muscleGroup":"chest","secondaryMuscles":["triceps","shoulders"],"equipment":"barbell","category":"compound","difficulty":"intermediate","videoUrl":"https://vz-xxx.b-cdn.net/video-id/play_720p.mp4?token=...","videoHlsUrl":"https://vz-xxx.b-cdn.net/video-id/playlist.m3u8?token=...","thumbnailUrl":"https://vz-xxx.b-cdn.net/video-id/thumbnail.jpg?token=...","videoDurationSecs":12,"exerciseType":["strength"],"hasVideo":true,"hasVideoWhite":true,"hasVideoGym":false,"videos":[{"videoUrl":"https://vz-xxx.b-cdn.net/video-id/play_720p.mp4?token=...","videoHlsUrl":"https://vz-xxx.b-cdn.net/video-id/playlist.m3u8?token=...","thumbnailUrl":"https://vz-xxx.b-cdn.net/video-id/thumbnail.jpg?token=...","tag":"white-background","orientation":"landscape","isPrimary":true}]}},"Pagination":{"type":"object","required":["page","pageSize","total","totalPages"],"properties":{"page":{"type":"integer"},"pageSize":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}},"MuscleGroup":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"exerciseCount":{"type":"integer"}}},"WorkoutExercise":{"type":"object","properties":{"exercise":{"$ref":"#/components/schemas/Exercise"},"sets":{"type":"integer"},"reps":{"type":"string"},"restSeconds":{"type":"integer"},"order":{"type":"integer"}}},"Workout":{"type":"object","properties":{"name":{"type":"string"},"muscleGroups":{"type":"array","items":{"type":"string"},"description":"Muscle groups targeted (expanded from any aliases in the request)."},"muscleGroupsRequested":{"type":"array","items":{"type":"string"},"description":"The original muscleGroup values from the request, including any aliases (full_body, upper_body, lower_body)."},"difficulty":{"type":"string"},"estimatedMinutes":{"type":"integer","description":"Estimated total workout duration, including warmup and cooldown when present."},"exerciseCount":{"type":"integer"},"exercises":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"}},"warmup":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"},"description":"Warmup exercises (bodyweight stretches, mobility, and light cardio) placed at the start of the session. Present unless includeWarmup=false."},"cooldown":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"},"description":"Cooldown exercises (bodyweight stretches and mobility) placed at the end of the session. Present unless includeCooldown=false."}}},"ProgramDay":{"type":"object","properties":{"day":{"type":"integer"},"name":{"type":"string"},"muscleGroups":{"type":"array","items":{"type":"string"}},"exercises":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"}},"warmup":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"},"description":"Warmup exercises (bodyweight stretches, mobility, and light cardio) placed at the start of this day. Present unless includeWarmup=false."},"cooldown":{"type":"array","items":{"$ref":"#/components/schemas/WorkoutExercise"},"description":"Cooldown exercises (bodyweight stretches and mobility) placed at the end of this day. Present unless includeCooldown=false."}}},"Program":{"type":"object","properties":{"name":{"type":"string"},"goal":{"type":"string"},"difficulty":{"type":"string"},"daysPerWeek":{"type":"integer"},"weeks":{"type":"integer"},"split":{"type":"string"},"weeklySchedule":{"type":"array","items":{"$ref":"#/components/schemas/ProgramDay"}},"notes":{"type":"string"}}},"PostureIssue":{"type":"object","properties":{"name":{"type":"string","description":"Issue identifier (e.g. \"forward_head\", \"rounded_shoulders\", \"knee_valgus\")."},"severity":{"type":"string","enum":["mild","moderate","severe"]},"description":{"type":"string","description":"Human-readable description of the issue detected."},"how_to_fix":{"type":"string","description":"Plain-language instructions on how to correct the issue."},"exercises":{"type":"array","description":"Corrective exercises with video URLs.","items":{"$ref":"#/components/schemas/CorrectiveExercise"}}}},"CorrectiveExercise":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"video_url":{"type":"string","format":"uri","nullable":true},"thumbnail_url":{"type":"string","format":"uri","nullable":true},"duration":{"type":"string","description":"Recommended sets/reps (e.g. \"30s hold x 3 sets each side\")."}}},"PostureAnalysisResult":{"type":"object","properties":{"data":{"type":"object","properties":{"score":{"type":"integer","description":"Form score from 0 (poor) to 100 (perfect)."},"issues":{"type":"array","items":{"$ref":"#/components/schemas/PostureIssue"}},"summary":{"type":"string","description":"Overall summary of the analysis."},"frames_analyzed":{"type":"integer","description":"Number of video frames analyzed."},"analysis_type":{"type":"string","enum":["standing","seated","walking","exercise","general"]},"exercise_name":{"type":"string"},"llm_used":{"type":"string"},"disclaimer":{"type":"string"}}},"usage":{"type":"object","properties":{"posture_analyses_used":{"type":"integer"},"posture_analyses_included":{"type":"integer"},"is_overage":{"type":"boolean"},"overage_charge":{"type":"number"}}}}},"Usage":{"type":"object","properties":{"plan":{"type":"string"},"status":{"type":"string","description":"Account status (e.g. \"active\", \"trial\")"},"minutesUsed":{"type":"integer"},"minutesLimit":{"type":"integer"},"minutesRemaining":{"type":"integer"},"percentUsed":{"type":"integer"},"rateLimit":{"type":"integer","description":"Requests per minute allowed for your plan"},"monthlyExercisesUsed":{"type":"integer","description":"Distinct exercises accessed in last 30 days"},"monthlyExerciseLimit":{"oneOf":[{"type":"integer"},{"type":"string","enum":["unlimited"]}],"description":"Max unique exercises per month for your plan. Returns \"unlimited\" for yearly plans."},"postureAnalyses":{"type":"object","properties":{"used":{"type":"integer"},"included":{"type":"integer"},"remaining_free":{"type":"integer"},"overage_count":{"type":"integer"},"overage_charge":{"type":"number"},"price_per_extra":{"type":"number"}}},"whiteVideoAccess":{"type":"boolean"},"premiumVideoAccess":{"type":"boolean"},"trialEndsAt":{"type":"string","format":"date-time","nullable":true,"description":"ISO 8601 timestamp when trial expires (null for non-trial accounts)"}}},"ExerciseType":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"exerciseCount":{"type":"integer"}}},"RateLimitError":{"type":"object","required":["error","retryAfterMs"],"properties":{"error":{"type":"string"},"retryAfterMs":{"type":"integer","description":"Milliseconds until the rate limit resets"},"upgradeUrl":{"type":"string","description":"URL to upgrade your plan"},"availablePlans":{"type":"array","items":{"type":"string"}}}},"MonthlyCapWarning":{"type":"object","description":"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.","properties":{"message":{"type":"string"},"reason":{"type":"string","enum":["monthly_exercise_cap"]},"monthlyExercisesUsed":{"type":"integer"},"monthlyExerciseLimit":{"type":"integer"},"upgradeUrl":{"type":"string"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"message":{"type":"string"}}},"Plan":{"type":"object","required":["plan","minutesLimit","postureLimit","brandLimit"],"properties":{"plan":{"type":"string","enum":["basic","pro","scale","enterprise"]},"minutesLimit":{"type":"integer"},"postureLimit":{"type":"integer"},"brandLimit":{"type":"integer"}}},"Food":{"type":"object","description":"All weights default to grams unless noted. Sodium and cholesterol are in milligrams. Three name fields: `shortName` is a compact label for search results and lists. `displayName` is a detailed label that distinguishes similar foods (includes cooking method, grade, brand). `name` is the raw database entry. Use `shortName` for compact views, `displayName` for detail views. The database includes international products from OpenFoodFacts with names in their original language (Dutch, French, German, Spanish, and more). The API is optimized for English, but searching in other languages works for branded and international products.","properties":{"id":{"type":"string"},"fdcId":{"type":"integer","nullable":true,"description":"USDA FoodData Central ID"},"name":{"type":"string","description":"Full original name from the source database (e.g. USDA). Often long and technical - not recommended for UI display. Example: \"Chicken, broilers or fryers, breast, skinless, boneless, meat only, cooked, grilled\""},"shortName":{"type":"string","description":"Short, search-friendly label. Use this for search results, autocomplete dropdowns, and compact list views where space is limited. Example: \"Chicken Breast\", \"Brown Rice\", \"Granola Bar\""},"displayName":{"type":"string","description":"Detailed human-readable name that distinguishes similar foods. Use this for food detail pages, nutrition labels, and anywhere users need to tell similar foods apart. Includes cooking method, grade, and preparation for USDA foods. Includes brand in parentheses for packaged products. Examples: \"Chicken Breast (grilled, lean)\", \"Top Round Steak (choice, lean, broiled)\", \"Granola Bar (Nature Valley)\""},"brand":{"type":"string","nullable":true,"description":"Brand name for packaged/branded products. Null for generic foods (e.g. USDA entries). Also included in displayName when present."},"category":{"type":"string","nullable":true,"description":"Food category (e.g. \"Poultry Products\", \"Fruits and Fruit Juices\", \"Cereals\")"},"servingSize":{"type":"number","description":"Serving size in grams. All nutritional values (calories, protein, fat, etc.) are per this serving size. To calculate nutrition per 100g: divide each value by servingSize and multiply by 100."},"servingDescription":{"type":"string","nullable":true,"description":"Human-readable serving description (e.g. \"1 cup (240ml)\", \"1 medium (182g)\", \"1 slice (28g)\"). Display this to users alongside servingSize for context."},"calories":{"type":"number","description":"Calories (kcal) per serving"},"protein":{"type":"number","description":"Protein per serving in grams. All macro values are in grams unless noted."},"fat":{"type":"number","description":"Total fat per serving (grams)"},"carbs":{"type":"number","description":"Carbohydrates per serving (grams)"},"fiber":{"type":"number","nullable":true,"description":"Dietary fiber per serving (grams)"},"sugar":{"type":"number","nullable":true,"description":"Sugar per serving (grams)"},"sodium":{"type":"number","nullable":true,"description":"Sodium per serving in milligrams (not grams - only sodium and cholesterol use mg)"},"cholesterol":{"type":"number","nullable":true,"description":"Cholesterol per serving in milligrams"},"saturatedFat":{"type":"number","nullable":true,"description":"Saturated fat per serving (grams)"},"barcode":{"type":"string","nullable":true},"imageUrl":{"type":"string","nullable":true,"description":"Product image URL. Sourced from Open Food Facts for branded products and enriched from Open Food Facts / curated staples for generic USDA items. May be null when no image has been located for the food."},"source":{"type":"string","description":"Data source (e.g. \"usda\", \"openfoodfacts\")"},"country":{"type":"string","nullable":true,"description":"ISO 3166-1 alpha-2 country code (e.g. \"FR\", \"US\", \"NL\") when the product is tagged to a specific country. Null for USDA generic items and untagged products."}},"example":{"id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","fdcId":171077,"name":"Chicken, broilers or fryers, breast, skinless, boneless, meat only, cooked, grilled","shortName":"Chicken Breast","displayName":"Chicken Breast (grilled, lean)","brand":null,"category":"Poultry Products","servingSize":100,"servingDescription":"100g","calories":165,"protein":31,"fat":3.6,"carbs":0,"fiber":0,"sugar":0,"sodium":74,"cholesterol":85,"saturatedFat":1,"barcode":null,"source":"usda"}},"FoodAnalysisResult":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"AI-identified food name"},"estimatedGrams":{"type":"number","description":"Estimated portion in grams"},"confidence":{"type":"string","enum":["high","medium","low"],"description":"AI confidence level"},"matchedFood":{"type":"object","nullable":true,"description":"Matched food from the database (null if no match)","properties":{"id":{"type":"string"},"name":{"type":"string"},"servingSizeG":{"type":"number"}}},"nutrition":{"type":"object","nullable":true,"description":"Calculated nutrition based on matched food and estimated portion (null if no match)","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"fat":{"type":"number"},"carbs":{"type":"number"}}}}}},"totals":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"fat":{"type":"number"},"carbs":{"type":"number"}}}}},"usage":{"type":"object","properties":{"analyses_used":{"type":"integer"},"analyses_included":{"type":"integer"},"is_overage":{"type":"boolean"},"overage_charge":{"type":"number"}}}}},"Recipe":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"cuisine":{"type":"string"},"diet":{"type":"array","items":{"type":"string"}},"mealType":{"type":"string"},"prepTimeMinutes":{"type":"integer"},"cookTimeMinutes":{"type":"integer"},"servings":{"type":"integer"},"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"fiber":{"type":"number"},"ingredients":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"amount":{"type":"string"},"calories":{"type":"number"},"protein":{"type":"number"}}}},"instructions":{"type":"array","items":{"type":"string"}}},"example":{"id":"grilled-chicken-salad","title":"Grilled Chicken Salad","description":"A healthy high-protein salad with grilled chicken.","cuisine":"american","diet":["high_protein","low_carb"],"mealType":"lunch","prepTimeMinutes":15,"cookTimeMinutes":10,"servings":2,"calories":350,"protein":38,"carbs":12,"fat":16}},"MealPlan":{"type":"object","properties":{"calories":{"type":"integer","description":"Daily calorie target"},"diet":{"type":"string"},"macroSplit":{"type":"string"},"mealsPerDay":{"type":"integer","description":"Number of meals per day"},"daysCount":{"type":"integer","description":"Number of days in this plan (1-7)"},"averageDailyTotals":{"type":"object","description":"Average per-day macros across all days in the plan.","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}}},"days":{"type":"array","description":"Per-day breakdown of the plan. Always populated, even for daysCount=1.","items":{"type":"object","properties":{"dayIndex":{"type":"integer","description":"1-based day number"},"totals":{"type":"object","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}}},"meals":{"type":"array","items":{"$ref":"#/components/schemas/MealPlanMeal"}}}}},"totals":{"type":"object","description":"Backward-compatible alias for days[0].totals (day 1 only). For multi-day plans use averageDailyTotals or per-day totals in days[].","properties":{"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}}},"meals":{"type":"array","description":"Backward-compatible alias for days[0].meals (day 1 only).","items":{"$ref":"#/components/schemas/MealPlanMeal"}}}},"MealPlanMeal":{"type":"object","properties":{"type":{"type":"string","description":"breakfast | lunch | dinner | snack"},"name":{"type":"string","description":"Recipe title (same as recipe.title)"},"recipeId":{"type":"string","description":"Recipe.id - use to look up the full recipe or fetch its image"},"recipeSlug":{"type":"string"},"imageUrl":{"type":"string","nullable":true},"portionMultiplier":{"type":"number","description":"Multiplier applied to the recipe (0.5-2.0). Macros + ingredient quantities are already scaled."},"calories":{"type":"number","description":"Already scaled by portionMultiplier"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"recipe":{"type":"object","description":"Full recipe metadata so clients can render title + prep time + servings + image without a second API call.","properties":{"id":{"type":"string"},"title":{"type":"string"},"slug":{"type":"string"},"description":{"type":"string","nullable":true},"mealType":{"type":"string"},"cuisineType":{"type":"string","nullable":true},"difficulty":{"type":"string","nullable":true},"prepTimeMin":{"type":"integer"},"cookTimeMin":{"type":"integer"},"servings":{"type":"integer"},"dietTags":{"type":"array","items":{"type":"string"}},"imageUrl":{"type":"string","nullable":true}}},"foods":{"type":"array","description":"Recipe ingredients with quantities + macros already scaled by portionMultiplier.","items":{"type":"object","properties":{"name":{"type":"string"},"portion":{"type":"string","description":"e.g. \"200 g\", \"1.5 tbsp\""},"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"}}}}}},"DietType":{"type":"object","properties":{"diet":{"type":"string","description":"Diet tag identifier (e.g. high_protein, keto, vegan)"},"count":{"type":"integer","description":"Number of recipes with this diet tag"}}},"MealType":{"type":"object","properties":{"mealType":{"type":"string","description":"Meal type (e.g. breakfast, lunch, dinner, snack)"},"count":{"type":"integer","description":"Number of recipes for this meal type"}}}}},"paths":{"/exercises":{"get":{"summary":"List and search exercises","operationId":"listExercises","tags":["Exercises"],"parameters":[{"name":"muscleGroup","in":"query","example":"chest","schema":{"type":"string","enum":["chest","back","shoulders","biceps","triceps","forearms","quads","hamstrings","glutes","calves","core","full_body","abs","cardio"]},"description":"Filter by muscle group"},{"name":"exerciseType","in":"query","schema":{"type":"string","enum":["strength","yoga","stretching","cardio","plyometric","calisthenics","warmup","cooldown","balance","mobility","isometric","rehabilitation","functional","core","hiit"]},"description":"Filter by exercise type"},{"name":"equipment","in":"query","schema":{"type":"string","enum":["machine","barbell","dumbbell","kettlebell","bodyweight","cable"]},"description":"Filter by equipment"},{"name":"difficulty","in":"query","schema":{"type":"string","enum":["beginner","intermediate","advanced"]},"description":"Filter by difficulty"},{"name":"hasVideo","in":"query","example":true,"schema":{"type":"boolean"},"description":"Only return exercises with video"},{"name":"hasVideoWhite","in":"query","schema":{"type":"boolean"},"description":"Only exercises with white-background video"},{"name":"hasVideoGym","in":"query","schema":{"type":"boolean"},"description":"Only exercises with gym-shot video"},{"name":"videoTag","in":"query","schema":{"type":"string","enum":["white-background","gym-shot"]},"description":"Filter video array by tag"},{"name":"search","in":"query","schema":{"type":"string"},"description":"Search by exercise title"},{"name":"page","in":"query","example":1,"schema":{"type":"integer","default":1,"minimum":1},"description":"Page number"},{"name":"pageSize","in":"query","example":3,"schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Results per page"},{"name":"includeVideos","in":"query","schema":{"type":"boolean","default":true},"description":"Whether to include video URLs in the response. Default true: videos are returned and each listed exercise counts toward your monthly cap. Set to false for browse-mode: no videoUrl/videoHlsUrl/thumbnailUrl/videos fields, and no monthly-cap charge for the listed exercises - useful while you paginate the catalog or build search UI without burning quota."}],"responses":{"200":{"description":"Paginated list of exercises. When the monthly exercise cap is exceeded, exercises not previously accessed will have video properties (videoUrl, videoHlsUrl, thumbnailUrl, videoDurationSecs, videos) removed entirely. A `_warning` object is included with details. Previously accessed exercises keep their video URLs.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Exercise"}},"pagination":{"$ref":"#/components/schemas/Pagination"},"_warning":{"$ref":"#/components/schemas/MonthlyCapWarning"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/exercises/exercise-types":{"get":{"summary":"List all exercise types with counts","operationId":"listExerciseTypes","tags":["Exercises"],"responses":{"200":{"description":"List of exercise types","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ExerciseType"}}}}}}}}}},"/exercises/muscle-groups":{"get":{"summary":"List all muscle groups with exercise counts","operationId":"listMuscleGroups","tags":["Exercises"],"responses":{"200":{"description":"List of muscle groups","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MuscleGroup"}}}}}}}}}},"/exercises/{id}":{"get":{"summary":"Get a single exercise by ID or slug","operationId":"getExercise","tags":["Exercises"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Exercise UUID or slug"}],"responses":{"200":{"description":"Exercise details. When the monthly exercise cap is exceeded and this exercise was not previously accessed, video properties are removed entirely and a `_warning` is included.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Exercise"},"_warning":{"$ref":"#/components/schemas/MonthlyCapWarning"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Exercise not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/workouts/generate":{"get":{"summary":"Generate a structured workout","operationId":"generateWorkout","tags":["Workouts"],"parameters":[{"name":"muscleGroup","in":"query","required":true,"style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["chest","back","shoulders","biceps","triceps","forearms","quads","hamstrings","glutes","calves","core","full_body","upper_body","lower_body"]}},"description":"Target muscle group(s). Accepts a single value, a comma-separated list (e.g. \"chest,back\"), or repeated query keys. Aliases: \"full_body\" (all groups), \"upper_body\" (chest, back, shoulders, biceps, triceps, forearms, core), \"lower_body\" (quads, hamstrings, glutes, calves). Aliases can be combined with specific groups."},{"name":"equipment","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["machine","barbell","dumbbell","kettlebell","bodyweight","cable"]}},"description":"Limit to specific equipment. Accepts a single value, comma-separated list, or repeated keys."},{"name":"exerciseType","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["strength","yoga","stretching","cardio","plyometric","calisthenics","warmup","cooldown","balance","mobility","isometric","rehabilitation","functional","core","hiit"]}},"description":"Filter main exercises by type. Accepts a single value, comma-separated list, or repeated keys."},{"name":"difficulty","in":"query","schema":{"type":"string","enum":["beginner","intermediate","advanced"],"default":"intermediate"},"description":"Difficulty level. Filters which exercises are selected: beginner returns beginner-level moves, intermediate returns beginner+intermediate, advanced prefers advanced moves (falling back to intermediate where advanced options are limited). Also sets the default set/rep/rest scheme."},{"name":"exerciseCount","in":"query","schema":{"type":"integer","default":6,"minimum":3,"maximum":12},"description":"Number of main exercises (warmup and cooldown are returned separately and counted in addition to this)."},{"name":"includeWarmup","in":"query","schema":{"type":"boolean","default":true},"description":"Prepends a warmup block of bodyweight stretches, mobility work, and light cardio. Default true; set to false to omit. Warmup exercises count toward your monthly exercise cap."},{"name":"warmupCount","in":"query","schema":{"type":"integer","default":3,"minimum":2,"maximum":5},"description":"Number of warmup exercises. Only applied when includeWarmup is not false."},{"name":"includeCooldown","in":"query","schema":{"type":"boolean","default":true},"description":"Appends a cooldown block of bodyweight stretches and mobility work at the end of the session. Default true; set to false to omit. Cooldown exercises count toward your monthly exercise cap."},{"name":"cooldownCount","in":"query","schema":{"type":"integer","default":3,"minimum":2,"maximum":5},"description":"Number of cooldown exercises. Only applied when includeCooldown is not false."},{"name":"includeVideos","in":"query","schema":{"type":"boolean","default":true},"description":"Whether to include video URLs. Default true. Set to false for browse-mode (no videoUrl/videoHlsUrl/thumbnailUrl/videos fields, and no monthly-cap charge)."}],"responses":{"200":{"description":"Generated workout. When the monthly exercise cap is exceeded, exercises not previously accessed will have video properties removed entirely. A `_warning` object is included with details.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Workout"},"_warning":{"$ref":"#/components/schemas/MonthlyCapWarning"}}}}}},"400":{"description":"Missing required parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/programs/generate":{"get":{"summary":"Generate a multi-week training program","operationId":"generateProgram","tags":["Programs"],"parameters":[{"name":"goal","in":"query","schema":{"type":"string","enum":["muscle_building","weight_loss","strength","endurance"],"default":"muscle_building"},"description":"Training goal. Sets the set/rep/rest scheme and exercises-per-muscle."},{"name":"difficulty","in":"query","schema":{"type":"string","enum":["beginner","intermediate","advanced"],"default":"intermediate"},"description":"Difficulty level. Filters which exercises are selected per muscle: beginner returns beginner-level moves, intermediate returns beginner+intermediate, advanced prefers advanced moves (falling back to intermediate where advanced options are limited). Combine with goal, which controls volume."},{"name":"daysPerWeek","in":"query","schema":{"type":"integer","minimum":3,"maximum":6,"default":4},"description":"Training days per week"},{"name":"weeks","in":"query","schema":{"type":"integer","enum":[4,8,12],"default":4},"description":"Program duration in weeks"},{"name":"equipment","in":"query","schema":{"type":"string","enum":["machine","barbell","dumbbell","kettlebell","bodyweight","cable"]},"description":"Limit to specific equipment"},{"name":"includeWarmup","in":"query","schema":{"type":"boolean","default":true},"description":"Adds a warmup block (bodyweight stretches, mobility, light cardio) to the start of each training day. Default true; set to false to omit. Warmup exercises count toward your monthly exercise cap."},{"name":"warmupCount","in":"query","schema":{"type":"integer","default":3,"minimum":2,"maximum":5},"description":"Number of warmup exercises per day. Only applied when includeWarmup is not false."},{"name":"includeCooldown","in":"query","schema":{"type":"boolean","default":true},"description":"Adds a cooldown block (bodyweight stretches and mobility) to the end of each training day. Default true; set to false to omit. Cooldown exercises count toward your monthly exercise cap."},{"name":"cooldownCount","in":"query","schema":{"type":"integer","default":3,"minimum":2,"maximum":5},"description":"Number of cooldown exercises per day. Only applied when includeCooldown is not false."},{"name":"includeVideos","in":"query","schema":{"type":"boolean","default":true},"description":"Whether to include video URLs. Default true. Set to false for browse-mode (no videoUrl/videoHlsUrl/thumbnailUrl/videos fields, and no monthly-cap charge)."}],"responses":{"200":{"description":"Generated training program. When the monthly exercise cap is exceeded, exercises not previously accessed will have video properties removed entirely. A `_warning` object is included with details.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Program"},"_warning":{"$ref":"#/components/schemas/MonthlyCapWarning"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/posture/analyze":{"post":{"summary":"Analyze exercise form from video (max 100MB)","operationId":"analyzePosture","tags":["Form Analysis"],"description":"Upload an exercise video and get AI-powered form analysis. Returns a form score (0-100), detected issues with plain-language fixes, and corrective exercise recommendations.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["video","exercise_name"],"properties":{"video":{"type":"object","required":["type","data"],"description":"The exercise video to analyze.","properties":{"type":{"type":"string","enum":["base64","url"],"description":"How the video is provided: base64-encoded data or a public URL."},"data":{"type":"string","description":"Base64-encoded video data, or a public URL to the video file."},"media_type":{"type":"string","enum":["video/mp4","video/webm","video/mov","video/quicktime"],"default":"video/mp4"}}},"exercise_name":{"type":"string","description":"Name of the exercise being performed (e.g. \"barbell squat\", \"deadlift\").","minLength":1,"maxLength":200},"analysis_type":{"type":"string","enum":["standing","seated","walking","exercise","general"],"default":"exercise","description":"Type of analysis to perform."},"custom_instructions":{"type":"string","maxLength":500,"description":"Optional extra instructions for the analysis (e.g. \"focus on knee alignment\")."},"num_frames":{"type":"integer","minimum":4,"maximum":20,"default":16,"description":"Number of frames to extract from the video for analysis."}}}}}},"responses":{"200":{"description":"Form analysis result with score, issues, and corrective exercises","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostureAnalysisResult"}}}},"400":{"description":"Validation error or analysis failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/usage":{"get":{"summary":"Check API usage and limits (includes monthly exercise cap)","operationId":"getUsage","tags":["Account"],"responses":{"200":{"description":"Current usage data including monthly exercise cap","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Usage"}}}}}}}}},"/upgrade":{"get":{"summary":"Get available plans and billing portal URL","operationId":"getUpgradeInfo","tags":["Account"],"responses":{"200":{"description":"Available plans and current subscription info","content":{"application/json":{"schema":{"type":"object","required":["currentPlan","availablePlans","message"],"properties":{"currentPlan":{"type":"string","description":"Your current plan (e.g. \"demo\", \"basic\", \"pro\")"},"availablePlans":{"type":"array","items":{"$ref":"#/components/schemas/Plan"}},"billingPortalUrl":{"type":"string","format":"uri","description":"Stripe billing portal URL (only for paid keys with a Stripe customer)"},"message":{"type":"string"}}}}}}}},"post":{"summary":"Start or upgrade a subscription","operationId":"upgradeSubscription","tags":["Account"],"description":"Creates a Stripe checkout session for new subscriptions or returns a billing portal URL for existing subscribers to upgrade.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["plan"],"properties":{"plan":{"type":"string","enum":["basic","pro","scale","enterprise"],"description":"The plan to subscribe to"},"email":{"type":"string","format":"email","description":"Required for demo keys. Paid keys use the email on file."}}}}}},"responses":{"200":{"description":"Checkout or billing portal URL","content":{"application/json":{"schema":{"type":"object","required":["url","message"],"properties":{"url":{"type":"string","format":"uri","description":"Stripe checkout or billing portal URL. Open in a browser to complete."},"message":{"type":"string"}}}}}},"400":{"description":"Invalid plan or missing email","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/foods":{"get":{"summary":"Search the food database","operationId":"searchFoods","tags":["Nutrition"],"parameters":[{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Search term (e.g. \"chicken breast\")"},{"name":"source","in":"query","schema":{"type":"string","enum":["usda","openfoodfacts"]},"description":"Filter results to a single data source."},{"name":"usdaOnly","in":"query","schema":{"type":"boolean"},"description":"Convenience alias for source=usda. Returns only USDA FoodData Central entries - ideal when you want clean generic foods without branded packaged-product clutter."},{"name":"country","in":"query","schema":{"type":"string","minLength":2,"maxLength":2},"description":"ISO 3166-1 alpha-2 country code (e.g. \"FR\", \"US\", \"NL\"). Soft-boosts results tagged with this country in the ranking, so Open Food Facts products local to your users surface first. Does not hard-filter - generic USDA and world results still appear. Also accepted as `cc`."},{"name":"per","in":"query","schema":{"type":"string","enum":["100g","100ml"]},"description":"Normalize nutrition values to a per-100g or per-100ml basis instead of the native serving size."},{"name":"page","in":"query","schema":{"type":"integer","default":1,"minimum":1},"description":"Page number"},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"minimum":1,"maximum":50},"description":"Results per page"}],"responses":{"200":{"description":"Paginated list of foods with nutrition data","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Food"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/foods/{id}":{"get":{"summary":"Get full nutrition details for a food","operationId":"getFood","tags":["Nutrition"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Food ID or slug"}],"responses":{"200":{"description":"Food with full nutrition data including micronutrients","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Food"}}}}}},"404":{"description":"Food not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/foods/barcode/{upc}":{"get":{"summary":"Look up a food product by barcode","operationId":"getFoodByBarcode","tags":["Nutrition"],"parameters":[{"name":"upc","in":"path","required":true,"schema":{"type":"string"},"description":"UPC or EAN barcode number"},{"name":"country","in":"query","schema":{"type":"string","minLength":2,"maxLength":2},"description":"ISO 3166-1 alpha-2 country code (e.g. \"FR\", \"NL\"). When provided, the Open Food Facts fallback is queried with the country locale so nutrition labels and serving descriptions come back localized where available. Also accepted as `cc`."}],"responses":{"200":{"description":"Food product with nutrition data","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Food"}}}}}},"404":{"description":"Product not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/foods/log/text":{"post":{"summary":"AI food logging from text description","operationId":"analyzeFoodText","tags":["Nutrition"],"description":"Send a text description of a meal and get back identified foods with full nutrition data. Pro plan and above. Uses your nutrition analysis quota.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"Text description of a meal (e.g. \"grilled chicken with rice and broccoli\")","maxLength":2000}}}}}},"responses":{"200":{"description":"Identified foods with nutrition data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodAnalysisResult"}}}},"403":{"description":"Requires Pro plan or higher","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/foods/log/photo":{"post":{"summary":"AI food logging from photo","operationId":"analyzeFoodPhoto","tags":["Nutrition"],"description":"Send a base64-encoded photo of a meal and get back identified foods with full nutrition data. Pro plan and above. Uses your nutrition analysis quota.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["image"],"properties":{"image":{"type":"string","description":"Base64-encoded image of a meal (JPEG/PNG)"},"media_type":{"type":"string","enum":["image/jpeg","image/png","image/webp","image/gif"],"default":"image/jpeg"}}}}}},"responses":{"200":{"description":"Identified foods with nutrition data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodAnalysisResult"}}}},"403":{"description":"Requires Pro plan or higher","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/recipes/search":{"get":{"summary":"Search recipes by diet, cuisine, and macros","operationId":"searchRecipes","tags":["Recipes"],"parameters":[{"name":"query","in":"query","schema":{"type":"string"},"description":"Search term (e.g. \"chicken salad\")"},{"name":"diet","in":"query","schema":{"type":"string","enum":["high_protein","low_carb","keto","vegan","vegetarian","mediterranean","paleo"]},"description":"Filter by diet type"},{"name":"cuisine","in":"query","schema":{"type":"string","enum":["american","mediterranean","asian","mexican","italian","indian","japanese"]},"description":"Filter by cuisine"},{"name":"mealType","in":"query","schema":{"type":"string","enum":["breakfast","lunch","dinner","snack"]},"description":"Filter by meal type"},{"name":"maxCalories","in":"query","schema":{"type":"number"},"description":"Maximum calories per serving"},{"name":"minProtein","in":"query","schema":{"type":"number"},"description":"Minimum protein per serving (grams)"},{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Page number"},{"name":"pageSize","in":"query","schema":{"type":"integer","default":20,"maximum":50},"description":"Results per page"}],"responses":{"200":{"description":"Paginated list of recipes","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Recipe"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}}}}},"/recipes/{id}":{"get":{"summary":"Get full recipe with ingredients and nutrition","operationId":"getRecipe","tags":["Recipes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Recipe ID or slug"}],"responses":{"200":{"description":"Full recipe with ingredients, instructions, and nutrition","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Recipe"}}}}}},"404":{"description":"Recipe not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/recipes/diets":{"get":{"summary":"List available diet types","operationId":"listDietTypes","tags":["Recipes"],"responses":{"200":{"description":"List of diet types","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DietType"}}}}}}}}}},"/recipes/meal-types":{"get":{"summary":"List available meal types","operationId":"listMealTypes","tags":["Recipes"],"responses":{"200":{"description":"List of meal types","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MealType"}}}}}}}}}},"/mealplans/generate":{"get":{"summary":"Generate a personalized meal plan","operationId":"generateMealPlan","tags":["Meal Plans"],"parameters":[{"name":"calories","in":"query","required":true,"schema":{"type":"integer"},"description":"Daily calorie target"},{"name":"diet","in":"query","schema":{"type":"string","enum":["balanced","high_protein","low_carb","keto","vegan","vegetarian","mediterranean","paleo"],"default":"balanced"},"description":"Diet preference"},{"name":"meals","in":"query","schema":{"type":"integer","minimum":3,"maximum":6,"default":3},"description":"Number of meals per day"},{"name":"days","in":"query","schema":{"type":"integer","minimum":1,"maximum":7,"default":1},"description":"Number of days in the plan. For days > 1, see data.days[] for per-day breakdown; data.meals/data.totals are aliased to day 1 for backward compatibility."},{"name":"macroSplit","in":"query","schema":{"type":"string","enum":["balanced","high_protein","low_carb","high_fat"],"default":"balanced"},"description":"Macro distribution preference"}],"responses":{"200":{"description":"Generated meal plan with nutrition breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MealPlan"}}}}}},"400":{"description":"Missing required parameter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"tags":[{"name":"Exercises","description":"Browse and search exercise videos. Video URLs are pre-signed and expire after 48 hours."},{"name":"Workouts","description":"Generate structured workouts"},{"name":"Programs","description":"Generate multi-week training programs"},{"name":"Form Analysis","description":"AI-powered exercise form analysis from video"},{"name":"Account","description":"Usage and account management"},{"name":"Nutrition","description":"Search foods, get nutrition data, barcode lookup, and AI food logging"},{"name":"Recipes","description":"Search recipes by diet, cuisine, and macros"},{"name":"Meal Plans","description":"Generate personalized meal plans"}]}