openapi: 3.0.0
paths:
  /v1/workouts/metadata:
    get:
      operationId: WorkoutsApi_getWorkoutMetadata
      summary: Get available workout categories and difficulties
      description: |-

        Retrieves all unique workout categories (e.g., HIIT, Strength, Mobility, Cardio) and difficulty levels available across workouts.

        **Use this endpoint to populate:**
        - `categoryId` parameter in `POST /v1/orgs/{orgId}/workouts/generate`
        - Workout category filters in your UI

        **Response includes:**
        - `categories`: Array of {id, name} objects for each workout category
        - `difficulties`: Array of difficulty strings (beginner, intermediate, advanced)

        **Example Categories:**
        - HIIT (615aa3f0dbe7140012c59e94)
        - Strength (615aa3dadbe7140012c59e90)
        - Mobility (615aa3e5dbe7140012c59e92)
        - Cardio (615aa3ebdbe7140012c59e93)
        - Yoga (649edb81733e2e007a30ab8d)
        - Pilates (615aa3f5dbe7140012c59e95)

        **Related Metadata Endpoints:**
        - `GET /v1/workouts/metadata` - Categories & difficulties (for workout generation/filtering)
        - `GET /v1/workouts/equipment/metadata` - Equipment items & categories
        - `GET /v1/workouts/exercises/metadata` - Muscle groups & collections
        - `GET /v1/plans/metadata` - Goals & difficulties (for plan generation)

        **For Workout Generation:** Call this endpoint + equipment/metadata + exercises/metadata (advanced)

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Category names

        ---

        **Related Endpoints:**
        - Generate: `POST /v1/orgs/{orgId}/workouts/generate`
        - List: `GET /v1/orgs/{orgId}/workouts`
        - Recommend: `POST /v1/orgs/{orgId}/workouts/recommend`
            
      parameters:
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved category and difficulty lists.
          content:
            application/json:
              schema:
                type: object
                properties:
                  categories:
                    type: array
                    description: List of all available workout categories.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Category ID
                          example: 615aa3f0dbe7140012c59e94
                        name:
                          type: string
                          description: Category display name
                          example: HIIT
                      required:
                        - id
                        - name
                  difficulties:
                    type: array
                    description: List of all available difficulty levels.
                    items:
                      type: string
                      example: intermediate
                example:
                  categories:
                    - id: 615aa3f0dbe7140012c59e94
                      name: HIIT
                    - id: 615aa3dadbe7140012c59e90
                      name: Strength
                    - id: 615aa3e5dbe7140012c59e92
                      name: Mobility
                  difficulties:
                    - beginner
                    - intermediate
                    - advanced
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/metadata' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutMetadata() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/metadata', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/metadata", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/equipment/metadata:
    get:
      operationId: WorkoutsApi_getEquipmentMetadata
      summary: Get available equipment categories and equipment items
      description: |-

        Retrieves all equipment items (e.g., Dumbbells, Kettlebells, Resistance Bands) and their categories (e.g., Free Weights, Bodyweight, Gym Equipment).

        **Use this endpoint to populate:**
        - `preferredEquipmentCategoryIds` in workout generation requests
        - Equipment filters in your application UI

        **Response includes:**
        - `categories`: Equipment categories with {id, name, category} 
        - `equipment`: Individual equipment items with {id, name, equipmentCategoryId}

        **Example Equipment Categories:**
        - Bodyweight (67deb36a6a5e49797c122f56)
        - Free Weights (67deb3696a5e49797c122f55)
        - Gym Equipment (67deb36a6a5e49797c122f57)

        **Example Equipment Items:**
        - Dumbbell (60812dea606fc90011eb4405) → Free Weights
        - Kettlebell (60812dd5606fc90011eb4404) → Free Weights
        - Mat (60812e08606fc90011eb4408) → Bodyweight
        - Resistance Band (64f9800b3b07122623b91c7d) → Free Weights

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Equipment names, equipment category names

        ---

        **Related Metadata Endpoints:**
        - `GET /v1/workouts/equipment/metadata` - Equipment items & categories
        - `GET /v1/workouts/metadata` - Categories & difficulties
        - `GET /v1/workouts/exercises/metadata` - Muscle groups & collections

        **Related Endpoints:**
        - Generate: `POST /v1/orgs/{orgId}/workouts/generate`
        - List: `GET /v1/orgs/{orgId}/workouts`
            
      parameters:
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved equipment and category lists.
          content:
            application/json:
              schema:
                type: object
                properties:
                  categories:
                    type: array
                    description: List of all available equipment categories.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Category ID
                          example: 67deb36a6a5e49797c122f56
                        name:
                          type: string
                          description: Category display name
                          example: Bodyweight
                        category:
                          type: string
                          description: Broader category grouping
                          example: bodyweight
                      required:
                        - id
                        - name
                        - category
                  equipment:
                    type: array
                    description: List of all available equipment items.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Equipment ID
                          example: 60812dea606fc90011eb4405
                        name:
                          type: string
                          description: Equipment display name
                          example: Dumbbell
                        equipmentCategoryId:
                          type: string
                          description: ID of the category this equipment belongs to (optional)
                          example: 67deb3696a5e49797c122f55
                          nullable: true
                      required:
                        - id
                        - name
                example:
                  categories:
                    - id: 67deb36a6a5e49797c122f56
                      name: Bodyweight
                      category: bodyweight
                    - id: 67deb3696a5e49797c122f55
                      name: Free Weights
                      category: free_weights
                    - id: 67deb36a6a5e49797c122f57
                      name: Gym Equipment
                      category: gym
                  equipment:
                    - id: 60812dea606fc90011eb4405
                      name: Dumbbell
                      equipmentCategoryId: 67deb3696a5e49797c122f55
                    - id: 60812dd5606fc90011eb4404
                      name: Kettlebell
                      equipmentCategoryId: 67deb3696a5e49797c122f55
                    - id: 60812e08606fc90011eb4408
                      name: Mat
                      equipmentCategoryId: 67deb36a6a5e49797c122f56
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/equipment/metadata' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getEquipmentMetadata() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/equipment/metadata', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/equipment/metadata", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}:
    get:
      operationId: WorkoutsApi_getWorkout
      summary: Get workout details
      description: |-

        ## Complete Workout Details

        Retrieves comprehensive workout information including metadata, equipment requirements, muscle group distribution, and media assets.

        ---

        ### 📋 What's Included

        | Field | Description | Example |
        |-------|-------------|---------|
        | **Core Info** | Name, description, duration, difficulty | "Full Body HIIT", 1800 seconds |
        | **Categories** | Workout type classifications | ["HIIT", "Cardio"] |
        | **Equipment** | Required/recommended gear | ["Dumbbells", "Mat"] |
        | **Muscle Groups** | Percentage distribution (sorted) | Chest: 35%, Arms: 25% |
        | **Media Assets** | Preview videos, images, audio | HLS streams, thumbnails |
        | **Trainer Info** | Coach details and organization | Name, bio, team |

        ---

        ### 🎯 Use Cases

        ✅ **Workout Preview** - Show details before starting  
        ✅ **Equipment Check** - Verify user has required gear  
        ✅ **Difficulty Assessment** - Match to user fitness level  
        ✅ **Content Discovery** - Browse workout library

        ---

        ### 🔄 Integration Flow

        1. **Browse Workouts**: `GET /v1/workouts` → Get workout list
        2. **Get Details**: `GET /v1/workouts/{id}` → **This endpoint** (full details)
        3. **Check Equipment**: Review equipment array for user compatibility
        4. **Start Session**: `POST /v1/workouts/{id}/sessions/start`
        5. **Get Playlist**: `GET /v1/workouts/{id}/playlist` → Detailed segments

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Name, description, equipment names, muscle group names

        ---

        ### 🔗 Related Endpoints

        - Workout List: `GET /v1/workouts` - Browse all workouts
        - Workout Playlist: `GET /v1/workouts/{id}/playlist` - Get detailed segments
        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin tracking
        - Submit Feedback: `POST /v1/workouts/{id}/feedback` - Rate workout
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout to retrieve.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Workout details retrieved successfully.
          schema:
            example:
              data:
                id: 12ab3efd45c67c1234566cd1
                name: Full Body HIIT Power
                description: A high-intensity interval training session targeting full body strength and cardiovascular fitness
                duration: 1800
                difficulty: intermediate
                visibility: public
                locked: false
                createdAt: '2023-10-26T10:00:00.000Z'
                updatedAt: '2023-10-27T11:30:00.000Z'
                trainer:
                  id: 64f1a2b3c4d5e6f7a8b9c0d4
                  name: Sarah Johnson
                categories:
                  - id: 615aa3f0dbe7140012c59e94
                    name: HIIT
                  - id: 615aa3ebdbe7140012c59e93
                    name: Cardio
                equipment:
                  - id: 60812dea606fc90011eb4405
                    name: Dumbbell
                    equipmentCategoryId: 67deb3696a5e49797c122f55
                  - id: 60812e08606fc90011eb4408
                    name: Mat
                    equipmentCategoryId: 67deb36a6a5e49797c122f56
                muscleGroupPercentages:
                  - muscleGroupId: 604b0129beaba770c284ff40
                    muscleGroupName: Arms
                    percentage: 25.5
                  - muscleGroupId: 604b0169076fe2727354d740
                    muscleGroupName: Chest
                    percentage: 20
                  - muscleGroupId: 604b0177076fe2727354d743
                    muscleGroupName: Legs
                    percentage: 30
                  - muscleGroupId: 604b0170076fe2727354d741
                    muscleGroupName: Core
                    percentage: 24.5
                preview:
                  url: https://stream.hyperhuman.cc/workout-preview.m3u8
                  poster: https://images.hyperhuman.cc/workout-poster.jpg
                  thumbnail: https://images.hyperhuman.cc/workout-thumb.jpg
                images:
                  thumbnail: https://images.hyperhuman.cc/workout-thumb.jpg
                  cover: https://images.hyperhuman.cc/workout-cover.jpg
                shareLink:
                  url: https://app.hyperhuman.cc/workouts/12ab3efd45c67c1234566cd1
                organization: null
                rating: 4.5
                mixBgMusic: true
                presentationStyle: full
                skipWorkoutPreview: false
                skipWorkoutCompletionScreen: false
                videoAudioMode: full
                allowAssessment: false
                assessmentType: null
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutResponse'
        '401':
          description: Authentication failed - API key is missing, invalid, or Bearer token is missing/invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkout() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/export/video/stream_url:
    get:
      operationId: WorkoutsApi_getExportVideoStream
      summary: Get complete workout video export URL
      description: |-

        ## Full Workout Video Export

        Returns a pre-signed S3 URL to a **complete, fully-rendered workout video** for the requested locale. This is typically a single file containing the entire workout from start to finish, including all exercises, rest periods, audio narration, graphics, and timing overlays.

        **Response shape:** HTTP **200** with **Content-Type: text/plain**. The body is a **single** URL string (not JSON). The URL is presigned and valid for **7 days**. The object at that URL matches whatever the export pipeline stored (commonly **MP4**; **HLS** or other packaging is possible in some cases—use the file extension and response headers when fetching the URL).

        ---

        ### 📋 Video Details

        **Format:** MP4 (H.264)  
        **Resolution:** 1080p (1920x1080)  
        **Frame Rate:** 30 fps  
        **Codec:** H.264 (High Profile)  
        **Audio:** AAC stereo, embedded in video  
        **File Size:** Typically 100-500 MB depending on workout length  
        **Expiration:** Pre-signed URL valid for 7 days  
        **Protocol:** HTTPS  
        **Content Type:** video/mp4

        ---

        ### 🎯 Use Cases

        This endpoint is ideal for:
        - **Simple video playback** - Direct download and play the complete workout
        - **Offline viewing** - Download the full video for offline use
        - **Social sharing** - Share the complete workout video
        - **Video archival** - Store the full workout as a single file
        - **Third-party players** - Use any standard MP4-compatible video player

        ---

        ### 🎬 Integration Examples

        **Basic HTML5 Video Player:**
        ```javascript
        // Fetch the video URL
        const videoUrl = await fetch(
          `/v1/workouts/${workoutId}/export/video/stream_url?locale=en-US`,
          { headers: { 'X-Api-Key': apiKey } }
        ).then(r => r.text());

        // Use standard HTML5 video player
        const video = document.createElement('video');
        video.src = videoUrl;
        video.controls = true;
        video.width = 1920;
        video.height = 1080;
        document.body.appendChild(video);
        ```

        **iOS/Swift AVPlayer:**
        ```swift
        let videoURL = URL(string: videoUrlString)!
        let player = AVPlayer(url: videoURL)
        let playerViewController = AVPlayerViewController()
        playerViewController.player = player
        present(playerViewController, animated: true) {
            player.play()
        }
        ```

        **Android/Kotlin ExoPlayer:**
        ```kotlin
        val player = ExoPlayer.Builder(context).build()
        playerView.player = player
        val mediaItem = MediaItem.fromUri(videoUrl)
        player.setMediaItem(mediaItem)
        player.prepare()
        player.play()
        ```

        **Download for Offline Use:**
        ```javascript
        async function downloadWorkoutVideo(workoutId, filename) {
          const videoUrl = await fetch(
            `/v1/workouts/${workoutId}/export/video/stream_url`,
            { headers: { 'X-Api-Key': apiKey } }
          ).then(r => r.text());
          
          const response = await fetch(videoUrl);
          const blob = await response.blob();
          const url = window.URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = url;
          a.download = filename || 'workout.mp4';
          a.click();
        }
        ```

        ---

        ### 🌍 Localization Support

        The video export includes localized content based on the `locale` parameter:
        - **Audio narration** - Voice instructions in the requested language
        - **Text overlays** - Exercise names, timers, and instructions in local language
        - **Exercise names** - Localized exercise titles

        **Supported locales:**
        en-US, en-GB, en-AU, fr-FR, de-DE, es-ES, it-IT, pt-PT, he-IL, ro-RO, cs-CZ, fi-FI, nl-NL

        **Locale fallback behavior:**
        1. If requested locale exists → return that version
        2. If requested locale not available but user's preferred locale exists → return preferred version
        3. Otherwise → return English (en-US) version
        4. If no export available → return 404

        ---

        ### ⚡ Video Generation Status

        Workout videos are **pre-generated asynchronously** after workout creation or modification. 

        **Possible scenarios:**
        - ✅ **Video ready** - Returns URL immediately (typical case)
        - ⏳ **Video processing** - Returns 404 if generation still in progress (usually 2-5 minutes)
        - ❌ **Generation failed** - Returns 404 if export job failed

        **Best practice:** Check `GET /v1/workouts/{id}` response for video availability before requesting stream URL.

        ---

        ### 💡 Best Practices

        ✅ **Cache the URL** - Save in memory/storage for up to 6 days  
        ✅ **Refresh before expiration** - Fetch new URL when approaching 7-day limit  
        ✅ **Handle 404 gracefully** - Video may still be processing  
        ✅ **Support offline download** - Allow users to download for offline viewing  
        ✅ **Show file size** - Inform users about download size (typically 100-500 MB)  
        ✅ **Implement retry logic** - Retry with exponential backoff if initial request fails  
        ✅ **Consider bandwidth** - These are large files; provide quality/size warnings on mobile

        ---

        ### 🔄 Workflow Comparison

        **Option A: Complete Video (This Endpoint)**
        ```
        GET /v1/workouts/{id}/export/video/stream_url
        → Single presigned URL to the full-workout video export
        → Simple playback, no segment control
        → Ideal for: Downloads, simple players, sharing
        ```

        **Option B: Segmented Playlist**
        ```
        GET /v1/workouts/{id}/playlist
        → Individual exercise videos + timing
        → Full control over each segment
        → Ideal for: Custom players, skip exercises, progress tracking
        ```

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### 🔗 Related Endpoints

        - **Workout Details:** `GET /v1/workouts/{id}` - Get workout metadata
        - **Workout Playlist:** `GET /v1/workouts/{id}/playlist` - Get segment-by-segment structure
        - **Audio Only:** `GET /v1/workouts/{id}/export/audio/stream_url` - Get audio-only version
        - **Start Session:** `POST /v1/workouts/{id}/sessions/start` - Track workout session
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier of the workout.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., de-DE, fr-FR, en-US). If specified and no export exists for this locale, returns 404. Falls back to user's preferred locale or en-US.
          example: en-US
          schema:
            type: string
      responses:
        '200':
          description: 'text/plain body: a single presigned HTTPS URL to the full video export (valid 7 days). Format of the linked asset matches the stored render (commonly MP4; see operation description).'
          content:
            application/json:
              schema:
                type: string
        '401':
          description: Authentication failed - API key is missing, invalid, or Bearer token is missing/invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Workout not found, video export not available for the requested locale, or video is still being generated (processing typically takes 2-5 minutes after workout creation).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/video/stream_url' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getExportVideoStream() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/video/stream_url', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/video/stream_url", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/export/audio/stream_url:
    get:
      operationId: WorkoutsApi_getExportAudioStream
      summary: Get audio-only workout export URL
      description: |-

        ## Audio-Only Workout Export

        Returns a pre-signed S3 URL to the **complete audio narrative** for the workout. This is ideal for audio-guided workout experiences where users prefer voice-only instruction without video.

        **Response shape:** HTTP **200** with **Content-Type: text/plain**. The body is a **single** URL string (not JSON), presigned and valid for **7 days**, pointing at the generated narrative audio object (commonly **M4A**).

        ---

        ### 📋 Audio Details

        **Format:** M4A (AAC)  
        **Quality:** 128 kbps stereo  
        **File Size:** Typically 5-20 MB depending on workout length  
        **Content:** Voice narration, exercise instructions, timing cues, background audio  
        **Expiration:** Pre-signed URL valid for 7 days  
        **Protocol:** HTTPS  
        **Content Type:** audio/mp4

        ---

        ### 🎧 Use Cases

        Perfect for:
        - **Audio-only workouts** - Voice-guided training without video overhead
        - **Background play** - Users can multitask while working out
        - **Low bandwidth** - Only 5-20 MB vs 100-500 MB for video
        - **Accessibility** - Screen-free workout experience for visually impaired users
        - **Outdoor activities** - Listen while running, cycling, or hiking
        - **Podcast-style workouts** - Portable fitness content
        - **Mobile data savings** - Significantly reduced data consumption

        ---

        ### 🎬 Integration Examples

        **Basic HTML5 Audio:**
        ```javascript
        // Fetch audio URL
        const audioUrl = await fetch(
          `/v1/workouts/${workoutId}/export/audio/stream_url?locale=en-US`,
          { headers: { 'X-Api-Key': apiKey } }
        ).then(r => r.text());

        // Simple audio player
        const audio = new Audio(audioUrl);
        audio.play();

        // Or with controls
        const player = document.createElement('audio');
        player.src = audioUrl;
        player.controls = true;
        document.body.appendChild(player);
        ```

        **Custom Audio Player with Progress Tracking:**
        ```javascript
        const audio = new Audio(audioUrl);

        // Track progress
        audio.addEventListener('timeupdate', () => {
          const progress = (audio.currentTime / audio.duration) * 100;
          console.log(`Workout progress: ${progress.toFixed(1)}%`);
        });

        // Handle completion
        audio.addEventListener('ended', () => {
          console.log('Workout completed!');
          // Submit workout session completion
        });

        // Play with controls
        audio.play();
        ```

        **iOS/Swift AVAudioPlayer:**
        ```swift
        let audioURL = URL(string: audioUrlString)!
        do {
            let audioData = try Data(contentsOf: audioURL)
            audioPlayer = try AVAudioPlayer(data: audioData)
            audioPlayer?.prepareToPlay()
            audioPlayer?.play()
        } catch {
            print("Error loading audio: \(error)")
        }
        ```

        **Android/Kotlin MediaPlayer:**
        ```kotlin
        val mediaPlayer = MediaPlayer().apply {
            setDataSource(audioUrl)
            prepareAsync()
            setOnPreparedListener { start() }
        }
        ```

        **Background Audio with Web Audio API:**
        ```javascript
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        const audioElement = new Audio(audioUrl);
        const track = audioContext.createMediaElementSource(audioElement);
        track.connect(audioContext.destination);

        // Enable background playback
        if ('mediaSession' in navigator) {
          navigator.mediaSession.metadata = new MediaMetadata({
            title: 'HIIT Workout',
            artist: 'Hyperhuman',
            album: 'Workout Audio',
          });
        }

        audioElement.play();
        ```

        ---

        ### 🌍 Localization Support

        Audio includes localized voice narration in the requested language:
        - **Voice instructions** - Exercise cues in native language
        - **Counting** - Rep counts and timers in local language
        - **Motivational cues** - Encouragement in native language

        **Supported locales:**
        en-US, en-GB, en-AU, fr-FR, de-DE, es-ES, it-IT, pt-PT, he-IL, ro-RO, cs-CZ, fi-FI, nl-NL

        **Locale fallback behavior:**
        1. If requested locale exists → return that version
        2. If requested locale not available but user's preferred locale exists → return preferred version
        3. Otherwise → return English (en-US) version
        4. If no audio export available → return 404

        ---

        ### ⚡ Audio Generation Status

        Audio files are **pre-generated asynchronously** after workout creation.

        **Possible scenarios:**
        - ✅ **Audio ready** - Returns URL immediately (typical case)
        - ⏳ **Audio processing** - Returns 404 if generation in progress (usually 1-3 minutes)
        - ❌ **Generation failed** - Returns 404 if export job failed

        ---

        ### 💡 Best Practices

        ✅ **Cache the URL** - Save in memory/storage for up to 6 days  
        ✅ **Refresh before expiration** - Fetch new URL after 6 days  
        ✅ **Enable background playback** - Allow app to continue playing when screen is off  
        ✅ **Handle network errors** - Implement retry logic with exponential backoff  
        ✅ **Show progress** - Display current time and duration  
        ✅ **Support playback controls** - Play, pause, seek, speed adjustment  
        ✅ **Lock screen controls** - Integrate with OS media controls  
        ✅ **Download option** - Allow offline download for gym use with no connectivity

        ---

        ### 🔄 Content Comparison

        **Audio Export (This Endpoint):**
        - Complete audio narrative in one file
        - Voice instructions + timing cues + background audio
        - 5-20 MB file size
        - Simple streaming/download

        **Playlist Audio:**
        - Individual audio clips per segment
        - Requires assembly and synchronization
        - More control but more complexity

        ---

        ### 🔗 Related Endpoints

        - **Workout Details:** `GET /v1/workouts/{id}` - Get workout metadata
        - **Workout Playlist:** `GET /v1/workouts/{id}/playlist` - Get segment-by-segment structure
        - **Video Export:** `GET /v1/workouts/{id}/export/video/stream_url` - Get full video version
        - **Start Session:** `POST /v1/workouts/{id}/sessions/start` - Track workout session
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier of the workout.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: Preferred language locale for audio narration (e.g., de-DE, fr-FR, en-US). If specified and no export exists for this locale, returns 404. Falls back to user's preferred locale or en-US.
          example: en-US
          schema:
            type: string
      responses:
        '200':
          description: 'text/plain body: a single presigned HTTPS URL to the full narrative audio export (valid 7 days; commonly M4A/AAC).'
          content:
            application/json:
              schema:
                type: string
        '401':
          description: Authentication failed - API key is missing, invalid, or Bearer token is missing/invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Workout not found, audio export not available for the requested locale, or audio is still being generated (processing typically takes 1-3 minutes after workout creation).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/audio/stream_url' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getExportAudioStream() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/audio/stream_url', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/export/audio/stream_url", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/exercises/metadata:
    get:
      operationId: WorkoutsApi_getExercisesMetadata
      summary: Get available muscle groups and exercise collections
      description: |-

        Retrieves all muscle groups and exercise collections with counts.

        **Use this endpoint to populate:**
        - `muscleGroupIds` for targeted muscle group focus in workout generation
        - `excludeExerciseCollections` to avoid specific trainer styles or backgrounds

        **Response includes:**
        - `muscleGroups`: Array of {id, name} for each muscle group (Arms, Chest, Legs, Core, etc.)
        - `collections`: Array of {name, count} for exercise collections (Free/Premium categories)

        **Example Muscle Groups:**
        - Arms (604b0129beaba770c284ff40)
        - Chest (604b0169076fe2727354d740)
        - Back (604b016c076fe2727354d740)
        - Core (604b0170076fe2727354d741)
        - Legs (604b0177076fe2727354d743)
        - Shoulders (604b0165076fe2727354d73e)
        - Glutes (604b0173076fe2727354d742)

        **Example Collections:**
        - "Premium - Neutral" (808 exercises) - Consistent neutral background
        - "Premium - Industrial" (200 exercises) - Industrial gym setting
        - "Premium - White" (151 exercises) - Clean white background
        - "Free - Eclectic Home" (239 exercises) - Varied home settings
        - "Premium - Advanced Gym" (120 exercises) - Professional gym equipment

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Muscle group names (collections not localized)

        ---

        **Related Metadata Endpoints:**
        - `GET /v1/workouts/exercises/metadata` - Muscle groups & collections
        - `GET /v1/workouts/metadata` - Categories & difficulties
        - `GET /v1/workouts/equipment/metadata` - Equipment items & categories

        **Related Endpoints:**
        - Generate: `POST /v1/orgs/{orgId}/workouts/generate`
        - List: `GET /v1/orgs/{orgId}/workouts`
            
      parameters:
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved list of muscle groups and exercise collections.
          content:
            application/json:
              schema:
                type: object
                properties:
                  muscleGroups:
                    type: array
                    description: List of all available muscle groups.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Muscle group ID
                          example: 604b0129beaba770c284ff40
                        name:
                          type: string
                          description: Muscle group display name
                          example: Arms
                      required:
                        - id
                        - name
                  collections:
                    type: array
                    description: List of all available exercise collections with exercise counts.
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                          description: Collection name
                          example: Premium - Neutral
                        count:
                          type: number
                          description: Number of exercises in this collection
                          example: 808
                      required:
                        - name
                        - count
                example:
                  muscleGroups:
                    - id: 604b0129beaba770c284ff40
                      name: Arms
                    - id: 604b0169076fe2727354d740
                      name: Chest
                    - id: 604b0177076fe2727354d743
                      name: Legs
                  collections:
                    - name: Premium - Neutral
                      count: 808
                    - name: Premium - Industrial
                      count: 200
                    - name: Free - Eclectic Home
                      count: 239
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/exercises/metadata' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getExercisesMetadata() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/exercises/metadata', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/exercises/metadata", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/workouts:
    get:
      operationId: OrganizationWorkoutsApi_getOrganizationWorkouts
      summary: List organization-specific workouts
      description: |-

        ## Organization Workout Library

        Retrieves paginated list of workouts specific to your organization. Includes filtering, sorting, and search capabilities.

        ---

        ### 🎯 Organization Context

        | Aspect | Organization Workouts | Public Workouts |
        |--------|----------------------|-----------------|
        | **Content** | Your branded workouts | Global library |
        | **Customization** | Team-specific exercises | Generic fitness content |
        | **Branding** | Your trainers/style | Mixed sources |
        | **Access Control** | Organization members | Public access |

        ---

        ### 📋 Use Cases

        ✅ **White-label Apps** - Show only your organization's content  
        ✅ **Corporate Wellness** - Company-specific fitness programs  
        ✅ **Trainer Platforms** - Personal trainer's workout library  
        ✅ **Gym Management** - Facility-specific workouts

        ---

        ### 🔍 Filtering & Pagination

        **Visibility Filtering:**
        - `private` - Organization-only content (requires ownership)
        - `public` - Publicly accessible workouts
        - `all` - Both private and public (default)

        **Additional Filters:**
        - `difficulty` - Filter by beginner, intermediate, or advanced
        - `categoryIds` - Filter by category IDs (comma-separated)
        - `duration` - Filter by duration range in format "min-max" (e.g., "15-45")
        - `q` - Search by workout name or description

        **Pagination:**
        - `offset` - Number of items to skip (default: 0)
        - `limit` - Items per page (default: 20, max: 50)
        - Prefer following `links.next` from the response over computing offsets manually.

        ---

        ### 💡 Best Practices

        ✅ **Cache responses** - Workouts change infrequently  
        ✅ **Filter by visibility** - Use `public` for end-user apps, `all` for management  
        ✅ **Implement search** - Use `q` parameter for name/description filtering  
        ✅ **Handle empty results** - Graceful fallback to public workouts

        ---

        ### 🔗 Related Endpoints

        - Generate Workout: `POST /v1/orgs/{orgId}/workouts/generate` - Create new workout
        - Recommend Workout: `POST /v1/orgs/{orgId}/workouts/recommend` - Get suggestions
        - Workout Details: `GET /v1/workouts/{id}` - Get individual workout
        - Workout Metadata: `GET /v1/workouts/metadata` - Get categories and difficulties
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Maximum number of items to return per page.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: q
          required: false
          in: query
          description: Search text
          schema:
            type: string
        - name: sort
          required: false
          in: query
          description: 'Fields to sort. Prefix them with - (descending) or + (ascending): +someField,-otherField'
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US, fr-FR). Localizes text and locale-aware media when this operation supports it. Falls back to English when unsupported.
          example: en-US
          schema:
            type: string
        - name: visibility
          required: false
          in: query
          description: Filter workouts by their visibility status.
          example: public
          schema:
            enum:
              - private
              - public
              - all
            type: string
        - name: difficulty
          required: false
          in: query
          description: Filter workouts by difficulty level.
          example: intermediate
          schema:
            enum:
              - beginner
              - intermediate
              - advanced
            type: string
        - name: categoryIds
          required: false
          in: query
          description: Filter workouts by one or more workout category IDs (comma-separated 24-character hex DB ids). Optional tokens prefixed with `custom:` are filtered in memory (e.g. duration-based buckets).
          example: 615aa3f0dbe7140012c59e94,custom:duration_short
          schema:
            type: string
        - name: duration
          required: false
          in: query
          description: Filter workouts by duration range in minutes. Use format "min-max" (e.g., "10-30").
          example: 15-45
          schema:
            pattern: ^\d+-\d+$
            type: string
        - name: allowAssessment
          required: false
          in: query
          description: Filter workouts by assessment support
          schema:
            type: boolean
      responses:
        '200':
          description: Successfully retrieved paginated list of workouts for the organization.
          schema:
            example:
              data:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  name: Morning Power HIIT
                  duration: 1800
                  difficulty: intermediate
                  categories:
                    - id: 615aa3f0dbe7140012c59e94
                      name: HIIT
                  trainer:
                    id: trainer123
                    name: Sarah Johnson
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/...
                  previewVideoUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/...
                  createdAt: '2025-09-15T10:30:00Z'
              links:
                next: https://content.api.hyperhuman.cc/v1/orgs/63415bf67a9c7000126616c1/workouts?offset=20&limit=20
                total: 45
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutListResponse'
        '400':
          description: Invalid pagination or filter parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationWorkouts() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/workouts/recommend:
    post:
      operationId: OrganizationWorkoutRecommendation_getWorkoutRecommendations
      summary: Get workout recommendations from existing library
      description: |-

        ## Smart Matching to Existing Content

        Returns ranked workout suggestions from your organization's library based on user profile analysis.

        ---

        ### 🎯 Recommendations vs. Generation

        | Aspect | **Recommendations** (This Endpoint) | **Generation** (`/generate`) |
        |--------|-------------------------------------|-------------------------------|
        | **Speed** | Instant (<100ms) | 2-5 seconds |
        | **Content** | Existing library workouts | New, unique workouts |
        | **Customization** | Matches to closest fit | Exact specifications |
        | **Use Case** | Browse & discover | On-demand custom |
        | **Requires** | Pre-built workout library | Just metadata IDs |

        ---

        ### 📋 When to Use Recommendations

        ✅ **Quick browsing experience** - Show options immediately  
        ✅ **Large workout library** - You have 20+ workouts  
        ✅ **Consistency** - Same workout for multiple users  
        ✅ **Analytics tracking** - See which workouts are popular

        ---

        ### 📋 When to Use Generation

        ✅ **Unique per user** - Every workout is personalized  
        ✅ **Specific requirements** - Exact duration, muscle groups  
        ✅ **No library** - You don't have pre-built workouts  
        ✅ **Dynamic content** - New workouts every session

        ---

        ### 🔍 How Matching Works

        1. **Analyzes** user profile (age, fitness level, goals, equipment)
        2. **Scores** each workout in your library (0.0 - 1.0)
        3. **Ranks** by match score
        4. **Returns** top 12 with match reasons

        **Match Factors:**
        - Fitness level alignment (35% weight)
        - Equipment compatibility (25% weight)
        - Goal alignment (20% weight)
        - Age appropriateness (10% weight)
        - Duration preference (10% weight)

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### 🔗 Related Endpoints

        - Generate Workout: `POST /v1/orgs/{orgId}/workouts/generate`
        - List Workouts: `GET /v1/orgs/{orgId}/workouts`
        - Workout Metadata: `GET /v1/workouts/metadata`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: Organization/Team unique identifier
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkoutRecommendationRequestDto'
      responses:
        '200':
          description: Ranked list of recommended workouts with match scores and reasons
          schema:
            example:
              workouts:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  name: Full Body HIIT Power
                  description: High-intensity interval training for full body conditioning
                  duration: 1800
                  difficulty: intermediate
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/workouts/64f1a2b3c4d5e6f7a8b9c0d1/thumbnail.jpg
                  recommendation: Matches your intermediate fitness level and preferred equipment
                  categories:
                    - id: 615aa3f0dbe7140012c59e94
                      name: HIIT
                  preview:
                    url: https://example.com/preview.m3u8
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/workouts/64f1a2b3c4d5e6f7a8b9c0d1/thumbnail.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/workouts/64f1a2b3c4d5e6f7a8b9c0d1/thumbnail.jpg
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  name: Upper Body Strength
                  description: Focused strength training for chest, back, and arms
                  duration: 2400
                  difficulty: intermediate
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/workouts/64f1a2b3c4d5e6f7a8b9c0d2/thumbnail.jpg
                  recommendation: Aligns with your strength goals and available equipment
                  categories:
                    - id: 615aa3dadbe7140012c59e90
                      name: Strength
                - id: 64f1a2b3c4d5e6f7a8b9c0d3
                  name: Cardio Blast
                  description: Fast-paced cardio workout for endurance
                  duration: 1500
                  difficulty: beginner
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/workouts/64f1a2b3c4d5e6f7a8b9c0d3/thumbnail.jpg
                  recommendation: Suitable for your fitness level with bodyweight exercises
                  categories:
                    - id: 615aa3ebdbe7140012c59e93
                      name: Cardio
              reasoning: Workouts recommended based on your profile and preferences. Top matches align with your intermediate fitness level and available equipment. The recommendations prioritize workouts that match your training goals while considering your current fitness capabilities.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutRecommendationResponseDto'
        '401':
          description: Unauthorized - Invalid API key
        '404':
          description: Organization/Team not found
      tags:
        - ai-recommendation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/recommend' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutRecommendations() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/recommend', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/recommend",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/workouts/generate:
    post:
      operationId: OrganizationWorkoutGeneration_generateWorkout
      summary: Generate personalized on-the-fly workouts based on user profile details, duration preferences, and exercise sources.
      description: |

        ## Generate Personalized Workouts

        Create AI-powered workout plans tailored to user profiles, equipment, fitness levels, and duration preferences.

        ---

        ### ⚠️ Storage Note

        Generated workouts are returned directly (not saved to organization library).  
        If you need to reference the workout later, store the returned workout structure in your database.

        ---

        ### 🎯 What's Generated

        - **Duration**: 10-90 minute workout with automatic warm-up/cooldown
        - **Personalized**: Matched to category, difficulty, age, equipment, muscle groups
        - **Complete**: Ready-to-use workout structure with exercises, sets, reps, timing
        - **Safe**: Every workout includes 3-5 warm-up and cooldown exercises

        **User Profile:**
        - Age → Appropriate exercise intensity (16-24 Young, 25-34 Young Adult, etc.)
        - Fitness level → Uses first level if multiple provided
        - Equipment → Guides exercise selection (bodyweight always included)
        - Muscle groups → Prioritizes specified groups (optional guidance)

        **Duration Logic:**
        - Both min/max provided → AI selects optimal in range
        - Only one value → Uses as target
        - Smart adjustment to meet constraints

        ---

        ### 📋 Quick Start

        1. **Fetch Metadata**: 
           - `GET /v1/workouts/metadata` → Category IDs (required)
           - `GET /v1/workouts/equipment/metadata` → Equipment category IDs (optional)
           - `GET /v1/workouts/exercises/metadata` → Muscle group IDs (advanced)

        2. **Build Request** with metadata IDs

        3. **POST to this endpoint**

        ---

        ### 📦 Exercise Sources

        | Source | Description | Use Case |
        |--------|-------------|----------|
        | `premium_stock` | High-quality professional content with consistent trainers/backgrounds | **Production (Recommended)** |
        | `free_stock` | Varied quality with mixed trainers/backgrounds | Development/testing only |
        | `team_exercises` | Your organization's custom content | Maximum brand consistency |

        **Default**: If omitted, uses both free and premium stock (not recommended for production)

        ---

        ### 💡 Best Practices

        ✅ Use `premium_stock` for consistent quality  
        ✅ Use `team_exercises` for brand consistency  
        ✅ Specify both min and max duration for predictable results  
        ❌ Avoid mixing `free_stock` with `premium_stock` (visual inconsistency)

        **Advanced Options:**

        - `muscleGroupIds`: Prioritize specific muscle groups (guidance, not strict filter)
        - `excludeExerciseCollections`: Exclude trainer styles (e.g., ["Free - Outdoor"])
        - `userRequirements`: High-level context and guidelines for customer-specific training definitions (e.g., "intermediate osteoporosis strength training", "CRITICAL: USE up to 3 unique exercises"). Overrides default AI behavior. Max 2000 characters.

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### 🔗 Related Endpoints

        - **Metadata**: `GET /v1/workouts/metadata` - Get category IDs
        - **Metadata**: `GET /v1/workouts/equipment/metadata` - Get equipment IDs
        - **Metadata**: `GET /v1/workouts/exercises/metadata` - Get muscle group IDs
        - **List**: `GET /v1/orgs/{orgId}/workouts` - Browse organization workouts
        - **Recommend**: `POST /v1/orgs/{orgId}/workouts/recommend` - Smart suggestions
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
      requestBody:
        required: true
        description: Workout generation request with user profile and preferences.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkoutGenerationRequestDto'
            examples:
              beginner-hiit-20min:
                summary: Beginner HIIT - 20 Minutes
                description: Full-body HIIT workout for beginners with minimal equipment
                value:
                  endUserProfileDetails:
                    age: 28
                    gender: female
                    fitnessLevels:
                      - beginner
                    trainingDaysPerWeek: 3
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                  exerciseSources:
                    - premium_stock
                  durationOptions:
                    minMinutes: 15
                    maxMinutes: 20
                  categoryId: 615aa3f0dbe7140012c59e94
              advanced-strength-upper-body:
                summary: Advanced Strength - Upper Body Focus
                description: Advanced strength training targeting chest, arms, and shoulders with free weights
                value:
                  endUserProfileDetails:
                    age: 35
                    gender: male
                    fitnessLevels:
                      - advanced
                    trainingDaysPerWeek: 5
                    preferredEquipmentCategoryIds:
                      - 67deb3696a5e49797c122f55
                  exerciseSources:
                    - premium_stock
                  durationOptions:
                    minMinutes: 30
                    maxMinutes: 45
                  categoryId: 615aa3dadbe7140012c59e90
                  muscleGroupIds:
                    - 604b0169076fe2727354d740
                    - 604b0129beaba770c284ff40
                    - 604b0165076fe2727354d73e
                  excludeExerciseCollections:
                    - Free - Outdoor
              intermediate-mobility-recovery:
                summary: Intermediate Mobility & Recovery
                description: Low-intensity mobility workout for active recovery
                value:
                  endUserProfileDetails:
                    age: 42
                    gender: female
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 4
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                  exerciseSources:
                    - premium_stock
                  durationOptions:
                    minMinutes: 10
                    maxMinutes: 15
                  categoryId: 615aa3e5dbe7140012c59e92
                  userRequirements: Focus on low-impact movements. Emphasize flexibility and joint mobility. Avoid high-intensity exercises.
              team-branded-workout:
                summary: Custom Team Exercises Only
                description: Use your organization's exercises for complete brand alignment
                value:
                  endUserProfileDetails:
                    age: 30
                    gender: male
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 3
                    preferredEquipmentCategoryIds:
                      - 67deb3696a5e49797c122f55
                  exerciseSources:
                    - team_exercises
                  durationOptions:
                    minMinutes: 20
                    maxMinutes: 30
                  categoryId: 615aa3f0dbe7140012c59e94
              cardio-legs-focus:
                summary: Cardio with Legs Focus
                description: Cardio workout emphasizing leg muscles
                value:
                  endUserProfileDetails:
                    age: 26
                    gender: female
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 4
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                  exerciseSources:
                    - premium_stock
                  durationOptions:
                    minMinutes: 25
                    maxMinutes: 35
                  categoryId: 615aa3ebdbe7140012c59e93
                  muscleGroupIds:
                    - 604b0177076fe2727354d743
                    - 604b0173076fe2727354d742
                  excludeExerciseCollections:
                    - Premium - Industrial
              complete-all-parameters:
                summary: Complete Example - All Parameters
                description: Real-world example with ALL available parameters filled out to demonstrate the full API capability. This shows every possible field that can be included in a workout generation request.
                value:
                  endUserProfileDetails:
                    age: 32
                    gender: male
                    fitnessLevels:
                      - intermediate
                      - advanced
                    goalIds:
                      - 63c92926f920a9005c4e619c
                      - 63c92926f920a9005c4e619d
                    trainingDaysPerWeek: 5
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                      - 67deb3696a5e49797c122f55
                    endUserId: 64e3bca9d1b7e600141a9712
                  exerciseSources:
                    - premium_stock
                    - team_exercises
                  durationOptions:
                    minMinutes: 30
                    maxMinutes: 45
                  categoryId: 615aa3dadbe7140012c59e90
                  muscleGroupIds:
                    - 604b0169076fe2727354d740
                    - 604b0129beaba770c284ff40
                    - 604b0165076fe2727354d73e
                    - 604b016c076fe2727354d740
                    - 604b0170076fe2727354d741
                  excludeExerciseCollections:
                    - Free - Eclectic Home
                    - Free - Outdoor
                    - Premium - Industrial
                  userRequirements: 'Intermediate strength / stimulus, one-sided exercises, rep schemes. Focus on controlled movements suitable for osteoporosis patients. CRITICAL: USE up to 3 unique exercises in the whole workout.'
      responses:
        '200':
          description: Successfully generated workout plan with automatic warm-up and cooldown sections. AI may adjust final difficulty based on exercise availability and safety considerations.
          schema:
            example:
              name: Full Body HIIT Power
              totalDurationSeconds: 1200
              difficulty: beginner
              categoryId: 615aa3f0dbe7140012c59e94
              instances:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  kind: singleExercise
                  durationSeconds: 30
                  skipIntro: false
                  pace: normal
                  exercise:
                    id: 60812dea606fc90011eb4405
                    name: Jumping Jacks
                    description: Full body cardio warm-up exercise
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/jumping-jacks.jpg
                    videoUri: https://cdn.example.com/exercises/videos/jumping-jacks/master.m3u8
                    estimatedRepDuration: 1500
                    muscleGroups:
                      - Full Body
                      - Cardio
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - warmup
                      - cardio
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  kind: rest
                  durationSeconds: 15
                - id: 64f1a2b3c4d5e6f7a8b9c0d3
                  kind: singleExercise
                  reps: 12
                  skipIntro: true
                  weightLevel: medium
                  exercise:
                    id: 60812dea606fc90011eb4406
                    name: Push-ups
                    description: Upper body strength exercise
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/push-ups.jpg
                    videoUri: https://cdn.example.com/exercises/videos/push-ups/master.m3u8
                    estimatedRepDuration: 2000
                    muscleGroups:
                      - Chest
                      - Arms
                      - Core
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - strength
                    showcasedReps: 12
                - id: 64f1a2b3c4d5e6f7a8b9c0d4
                  kind: rest
                  durationSeconds: 30
                - id: 64f1a2b3c4d5e6f7a8b9c0d5
                  kind: singleExercise
                  durationSeconds: 40
                  skipIntro: false
                  pace: fast
                  exercise:
                    id: 60812dea606fc90011eb4407
                    name: High Knees
                    description: Cardio exercise for legs and core
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/high-knees.jpg
                    videoUri: https://cdn.example.com/exercises/videos/high-knees/master.m3u8
                    estimatedRepDuration: 1000
                    muscleGroups:
                      - Legs
                      - Core
                      - Cardio
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - cardio
                    executionSide: both
                - id: 64f1a2b3c4d5e6f7a8b9c0d6
                  kind: rest
                  durationSeconds: 20
                - id: 64f1a2b3c4d5e6f7a8b9c0d7
                  kind: singleExercise
                  reps: 15
                  skipIntro: false
                  weightLevel: light
                  exercise:
                    id: 60812dea606fc90011eb4408
                    name: Bodyweight Squats
                    description: Lower body strength exercise
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/squats.jpg
                    videoUri: https://cdn.example.com/exercises/videos/squats/master.m3u8
                    estimatedRepDuration: 2500
                    muscleGroups:
                      - Legs
                      - Glutes
                      - Core
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - strength
                    showcasedReps: 15
                - id: 64f1a2b3c4d5e6f7a8b9c0d8
                  kind: rest
                  durationSeconds: 15
                - id: 64f1a2b3c4d5e6f7a8b9c0d9
                  kind: singleExercise
                  durationSeconds: 30
                  skipIntro: false
                  pace: slow
                  exercise:
                    id: 60812dea606fc90011eb4409
                    name: Arm Circles
                    description: Cooldown and mobility exercise
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/arm-circles.jpg
                    videoUri: https://cdn.example.com/exercises/videos/arm-circles/master.m3u8
                    estimatedRepDuration: 1500
                    muscleGroups:
                      - Shoulders
                      - Arms
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - cooldown
                      - mobility
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutGenerationResponseDto'
        '400':
          description: Bad Request - Invalid input parameters.
          schema:
            example:
              error:
                message: Invalid categoryId provided
                statusCode: 400
                errorCode: INVALID_CATEGORY_ID
                details: The categoryId '615aa3f0dbe7140012c59e99' does not exist. Please use GET /v1/workouts/metadata to fetch valid category IDs.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized - Invalid API key.
          schema:
            example:
              error:
                message: Invalid API key
                statusCode: 401
                errorCode: UNAUTHORIZED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden - API key required or insufficient permissions.
          schema:
            example:
              error:
                message: API key required
                statusCode: 403
                errorCode: FORBIDDEN
                details: This endpoint requires a valid API key. Please include the X-Api-Key header with your request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found - Organization or other resources not found.
          schema:
            example:
              error:
                message: Organization not found
                statusCode: 404
                errorCode: ORGANIZATION_NOT_FOUND
                details: The organization with ID '67e2e9d0e23f010013e19dec' does not exist or your API key does not have access to it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal Server Error - Failed to generate workout.
          schema:
            example:
              error:
                message: Failed to generate workout plan due to an internal issue.
                statusCode: 500
                errorCode: INTERNAL_SERVER_ERROR
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - ai-generation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/generate' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function generateWorkout() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/generate', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/generate",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/workouts/{workoutId}/adapt:
    post:
      operationId: OrganizationWorkoutAdaptation_adaptWorkout
      summary: Adapt an existing team workout based on user profile and data
      description: |-

        ## Workout Adaptation

        Personalizes an existing team workout by adjusting intensity, duration, and exercises based on:
        - User profile (age, fitness level, goals, equipment)
        - Last 60 days of wearable health data (body/sleep/physical scores)
        - Workout feedback and session history
        - User-provided guidance and constraints

        ---

        ### Key Differences from Generation

        | Aspect | Adaptation | Generation |
        |--------|------------|------------|
        | Source | Existing workout | New from scratch |
        | Goals | Preserved from original | User-specified |
        | Structure | Modified original | AI-created |
        | Use case | Personalize team content | On-demand custom |

        ---

        ### What Gets Adapted

        - **Intensity**: Reps, duration, rest periods, pace, weight level, RPE
        - **Duration**: Total workout time adjusted for user
        - **Exercises**: Substitutions only when needed (safety, equipment)
        - **NOT Changed**: Workout goals, overall structure intent

        ---

        ### Adaptation Factors

        Based on user data, the AI considers:
        - **Low sleep scores**: Reduces intensity, adds longer rest
        - **Declining physical scores**: Lowers reps/duration
        - **High difficulty feedback**: Decreases difficulty progressively
        - **Low completion rate**: Shortens workout, adds rest
        - **User injury mention**: Substitutes risky exercises
        - **Equipment constraints**: Replaces with available alternatives

        ---

        ### Response Format

        Returns same structure as AI workout generation for seamless integration.

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - Generate Workout: `POST /v1/orgs/{orgId}/workouts/generate`
        - Recommend Workout: `POST /v1/orgs/{orgId}/workouts/recommend`
        - List Workouts: `GET /v1/orgs/{orgId}/workouts`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: Organization/Team ID
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
        - name: workoutId
          required: true
          in: path
          description: Workout ID to adapt
          example: 67e2e9d0e23f010013e19def
          schema:
            type: string
      requestBody:
        required: true
        description: Workout adaptation request with user profile and preferences
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkoutAdaptationRequestDto'
            examples:
              basic-adaptation:
                summary: Basic Adaptation - Intermediate User
                description: Adapt a workout for an intermediate fitness level user
                value:
                  endUserProfileDetails:
                    age: 32
                    gender: female
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 4
                  exerciseSources:
                    - premium_stock
                    - team_exercises
              injury-adaptation:
                summary: Adaptation with Injury Guidance
                description: Adapt a workout considering user injury
                value:
                  endUserProfileId: 64e3bca9d1b7e600141a9712
                  endUserProfileDetails:
                    age: 45
                    gender: male
                    fitnessLevels:
                      - beginner
                    trainingDaysPerWeek: 3
                  exerciseSources:
                    - premium_stock
                  userGuidance: I have a slight knee injury. Please avoid high-impact exercises like jumping and running. Prefer low-impact alternatives.
              full-personalization:
                summary: Full Personalization with User Data
                description: Adapt using 60-day wearable data and full user profile
                value:
                  endUserProfileId: 64e3bca9d1b7e600141a9712
                  endUserProfileDetails:
                    age: 28
                    gender: female
                    fitnessLevels:
                      - advanced
                    goalIds:
                      - 63c92926f920a9005c4e619c
                    trainingDaysPerWeek: 5
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                      - 67deb3696a5e49797c122f55
                  exerciseSources:
                    - premium_stock
                    - team_exercises
                  userGuidance: Training for a 10K run in 2 months. Focus on building endurance. Limited time today, prefer shorter workout.
      responses:
        '200':
          description: Adapted workout with personalized adjustments
          schema:
            example:
              name: 'Adapted: Full Body HIIT Power'
              totalDurationSeconds: 1050
              difficulty: intermediate
              categoryId: 615aa3f0dbe7140012c59e94
              adaptationReasoning: Reduced workout duration from 20 to 17.5 minutes to accommodate your current fitness level. Adjusted rest periods to 20 seconds (from 15) to allow better recovery. Modified exercise intensity by reducing reps for high-impact movements to protect your knee. Substituted jumping exercises with low-impact alternatives.
              instances:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  kind: singleExercise
                  durationSeconds: 30
                  skipIntro: false
                  pace: normal
                  exercise:
                    id: 60812dea606fc90011eb4405
                    name: Jumping Jacks
                    description: Full body cardio warm-up exercise
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/jumping-jacks.jpg
                    videoUri: https://cdn.example.com/exercises/videos/jumping-jacks/master.m3u8
                    estimatedRepDuration: 1500
                    muscleGroups:
                      - Full Body
                      - Cardio
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: beginner
                    categories:
                      - warmup
                      - cardio
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  kind: rest
                  durationSeconds: 20
                - id: 64f1a2b3c4d5e6f7a8b9c0d3
                  kind: singleExercise
                  reps: 10
                  skipIntro: true
                  weightLevel: medium
                  rpe: 7
                  exercise:
                    id: 60812dea606fc90011eb4406
                    name: Modified Push-ups
                    description: Upper body strength exercise adapted for lower intensity
                    thumbnailUrl: https://cdn.example.com/exercises/thumbnails/push-ups.jpg
                    videoUri: https://cdn.example.com/exercises/videos/push-ups/master.m3u8
                    estimatedRepDuration: 2000
                    muscleGroups:
                      - Chest
                      - Arms
                    equipment:
                      - Bodyweight
                    collectionName: Premium - Neutral
                    coach: female
                    skillLevel: intermediate
                    categories:
                      - strength
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutAdaptationResponseDto'
        '400':
          description: Invalid request or workout not eligible for adaptation (only team workouts can be adapted)
        '401':
          description: Unauthorized - Invalid API key
        '404':
          description: Workout or organization not found
      tags:
        - ai-adaptation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/<WORKOUT_ID>/adapt' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function adaptWorkout() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/<WORKOUT_ID>/adapt', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/workouts/<WORKOUT_ID>/adapt",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot:
    get:
      operationId: OrganizationContentAutopilotApi_listTasks
      summary: List content autopilot tasks
      description: |-

        ## Content Autopilot Tasks

        Retrieves a paginated list of content autopilot tasks for your organization. Autopilot tasks automate the creation, adaptation, and publishing of workouts and programs on a configurable schedule.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Use Cases

        - **Dashboard views** - List all scheduled content automation tasks
        - **Status monitoring** - Filter by active/draft to see running vs paused tasks
        - **Content type filtering** - Show only workout or program automation tasks
        - **Audit and review** - Browse task configurations for the organization

        ---

        ### Filtering and Pagination

        **Filters:**
        - `status` - active, draft
        - `scope` - ai_generate, create_similar, publish_existing
        - `contentType` - workout, program

        **Sort:** `sortBy` (updatedAt, createdAt) + `sortOrder` (ascend, descend)

        **Pagination:**
        - `limit` - Items per page (default: 20, max: 50)
        - `offset` - Pagination offset (default: 0)

        ---

        ### Related Endpoints

        - Get Task: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}`
        - Create Task: `POST /v1/orgs/{orgId}/content-autopilot`
        - Task Events: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}/events`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Items per page. Defaults to 20, max 50.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: status
          required: false
          in: query
          description: Filter by task status
          schema:
            enum:
              - active
              - draft
            type: string
        - name: scope
          required: false
          in: query
          description: Filter by task scope
          schema:
            enum:
              - ai_generate
              - create_similar
              - publish_existing
            type: string
        - name: contentType
          required: false
          in: query
          description: Filter by content type
          schema:
            enum:
              - workout
              - program
            type: string
        - name: sortBy
          required: false
          in: query
          description: Sort by field
          schema:
            enum:
              - updatedAt
              - createdAt
            type: string
        - name: sortOrder
          required: false
          in: query
          description: Sort order
          schema:
            enum:
              - ascend
              - descend
            type: string
        - name: offset
          required: false
          in: query
          description: Pagination offset. Defaults to 0.
          example: 0
          schema:
            type: number
      responses:
        '200':
          description: Successfully retrieved paginated list of autopilot tasks.
          content:
            application/json:
              examples:
                default:
                  summary: List of autopilot tasks
                  value:
                    data:
                      - id: 64f1a2b3c4d5e6f7a8b9c0d1
                        organizationId: 63415bf67a9c7000126616c1
                        ownerId: 507f1f77bcf86cd799439011
                        name: Daily HIIT Generator
                        status: active
                        scope: ai_generate
                        contentType: workout
                        difficultyOptions:
                          - beginner
                          - intermediate
                        includeFreeStock: true
                        includePremiumStock: false
                        includeTeamContent: false
                        repeatMode: daily
                        nextRunAt: '2026-04-06T10:00:00.000Z'
                        createdAt: '2026-04-01T08:00:00.000Z'
                        updatedAt: '2026-04-05T14:00:00.000Z'
                    links:
                      next: null
                      total: 1
                    explanation: Showing 1 autopilot task for your organization.
        '400':
          description: Invalid filter or pagination parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function listTasks() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot", headers=headers)
            response.raise_for_status()
            print(response.json())
    post:
      operationId: OrganizationContentAutopilotApi_createTask
      summary: Create content autopilot task
      description: |-

        ## Create Autopilot Task

        Creates a new content autopilot task in `draft` status. Use the activate endpoint to start the scheduling.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Task Scopes

        | Scope | Description | Required Fields |
        |-------|-------------|-----------------|
        | `ai_generate` | Generate new content using AI | categoryIds/goalIds, difficultyOptions |
        | `create_similar` | Adapt an existing workout/program | `sourceContentId` |
        | `publish_existing` | Flip visibility to public on schedule | `existingContentId` |

        ---

        ### Prompt Guidance Modes

        | Mode | Description |
        |------|-------------|
        | `none` | No additional prompt context |
        | `custom` | User-written free text (`customPromptGuidance`) |
        | `ai_tuned` | 30-day analytics context appended to prompt |
        | `ai_driven` | Fully autonomous - AI decides category, difficulty, duration |

        ---

        ### Validation

        - `minutesLimit` entitlement must have remaining capacity
        - `premiumStock` entitlement required if `includePremiumStock` is true
        - `sourceContentId` / `existingContentId` must belong to the organization

        ---

        ### Related Endpoints

        - Activate: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/activate`
        - Update: `PATCH /v1/orgs/{orgId}/content-autopilot/{taskId}`
        - List: `GET /v1/orgs/{orgId}/content-autopilot`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAutopilotTaskDto'
            examples:
              aiGenerate:
                summary: AI-generated daily workout
                value:
                  name: Daily HIIT Generator
                  scope: ai_generate
                  contentType: workout
                  categoryIds:
                    - 615aa3f0dbe7140012c59e94
                  difficultyOptions:
                    - beginner
                    - intermediate
                  durationMin: 15
                  durationMax: 30
                  includeFreeStock: true
                  repeatMode: daily
                  promptGuidanceMode: ai_driven
              createSimilar:
                summary: Weekly workout variation
                value:
                  name: Monday Strength Variation
                  scope: create_similar
                  contentType: workout
                  sourceContentId: 507f1f77bcf86cd799439011
                  difficultyOptions:
                    - intermediate
                  repeatMode: weekly
              publishExisting:
                summary: Scheduled publish
                value:
                  name: Publish Friday Program
                  scope: publish_existing
                  contentType: program
                  existingContentId: 507f1f77bcf86cd799439012
                  difficultyOptions:
                    - beginner
                  repeatMode: once
                  nextRunAt: '2026-04-10T09:00:00.000Z'
      responses:
        '201':
          description: Task created in draft status.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutopilotTaskResponseDto'
        '400':
          description: Invalid input or missing required fields for scope.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Entitlement limit exceeded or API key not authorized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function createTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/events:
    get:
      operationId: OrganizationContentAutopilotApi_listTeamEvents
      summary: List execution events across all tasks
      description: |-

        ## Organization Autopilot Events

        Retrieves execution history across all content autopilot tasks for the organization. Each event records a task execution outcome: success, failure, or skip.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Use Cases

        - **Execution dashboard** - View recent automation activity across all tasks
        - **Failure monitoring** - Filter by `failed` to identify issues
        - **Audit trail** - Review content creation history with content IDs

        ---

        ### Filtering

        - `taskId` - Filter events to a specific task
        - `eventType` - success, failed, skipped_limit, skipped_premium_lost

        ---

        ### Related Endpoints

        - List Tasks: `GET /v1/orgs/{orgId}/content-autopilot`
        - Task Events: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}/events`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Items per page. Defaults to 20, max 50.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: eventType
          required: false
          in: query
          description: Filter by event type
          schema:
            enum:
              - success
              - failed
              - skipped_limit
              - skipped_premium_lost
            type: string
        - name: taskId
          required: false
          in: query
          description: Filter events to a specific task
          schema:
            type: string
        - name: offset
          required: false
          in: query
          description: Pagination offset. Defaults to 0.
          example: 0
          schema:
            type: number
      responses:
        '200':
          description: Successfully retrieved execution events.
          content:
            application/json:
              examples:
                default:
                  summary: Execution event list
                  value:
                    data:
                      - id: 64f1a2b3c4d5e6f7a8b9c0e1
                        taskId: 64f1a2b3c4d5e6f7a8b9c0d1
                        organizationId: 63415bf67a9c7000126616c1
                        ownerId: 507f1f77bcf86cd799439011
                        eventType: success
                        resultContentId: 64f1a2b3c4d5e6f7a8b9c0f1
                        resultContentType: workout
                        createdAt: '2026-04-05T10:00:00.000Z'
                    links:
                      next: null
                      total: 1
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/events' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function listTeamEvents() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/events', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/events", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/{taskId}:
    get:
      operationId: OrganizationContentAutopilotApi_getTask
      summary: Get autopilot task by ID
      description: |-

        ## Autopilot Task Detail

        Returns full configuration of a content autopilot task including schedule, content parameters, and prompt guidance settings.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - List Tasks: `GET /v1/orgs/{orgId}/content-autopilot`
        - Update Task: `PATCH /v1/orgs/{orgId}/content-autopilot/{taskId}`
        - Task Events: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}/events`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved autopilot task detail.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutopilotTaskResponseDto'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>", headers=headers)
            response.raise_for_status()
            print(response.json())
    patch:
      operationId: OrganizationContentAutopilotApi_updateTask
      summary: Update autopilot task configuration
      description: |-

        ## Update Autopilot Task

        Partially updates an autopilot task's configuration. All fields are optional. Fields not included in the request body remain unchanged.

        Notable: update `nextRunAt` to reschedule an active task to a different day without affecting its repeat configuration.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - Get Task: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}`
        - Activate: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/activate`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAutopilotTaskDto'
            examples:
              reschedule:
                summary: Reschedule to a different date
                value:
                  nextRunAt: '2026-04-12T09:00:00.000Z'
              updateConfig:
                summary: Update difficulty and duration
                value:
                  difficultyOptions:
                    - intermediate
                    - advanced
                  durationMin: 20
                  durationMax: 40
      responses:
        '200':
          description: Task updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutopilotTaskResponseDto'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X PATCH 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function updateTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>', {
              method: 'PATCH',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.patch(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
    delete:
      operationId: OrganizationContentAutopilotApi_deleteTask
      summary: Delete autopilot task (soft delete)
      description: |-

        ## Delete Autopilot Task

        Soft-deletes a content autopilot task. The task will no longer execute and will not appear in list results.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - List Tasks: `GET /v1/orgs/{orgId}/content-autopilot`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '204':
          description: Task deleted.
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or already deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X DELETE 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function deleteTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>', {
              method: 'DELETE',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.delete("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/{taskId}/activate:
    post:
      operationId: OrganizationContentAutopilotApi_activateTask
      summary: Activate autopilot task
      description: |-

        ## Activate Task

        Sets the task status to `active` and determines the next scheduled execution time.

        **Schedule resolution:**
        1. If the task already has a `nextRunAt` in the future, it is preserved.
        2. Otherwise, `nextRunAt` is computed from the task's `repeatMode`.
        3. For `once` mode, defaults to now.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - Deactivate: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/deactivate`
        - Run Now: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/run-now`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: Task activated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutopilotTaskResponseDto'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/activate' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function activateTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/activate', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/activate", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/{taskId}/deactivate:
    post:
      operationId: OrganizationContentAutopilotApi_deactivateTask
      summary: Deactivate autopilot task
      description: |-

        ## Deactivate Task

        Sets the task status to `draft` and clears the `nextRunAt` schedule. The task will stop executing until activated again.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - Activate: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/activate`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: Task deactivated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AutopilotTaskResponseDto'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/deactivate' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function deactivateTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/deactivate', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/deactivate", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/{taskId}/run-now:
    post:
      operationId: OrganizationContentAutopilotApi_runNow
      summary: Manually trigger task execution
      description: |-

        ## Run Now

        Executes a content autopilot task immediately, bypassing the cron schedule. Respects all entitlement limits and daily execution caps (max 20 per user per day).

        The task can be in any status (active or draft) -- this allows testing a task configuration before activating it on a schedule.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Rate Limit

        This endpoint triggers AI content generation and counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - Activate: `POST /v1/orgs/{orgId}/content-autopilot/{taskId}/activate`
        - Task Events: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}/events`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: Task executed successfully.
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Entitlement limit exceeded or API key not authorized.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/run-now' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function runNow() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/run-now', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/run-now", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/content-autopilot/{taskId}/events:
    get:
      operationId: OrganizationContentAutopilotApi_listTaskEvents
      summary: List execution events for a task
      description: |-

        ## Task Execution History

        Retrieves the execution event log for a specific autopilot task. Each event records a task run outcome.

        **Event types:**
        - `success` - Content created and published successfully. `resultContentId` contains the new content ID.
        - `failed` - Execution failed. `errorMessage` contains the reason.
        - `skipped_limit` - Daily execution limit (20/day) reached. Task retries next day.
        - `skipped_premium_lost` - Premium stock entitlement lost. Schedule advanced.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)

        ---

        ### Related Endpoints

        - Get Task: `GET /v1/orgs/{orgId}/content-autopilot/{taskId}`
        - Team Events: `GET /v1/orgs/{orgId}/content-autopilot/events`
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the autopilot task.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Items per page. Defaults to 20, max 50.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: eventType
          required: false
          in: query
          description: Filter by event type
          schema:
            enum:
              - success
              - failed
              - skipped_limit
              - skipped_premium_lost
            type: string
        - name: offset
          required: false
          in: query
          description: Pagination offset. Defaults to 0.
          example: 0
          schema:
            type: number
      responses:
        '200':
          description: Successfully retrieved task execution events.
          content:
            application/json:
              examples:
                default:
                  summary: Task execution history
                  value:
                    data:
                      - id: 64f1a2b3c4d5e6f7a8b9c0e1
                        taskId: 64f1a2b3c4d5e6f7a8b9c0d1
                        organizationId: 63415bf67a9c7000126616c1
                        ownerId: 507f1f77bcf86cd799439011
                        eventType: success
                        resultContentId: 64f1a2b3c4d5e6f7a8b9c0f1
                        resultContentType: workout
                        createdAt: '2026-04-05T10:00:00.000Z'
                      - id: 64f1a2b3c4d5e6f7a8b9c0e2
                        taskId: 64f1a2b3c4d5e6f7a8b9c0d1
                        organizationId: 63415bf67a9c7000126616c1
                        ownerId: 507f1f77bcf86cd799439011
                        eventType: failed
                        errorMessage: Content minutes limit reached
                        createdAt: '2026-04-04T10:00:00.000Z'
                    links:
                      next: null
                      total: 2
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Task not found or deleted.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - content-autopilot
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/events' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function listTaskEvents() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/events', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/content-autopilot/<TASKID>/events", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/drops:
    get:
      operationId: OrganizationDropsApi_getOrganizationDrops
      summary: List organization social drops
      description: |-

        ## Organization Social Drops

        Retrieves paginated list of ready social drops for your organization. A drop is a publish-ready package (video variants, covers, copy packs) linked to an Exercise, Collection (Micro Workout), Workout, or Program.

        **Note:** Only drops with status `ready` are returned. Draft, processing, and failed drops are excluded.

        ---

        ### Access and Auth

        - **Auth:** API key (X-Api-Key header)
        - **Scope:** Organization (organizationId)
        - **Capabilities:** List ready drops, get drop detail, export channel bundle (video, cover, copy pack)

        ---

        ### Use Cases

        - **Social scheduling tools** - List drops for content calendar
        - **Content management dashboards** - Browse and export ready assets
        - **Bulk export workflows** - Get video + cover + copy for channel publishing
        - **Channel-specific discovery** - Filter by aspect ratio and duration

        ---

        ### Filtering and Pagination

        **Filters:**
        - `sourceType` - exercise, exerciseCollection, workout, workoutCollection
        - `sourceId` - Filter by source entity ID (use with sourceType for entity-context views)
        - `aspectRatio` - 9:16, 1:1, 16:9 (drops that have this variant)
        - `duration` - 15, 30, 60 (seconds; drops that have this variant)
        - `q` - Search by drop title (min 3 characters)

        **Sort:** Use `sort` with +field (asc) or -field (desc), e.g. `-updatedAt`, `+createdAt`

        **Pagination:**
        - `limit` - Items per page (default: 20, max: 50)
        - `offset` - Pagination offset (default: 0)

        ---

        ### Best Practices

        - **Cache responses** - Drops change when new content is published
        - **Use sourceId** - Filter by source when showing drops in entity-context modals
        - **Handle empty results** - Graceful fallback when no ready drops exist

        ---

        ### Related Endpoints

        - Get Drop: `GET /v1/orgs/{orgId}/drops/{dropId}` - Full detail with variants and copy packs
        - Export Drop: `POST /v1/orgs/{orgId}/drops/{dropId}/export` - Channel bundle (video, cover, copy)
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Items per page. Defaults to 20, max 50.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: q
          required: false
          in: query
          description: Search by drop title (min 3 characters)
          schema:
            type: string
        - name: sort
          required: false
          in: query
          description: 'Sort: +updatedAt, -createdAt'
          schema:
            type: string
        - name: sourceType
          required: false
          in: query
          description: Filter by source type
          schema:
            enum:
              - exercise
              - exerciseCollection
              - workout
              - workoutCollection
            type: string
        - name: sourceId
          required: false
          in: query
          description: Filter by source entity ID
          schema:
            type: string
        - name: aspectRatio
          required: false
          in: query
          description: Filter by aspect ratio
          schema:
            enum:
              - '9:16'
              - '1:1'
              - '16:9'
            type: string
        - name: duration
          required: false
          in: query
          description: Filter by duration in seconds
          schema:
            enum:
              - 15
              - 30
              - 60
            type: number
        - name: offset
          required: false
          in: query
          description: Pagination offset. Defaults to 0.
          example: 0
          schema:
            type: number
      responses:
        '200':
          description: Successfully retrieved paginated list of ready drops for the organization.
          content:
            application/json:
              examples:
                default:
                  summary: List of ready drops
                  value:
                    data:
                      - id: 64f1a2b3c4d5e6f7a8b9c0d1
                        organizationId: 63415bf67a9c7000126616c1
                        sourceType: exercise
                        sourceId: 507f1f77bcf86cd799439011
                        sourceName: Jumping Jacks
                        title: Jumping Jacks
                        sourceThumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/...
                        sourceTypeLabel: Exercise
                        locale: en-US
                        channelPreset: ig_reels
                        channelPresetLabel: Instagram Reels
                        availableVariants:
                          - '9:16_30000'
                          - '9:16_15000'
                          - '1:1_30000'
                        createdAt: '2025-09-15T10:30:00Z'
                        updatedAt: '2025-09-16T14:20:00Z'
                      - id: 64f1a2b3c4d5e6f7a8b9c0d2
                        organizationId: 63415bf67a9c7000126616c1
                        sourceType: workout
                        sourceId: 12ab3efd45c67c1234566cd1
                        sourceName: Morning Power HIIT
                        title: Morning Power HIIT
                        sourceThumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/...
                        sourceTypeLabel: Workout
                        locale: en-US
                        channelPreset: ig_reels
                        channelPresetLabel: Instagram Reels
                        availableVariants:
                          - '9:16_60000'
                          - '1:1_30000'
                        createdAt: '2025-09-14T08:00:00Z'
                        updatedAt: '2025-09-15T11:45:00Z'
                    links:
                      next: https://content.api.hyperhuman.cc/v1/orgs/63415bf67a9c7000126616c1/drops?limit=20&offset=20
                      total: 42
                    explanation: Your ready social drops - video variants, covers, and copy packs for channel publishing.
        '400':
          description: Invalid filter or pagination parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationDrops() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/drops/{dropId}:
    get:
      operationId: OrganizationDropsApi_getOrganizationDropById
      summary: Get drop by ID
      description: |-

        ## Drop Detail

        Returns full drop detail including video variants with presigned download and poster URLs, and copy packs per channel.

        **Response structure:**
        - `copyPack` - Copy pack for the default channel (channelPreset)
        - `copyPacks` - Copy packs per channel; use `copyPacks[viewChannel] ?? copyPack` for channel switching
        - `variants` - Video variants with aspectRatio, duration, downloadLink, posterLink, posterLinksByChannel, size

        **URL expiration:** Presigned URLs are valid for 7 days.

        ---

        ### Related Endpoints

        - List Drops: `GET /v1/orgs/{orgId}/drops` - Browse organization drops
        - Export Drop: `POST /v1/orgs/{orgId}/drops/{dropId}/export` - Get channel bundle
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: dropId
          required: true
          in: path
          description: The unique identifier of the drop.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved drop detail.
          content:
            application/json:
              examples:
                default:
                  summary: Drop detail with variants and copy packs
                  value:
                    id: 64f1a2b3c4d5e6f7a8b9c0d1
                    organizationId: 63415bf67a9c7000126616c1
                    sourceType: exercise
                    sourceId: 507f1f77bcf86cd799439011
                    sourceName: Jumping Jacks
                    title: Jumping Jacks
                    sourceThumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/...
                    sourceTypeLabel: Exercise
                    locale: en-US
                    channelPreset: ig_reels
                    channelPresetLabel: Instagram Reels
                    availableVariants:
                      - '9:16_30000'
                      - '9:16_15000'
                      - '1:1_30000'
                    copyPack:
                      hook: Get fit in 30 seconds!
                      caption: 30 seconds of Jumping Jacks to get your heart pumping. Perfect for a quick warm-up or standalone cardio burst. Try it now and feel the burn.
                      hashtags: '#fitness #workout #hiit #cardio'
                      cta: Link in bio
                      posterTagline:
                        primaryLine: 30s HIIT
                        secondaryLine: Jumping Jacks
                    copyPacks:
                      ig_reels:
                        hook: Get fit in 30 seconds!
                        caption: 30 seconds of Jumping Jacks to get your heart pumping. Perfect for a quick warm-up or standalone cardio burst. Try it now and feel the burn.
                        hashtags: '#fitness #workout #hiit #cardio'
                        cta: Link in bio
                        posterTagline:
                          primaryLine: 30s HIIT
                          secondaryLine: Jumping Jacks
                      tiktok:
                        hook: 30 sec cardio burst
                        caption: Jumping Jacks - no equipment needed. Drop a heart if you finished it.
                        hashtags: '#fitness #workout #cardio #30secondchallenge'
                        cta: Full workout in bio
                        posterTagline:
                          primaryLine: 30s HIIT
                          secondaryLine: Jumping Jacks
                    variants:
                      - aspectRatio: '9:16'
                        duration: 30000
                        downloadLink: https://hhcontent.s3.../drop_9x16_30.mp4?X-Amz-...
                        posterLink: https://hhcontent.s3.../poster.png?X-Amz-...
                        posterLinksByChannel:
                          tiktok: https://hhcontent.s3.../poster_tiktok.png?X-Amz-...
                        size: 1234567
                      - aspectRatio: '9:16'
                        duration: 15000
                        downloadLink: https://hhcontent.s3.../drop_9x16_15.mp4?X-Amz-...
                        posterLink: https://hhcontent.s3.../poster_15.png?X-Amz-...
                        size: 654321
                      - aspectRatio: '1:1'
                        duration: 30000
                        downloadLink: https://hhcontent.s3.../drop_1x1_30.mp4?X-Amz-...
                        posterLink: https://hhcontent.s3.../poster_1x1.png?X-Amz-...
                        size: 987654
                    createdAt: '2025-09-15T10:30:00Z'
                    updatedAt: '2025-09-16T14:20:00Z'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Drop not found or not ready.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationDropById() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/drops/{dropId}/export:
    post:
      operationId: OrganizationDropsApi_exportDrop
      summary: Export drop for channel bundle
      description: |-

        ## Export for Channel Bundle

        Returns presigned video download URL, cover image URL, and copy pack for the specified channel. Use for one-click export to Reels, Shorts, TikTok, etc.

        **Response contents:**
        - `videoDownloadLink` - Presigned S3 URL for MP4 video (valid 7 days)
        - `coverLink` - Presigned S3 URL for cover/poster image
        - `copyPack` - Hook, caption, hashtags, CTA, poster tagline
        - `ctaUrl` - Optional CTA URL from team settings (when configured)

        **Channel presets:** ig_reels, ig_stories, ig_carousel, tiktok, yt_shorts, fb_reels, yt_longform. Each has default aspect ratio and duration; override via body.

        ---

        ### Integration Example

        ```javascript
        const res = await fetch(
          `/v1/orgs/${orgId}/drops/${dropId}/export`,
          {
            method: 'POST',
            headers: {
              'X-Api-Key': apiKey,
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({ channelPreset: 'ig_reels' }),
          }
        );
        const { videoDownloadLink, coverLink, copyPack } = await res.json();
        // Download video, copy caption to clipboard
        ```

        ---

        ### Best Practices

        - **Refresh URLs before expiry** - Presigned URLs valid for 7 days
        - **Use channel preset** - Platform-specific defaults (aspect ratio, duration)
        - **Handle 400** - Requested variant may not be available for this drop

        ---

        ### Related Endpoints

        - Get Drop: `GET /v1/orgs/{orgId}/drops/{dropId}` - Full detail before export
        - List Drops: `GET /v1/orgs/{orgId}/drops` - Browse organization drops
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: dropId
          required: true
          in: path
          description: The unique identifier of the drop.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      requestBody:
        required: false
        description: Optional overrides. Omit to use drop defaults.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExportDropDto'
            examples:
              default:
                summary: Use drop defaults
                value: {}
              igReels:
                summary: Instagram Reels
                value:
                  channelPreset: ig_reels
              customVariant:
                summary: Custom variant
                value:
                  channelPreset: tiktok
                  aspectRatio: '9:16'
                  duration: 15
      responses:
        '200':
          description: Channel bundle with presigned URLs and copy pack.
          content:
            application/json:
              examples:
                default:
                  summary: Export bundle for Instagram Reels
                  value:
                    videoDownloadLink: https://hhcontent.s3.../drop_9x16_30.mp4?X-Amz-...
                    coverLink: https://hhcontent.s3.../cover.png?X-Amz-...
                    ctaUrl: https://mybrand.com/fitness
                    copyPack:
                      hook: Get fit in 30 seconds!
                      caption: 30 seconds of Jumping Jacks to get your heart pumping. Perfect for a quick warm-up or standalone cardio burst. Try it now and feel the burn.
                      hashtags: '#fitness #workout #hiit'
                      cta: Link in bio
                      posterTagline:
                        primaryLine: 30s HIIT
                        secondaryLine: Jumping Jacks
        '400':
          description: Requested variant not available for this drop.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Drop not found or not ready.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>/export' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function exportDrop() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>/export', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/drops/<DROPID>/export",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/social-publish/connected-platforms:
    get:
      operationId: OrganizationSocialPublishApi_getConnectedPlatforms
      summary: List connected social platforms
      description: Returns which platforms (instagram, tiktok, youtube, facebook) have a stored account id for this organization. Account connection is managed in the Hyperhuman team app, not via this API.
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationConnectedPlatformsResponseDto'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/connected-platforms' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getConnectedPlatforms() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/connected-platforms', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/connected-platforms", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/social-publish:
    get:
      operationId: OrganizationSocialPublishApi_listTasks
      summary: List scheduled social publish automations
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Maximum number of items to return per page.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: status
          required: false
          in: query
          description: Filter by task status
          schema:
            enum:
              - active
              - draft
            type: string
        - name: sourceMode
          required: false
          in: query
          description: Filter by source mode
          schema:
            enum:
              - manual_fixed
              - random_ready
              - ai_insights
              - ai_pick
            type: string
        - name: sortBy
          required: false
          in: query
          description: Sort by field
          schema:
            enum:
              - updatedAt
              - createdAt
            type: string
        - name: sortOrder
          required: false
          in: query
          description: Sort order
          schema:
            enum:
              - ascend
              - descend
            type: string
        - name: search
          required: false
          in: query
          description: Case-insensitive substring match on automation name (min 1 character after trim)
          schema:
            maxLength: 200
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationSocialPublishTaskListResponse'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function listTasks() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish", headers=headers)
            response.raise_for_status()
            print(response.json())
    post:
      operationId: OrganizationSocialPublishApi_createTask
      summary: Create a social publish automation (draft)
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSocialDropPublishTaskDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationSocialPublishTaskResponseDto'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function createTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/social-publish/{taskId}:
    get:
      operationId: OrganizationSocialPublishApi_getTask
      summary: Get one social publish automation
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the scheduled social publish automation.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationSocialPublishTaskResponseDto'
        '404':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>", headers=headers)
            response.raise_for_status()
            print(response.json())
    patch:
      operationId: OrganizationSocialPublishApi_patchTask
      summary: Update a social publish automation
      description: 'Use `status: active` to schedule (requires connected accounts for all target platforms). Use `status: draft` to pause. Other fields follow the same rules as the team internal API.'
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the scheduled social publish automation.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrganizationPatchSocialPublishTaskDto'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationSocialPublishTaskResponseDto'
        '422':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X PATCH 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function patchTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>', {
              method: 'PATCH',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.patch(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
    delete:
      operationId: OrganizationSocialPublishApi_deleteTask
      summary: Delete a social publish automation (soft delete)
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: taskId
          required: true
          in: path
          description: The unique identifier of the scheduled social publish automation.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
      responses:
        '204':
          description: ''
      tags:
        - social-publish
      security:
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X DELETE 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function deleteTask() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>', {
              method: 'DELETE',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.delete("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/social-publish/<TASKID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/playlist:
    get:
      operationId: WorkoutContentApi_getWorkoutPlaylist
      summary: Retrieve Detailed Workout Playlist Structure
      description: |-

        ## Workout Playlist with Media Assets

        Essential endpoint for building workout video players. Returns the complete, ordered sequence of workout segments with all media assets.

        ---

        ### 📋 Typical Integration Flow

        1. **Get Workout Metadata**: `GET /v1/workouts/{id}` → Basic info (name, duration, difficulty)
        2. **Get Playlist**: `GET /v1/workouts/{id}/playlist` → **This endpoint** (complete playback structure)
        3. **Build Player**: Use segments array to create video player experience
        4. **Track Session**: `POST /v1/workouts/{id}/sessions/start`
        5. **Submit Feedback**: `POST /v1/workouts/{id}/feedback`

        ---

        ### 🎬 Segment Types

        | Type | Description | Contains |
        |------|-------------|----------|
        | `intro` | Workout introduction | Video/audio intro, workout overview |
        | `exercise` | Exercise performance | Name, reps/duration, **rpe**, **amrap**, video (intro+main), audio cues, equipment, muscle groups |
        | `break` | Rest period | Duration, optional video/audio |
        | `outro` | Workout conclusion | Cooldown, summary |

        ---

        ### 📦 What's Included

        - **Video URLs**: Pre-signed S3 URLs for HLS master playlists
        - **Audio URLs**: Instruction audio, background music, voice cues
        - **Timing**: Precise duration for each segment in seconds
        - **Exercise Metadata**: Muscle groups, equipment, difficulty
        - **Localization**: All content in requested locale (13 languages)

        ---

        ### 🌍 Localization

        Supports 13 locales: en-US, en-GB, en-AU, fr-FR, de-DE, es-ES, it-IT, pt-PT, he-IL, ro-RO, cs-CZ, fi-FI, nl-NL

        Falls back to English if locale unsupported.

        ---

        ### 🔗 Related Endpoints

        - Get Workout: `GET /v1/workouts/{id}`
        - Workout Metadata: `GET /v1/workouts/metadata`
        - Start Session: `POST /v1/workouts/{id}/sessions/start`
        - Full audio export: `GET /v1/workouts/{id}/export/audio/stream_url`
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique workout id (24-character hex DB id) whose playlist is required.
          example: a1b2c3d4e5f6a7b8c9d0e1f2
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: 'Language locale for localized content (BCP-47 format). Affects exercise names, equipment names, muscle group names, and audio selection. Supported: en-US, en-GB, en-AU, fr-FR, de-DE, es-ES, it-IT, pt-PT, he-IL, ro-RO, cs-CZ, fi-FI, nl-NL. Falls back to English if unsupported.'
          example: fr-FR
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved the detailed workout playlist structure. `data` is an ordered array; each item is an object with a single key indicating the segment kind (one of `intro`, `narrative`, `exercise`, `multiExercise`, `class`, `promo`, `educational`, `break`, `outro`). The value under that key is the segment payload (see schema for the per-kind shape).
          schema:
            example:
              data:
                - intro:
                    kind: workout-intro
                    id: intro
                    duration: 5.2
                    audio:
                      url: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/intro.m4a
                    video:
                      url: https://stream.hyperhuman.cc/intro.m3u8
                      poster: https://images.hyperhuman.cc/intro-poster.jpg
                      thumbnail: https://images.hyperhuman.cc/intro-thumb.jpg
                - exercise:
                    kind: exercise
                    id: exercise_squats_1
                    exerciseId: 507f1f77bcf86cd799439011
                    duration: 45
                    name: Bodyweight Squats
                    reps: 12
                    pace: medium
                    weightLevel: null
                    rpe: 7
                    amrap: false
                    equipment:
                      - id: 60812e08606fc90011eb4408
                        name: Mat
                    muscleGroups:
                      - id: 604b0177076fe2727354d743
                        name: Legs
                    intro:
                      audio:
                        url: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/squat-cue.m4a
                      video:
                        url: https://stream.hyperhuman.cc/squat-intro.m3u8
                        poster: https://images.hyperhuman.cc/squat-poster.jpg
                        thumbnail: https://images.hyperhuman.cc/squat-thumb.jpg
                        loop: -1
                    main:
                      video:
                        url: https://stream.hyperhuman.cc/squat-main.m3u8
                        poster: https://images.hyperhuman.cc/squat-poster.jpg
                        thumbnail: https://images.hyperhuman.cc/squat-thumb.jpg
                        loop: -1
                      instructionAudio:
                        - url: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/squat-instruction-1.m4a
                - break:
                    kind: break
                    id: break_1
                    duration: 30
                    video: null
                - outro:
                    kind: workout-outro
                    id: outro
                    duration: 45.5
                    audio:
                      url: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/outro-cooldown.m4a
                    video:
                      url: https://stream.hyperhuman.cc/outro.m3u8
                      poster: https://images.hyperhuman.cc/outro-poster.jpg
                      thumbnail: https://images.hyperhuman.cc/outro-thumb.jpg
              presentationStyle: full
              links: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutPlaylistResponse'
        '401':
          description: Authentication failed. API key or Bearer token is missing, invalid, or expired.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID does not exist or a playlist could not be generated for it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - X-Api-Key:
            - X-Api-Key
        - AccessToken: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/playlist' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutPlaylist() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/playlist', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/playlist", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/music:
    get:
      operationId: WorkoutContentApi_getWorkoutMusic
      summary: Get workout music playlist
      description: |-

        ## Workout Music Playlist

        Returns a shuffled playlist of music tracks selected to fill the workout duration. 
        Uses the trainer's music preferences and workout categories to select appropriate tracks.

        ### Music Selection
        - **User Preferences**: Respects trainer's music settings and category mappings
        - **Category Filtering**: Selects tracks matching workout categories (HIIT, Strength, etc.)
        - **Duration Filling**: Shuffled, deduplicated track list whose total duration generously exceeds the workout duration so the player always has headroom for runtime track selection (do not rely on a specific buffer ratio)
        - **Fallback**: Uses stock music if no user preferences set

        ### 📱 Mobile Ready
        - Pre-signed S3 URLs (7-day expiration)
        - Simple JSON response
        - Track metadata (name, duration, filename)
        - Total playlist duration for player setup

        ### 🔗 Related Endpoints
        - Workout Details: `GET /v1/workouts/{id}`
        - Workout Playlist: `GET /v1/workouts/{id}/playlist`
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier of the workout
          example: a1b2c3d4e5f6a7b8c9d0e1f2
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved workout music playlist
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutMusicPlaylistResponse'
        '401':
          description: Authentication failed. API key or Bearer token is missing, invalid, or expired.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - X-Api-Key:
            - X-Api-Key
        - AccessToken: []
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/music' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutMusic() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/music', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/music", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/sessions/start:
    post:
      operationId: WorkoutsSessionsApi_startWorkoutSession
      summary: Start workout session
      description: |-

        ## Begin Workout Tracking

        Initiates a new workout session for progress tracking, analytics, and completion monitoring. Handles both authenticated and anonymous users.

        ---

        ### 🔄 Session Lifecycle

        1. **Start Session**: `POST /v1/workouts/{id}/sessions/start` → **This endpoint**
        2. **Track Progress**: `PATCH /v1/workouts/{id}/sessions/{sessionId}` → Update completion
        3. **End Session**: `POST /v1/workouts/{id}/sessions/end` → Mark complete
        4. **Submit Feedback**: `POST /v1/workouts/{id}/feedback` → Rate experience

        ---

        ### 👤 Authentication Scenarios

        **Authenticated Users:**
        - Closes any previous incomplete sessions automatically
        - Links session to user profile for history tracking
        - Enables progress sync across devices

        **Anonymous Users:**
        - Creates temporary session without user linkage
        - Limited to single-device tracking
        - No historical data retention

        ---

        ### 📊 What Gets Tracked

        | Data Point | Description | Use Case |
        |------------|-------------|----------|
        | **Start Time** | Session initiation timestamp | Duration calculation |
        | **User ID** | Authenticated user (if logged in) | Progress history |
        | **Workout ID** | Which workout being performed | Analytics |
        | **Session ID** | Unique session identifier | Progress updates |

        ---

        ### 💡 Best Practices

        ✅ **Start immediately** - Call when user begins workout  
        ✅ **Handle failures** - Graceful degradation if session fails  
        ✅ **Update progress** - Use PATCH endpoint during workout  
        ✅ **Complete session** - Always call end endpoint

        ---

        ### 🔗 Related Endpoints

        - Get Workout: `GET /v1/workouts/{id}` - Workout details before starting
        - Update Session: `PATCH /v1/workouts/{id}/sessions/{sessionId}` - Track progress
        - End Session: `POST /v1/workouts/{id}/sessions/end` - Mark complete
        - Submit Feedback: `POST /v1/workouts/{id}/feedback` - Rate workout
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout to start a session for.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: false
        description: Session start request. No body required - workout ID from URL parameter.
        content:
          application/json:
            schema:
              type: string
            examples:
              authenticated-user:
                summary: Authenticated User Session
                description: Standard session start for logged-in user with automatic session management
                value: {}
              anonymous-user:
                summary: Anonymous User Session
                description: Session start without authentication - limited tracking capabilities
                value: {}
      responses:
        '201':
          description: Workout session successfully started. Any previous incomplete sessions for this workout are automatically closed.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T08:30:00.000Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: intro
                status: started
                duration: 0
                progress: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/start' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function startWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/start', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/start",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/sessions/{sessionId}:
    patch:
      operationId: WorkoutsSessionsApi_patchWorkoutSession
      summary: Update a workout session
      description: |-

        Updates an active workout session to track playback progress.

        **Primary Use:**
        - Send `progressSeconds` with actual playback time during workout
        - Update `workoutSegmentId` to track current segment

        **Duration Tracking:**
        - `progressSeconds` should represent total actual playback time (excluding pauses)
        - Duration is capped at 2x the expected workout duration to prevent outliers
        - On end session, the last known duration from PATCH is preserved

        **Best Practices:**
        - PATCH every 10-30 seconds during active playback
        - PATCH on segment transitions
        - Send final PATCH before calling end session

        **Related Endpoints:**
        - Start Session: `POST /v1/workouts/{id}/sessions/start`
        - End Session: `POST /v1/workouts/{id}/sessions/end`
        - Complete Session: `POST /v1/workouts/{id}/sessions/complete`
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout associated with the session.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: sessionId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout session to update.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        description: Update session progress. Send progressSeconds to track actual playback time.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchWorkoutSessionBody'
            examples:
              updateProgress:
                summary: Update playback progress (recommended)
                description: Track actual playback time. This is the primary method for accurate duration tracking.
                value:
                  workoutSegmentId: seg-exercise-2
                  progressSeconds: 125.5
              updateSegmentOnly:
                summary: Update segment only
                description: Track which segment user is on without updating playback time.
                value:
                  workoutSegmentId: seg-exercise-3
      responses:
        '200':
          description: Workout session updated successfully.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T08:32:45.500Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: seg-exercise-2
                status: started
                duration: 125.5
                progress: 0.15
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '400':
          description: Invalid data provided in the request body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID or session ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Session is already completed and cannot be updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X PATCH 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function patchWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>', {
              method: 'PATCH',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.patch(
                "https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
    get:
      operationId: WorkoutsSessionsApi_getWorkoutSession
      summary: Get specific workout session details
      description: |-

        ## Get Specific Session Details

        Retrieves details of a specific workout session by its unique ID. Includes status, duration, progress, and timestamps.

        ---

        ### 🎯 Use Cases

        **Session Inspection:**
        - View detailed session information
        - Check current status and progress
        - Verify session duration

        **Progress Tracking:**
        - Display session statistics
        - Track completion percentage
        - Show duration in seconds

        ---

        ### 📊 Response Fields

        | Field | Type | Description |
        |-------|------|-------------|
        | id | string | Session unique identifier |
        | createdAt | date | When session was started |
        | updatedAt | date | Last update timestamp |
        | workoutId | string | Associated workout ID |
        | workoutSegmentId | string | Current segment ID |
        | status | string | 'started' or 'completed' |
        | duration | number | Playback time in seconds |
        | progress | number | Completion fraction (0-1) |

        ---

        ### 💡 Best Practices

        ✅ **Handle 404 gracefully** - Session may not exist or be accessible  
        ✅ **Check status field** - Verify session is 'started' before updates  
        ✅ **Use duration** - Duration is in seconds (actual playback time)

        ---

        ### 🔗 Related Endpoints

        - Recent Session: `GET /v1/workouts/{id}/sessions/recent` - Most recent active session
        - Update Session: `PATCH /v1/workouts/{id}/sessions/{sessionId}` - Track progress
        - End Session: `POST /v1/workouts/{id}/sessions/end` - Complete session
        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin new session
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout associated with the session.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: sessionId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout session to retrieve.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      responses:
        '200':
          description: Workout session details retrieved successfully.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T08:45:30.500Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: seg-exercise-3
                status: started
                duration: 930
                progress: 0.52
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The authenticated user is not authorized to view this session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID or session ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/<SESSION_ID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/sessions/end:
    post:
      operationId: WorkoutsSessionsApi_endWorkoutSession
      summary: End a workout session
      description: |-

        Marks an active workout session as completed. The duration is preserved from the last PATCH call.

        **Duration Behavior:**
        - Uses the duration from the most recent PATCH (progressSeconds-based)
        - Does NOT recalculate duration from wall-clock time
        - If no PATCH was called, duration will be 0

        **Typical Flow:**
        1. Start session: `POST /v1/workouts/{id}/sessions/start`
        2. Update progress: `PATCH /v1/workouts/{id}/sessions/{sessionId}` with progressSeconds
        3. **End session**: `POST /v1/workouts/{id}/sessions/end` (this endpoint)
        4. Submit feedback: `POST /v1/workouts/{id}/feedback`

        **Best Practice:** Send a final PATCH with current progressSeconds before calling end.

        **Related Endpoints:**
        - Start Session: `POST /v1/workouts/{id}/sessions/start`
        - Update Session: `PATCH /v1/workouts/{id}/sessions/{sessionId}`
        - Complete Session: `POST /v1/workouts/{id}/sessions/complete` (force 100%)
        - Submit Feedback: `POST /v1/workouts/{id}/feedback`
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout associated with the session.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        description: Data required to end the session.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EndWorkoutSessionBody'
            examples:
              endSession:
                summary: End a session
                description: Ends the session with duration from last PATCH.
                value:
                  sessionId: 12ab3efd45c67c1234566cd1
      responses:
        '200':
          description: Workout session successfully marked as completed.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T09:15:30.000Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: seg-outro
                status: completed
                duration: 2730
                progress: 1
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '400':
          description: Invalid request data (e.g., missing sessionId).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID or session ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Session is already completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/end' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function endWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/end', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/end",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/sessions/complete:
    post:
      operationId: WorkoutsSessionsApi_completeWorkoutSession
      summary: Complete workout session with 100% progress
      description: |-

        ## Force Complete Session

        Marks a session as fully completed (100% progress) regardless of actual elapsed time. Use this when you need to guarantee a workout shows as complete in user history.

        ---

        ### 🎯 When to Use

        **Use `/sessions/complete` when:**
        - ✅ User manually marks workout as done
        - ✅ Workout completed outside the app (e.g., offline)
        - ✅ Need to force 100% completion for user's history
        - ✅ Retroactive completion (user forgot to track)

        **Use `/sessions/end` instead when:**
        - ✅ Normal workout completion flow
        - ✅ Want to preserve actual progress percentage
        - ✅ User stopped mid-workout
        - ✅ Tracking actual time and progress

        ---

        ### 📊 Endpoint Comparison

        | Aspect | complete | end |
        |--------|----------|-----|
        | **Progress** | Always 100% | Actual progress |
        | **Duration** | Full workout duration | Actual elapsed time |
        | **Use Case** | Manual/forced completion | Natural completion |
        | **User Experience** | "Mark as done" button | Workout timer ends |

        ---

        ### 🔄 Integration Flow

        **Normal Flow (Use /end):**
        ```
        1. POST /sessions/start → Start tracking
        2. PATCH /sessions/{id} → Update progress
        3. POST /sessions/end → Natural completion
        4. POST /feedback → Collect feedback
        ```

        **Force Complete Flow (Use /complete):**
        ```
        1. POST /sessions/start → May have happened earlier
        2. POST /sessions/complete → Force to 100%
        3. (Optional) POST /feedback → Collect feedback
        ```

        ---

        ### 💡 Best Practices

        ✅ **Use sparingly** - Prefer /end for actual completions  
        ✅ **Document reason** - Log why forced completion was used  
        ✅ **User transparency** - Show "marked complete" vs "completed"  
        ✅ **Analytics distinction** - Track forced vs natural completions separately

        ---

        ### 🔗 Related Endpoints

        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin workout
        - End Session (natural): `POST /v1/workouts/{id}/sessions/end` - Normal completion
        - Update Session: `PATCH /v1/workouts/{id}/sessions/{sessionId}` - Track progress
        - Get Session: `GET /v1/workouts/{id}/sessions/{sessionId}` - Check status
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout associated with the session.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        description: Data required to complete the session.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CompleteWorkoutSessionBody'
            examples:
              completeSession:
                summary: Mark a specific session as 100% completed
                description: Force complete a session for user's workout history
                value:
                  sessionId: 12ab3efd45c67c1234566cd1
      responses:
        '200':
          description: Workout session successfully marked as 100% completed.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T09:00:00.000Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: seg-outro
                status: completed
                duration: 1800
                progress: 1
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '400':
          description: Invalid request data (e.g., missing sessionId) or session is already completed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The authenticated user is not authorized to complete this session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID or session ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/complete' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function completeWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/complete', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/complete",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/sessions/recent:
    get:
      operationId: WorkoutsSessionsApi_getRecentWorkoutSession
      summary: Get most recent workout session
      description: |-

        ## Get Most Recent Session

        Retrieves the most recent incomplete (status='started') workout session for a specific workout. Use this to check if there's an active session to resume.

        ---

        ### 🎯 Use Cases

        **Resume Workout:**
        - Check if user has an active session to resume
        - Display current progress and duration
        - Continue where they left off

        **Progress Tracking:**
        - Show current completion status
        - Display workout progress
        - Check session state

        ---

        ### 📊 Session States

        **Started Sessions:**
        - Session is in progress
        - Can be updated via PATCH to track progress
        - Will be auto-completed if user starts a new session for the same workout

        **Completed Sessions:**
        - Session has ended (via /end, /complete, or auto-complete)
        - Duration and progress are finalized
        - Historical record for analytics

        ---

        ### 💡 Best Practices

        ✅ **Check before starting** - Use this to offer "Resume" vs "Start New"  
        ✅ **Handle 404 gracefully** - No active session is normal for new workouts  
        ✅ **Use for resume flow** - Perfect for "Continue Workout" buttons  
        ✅ **Check status field** - Verify session is 'started' before resuming

        ---

        ### 🔗 Related Endpoints

        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin new session
        - Get Session by ID: `GET /v1/workouts/{id}/sessions/{sessionId}` - Specific session
        - Update Session: `PATCH /v1/workouts/{id}/sessions/{sessionId}` - Track progress
        - End Session: `POST /v1/workouts/{id}/sessions/end` - Complete session
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout for which to find the recent session.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      responses:
        '200':
          description: Most recent workout session details retrieved successfully.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d1
                createdAt: '2025-01-10T08:30:00.000Z'
                updatedAt: '2025-01-10T08:45:30.500Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSegmentId: seg-exercise-3
                status: started
                duration: 930
                progress: 0.52
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutSessionResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No workout session (active or completed) found for this workout ID and authenticated user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/recent' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getRecentWorkoutSession() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/recent', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/sessions/recent", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/feedback/options:
    get:
      operationId: WorkoutsFeedbackApi_getWorkoutFeedbackOptions
      summary: Get workout feedback options
      description: |-

        ## Available Feedback Options

        Retrieves the rating scales and options available for workout feedback. Use this to populate your feedback UI dynamically.

        ---

        ### 📋 Response Structure

        **Rating Options:**
        - 1 Star - Poor
        - 2 Stars - Fair  
        - 3 Stars - Good
        - 4 Stars - Very Good
        - 5 Stars - Excellent

        **Difficulty Options:**
        - 1 - Too Easy
        - 2 - Easy
        - 3 - Just Right
        - 4 - Challenging
        - 5 - Too Hard

        ---

        ### 🎯 Use Cases

        ✅ **Build Feedback UI** - Get all available options dynamically  
        ✅ **Validate Submissions** - Ensure feedback IDs are valid before submitting  
        ✅ **Localization** - Get translated option labels based on locale  
        ✅ **Consistency** - Use platform-standard feedback scales

        ---

        ### 💡 Best Practices

        ✅ **Cache options** - They rarely change, cache for 24 hours  
        ✅ **Use option IDs** - Submit feedback using IDs not labels  
        ✅ **Handle missing options** - Graceful degradation if endpoint fails  
        ✅ **Refresh periodically** - Check for new options monthly

        ---

        ### 🔗 Related Endpoints

        - Submit Feedback: `POST /v1/workouts/{id}/feedback` - Submit user feedback
        - End Session: `POST /v1/workouts/{id}/sessions/end` - Complete before feedback
        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin workout tracking
            
      parameters: []
      responses:
        '200':
          description: Successfully retrieved feedback options with all available rating scales.
          schema:
            example:
              ratings:
                - id: rating-1-star
                  label: Poor
                  value: 1
                - id: rating-2-stars
                  label: Fair
                  value: 2
                - id: rating-3-stars
                  label: Good
                  value: 3
                - id: rating-4-stars
                  label: Very Good
                  value: 4
                - id: rating-5-stars
                  label: Excellent
                  value: 5
              difficulties:
                - id: difficulty-too-easy
                  label: Too Easy
                  value: 1
                - id: difficulty-easy
                  label: Easy
                  value: 2
                - id: difficulty-just-right
                  label: Just Right
                  value: 3
                - id: difficulty-challenging
                  label: Challenging
                  value: 4
                - id: difficulty-too-hard
                  label: Too Hard
                  value: 5
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutFeedbackOptionsResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/feedback/options' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getWorkoutFeedbackOptions() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/feedback/options', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/workouts/feedback/options", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/workouts/{workoutId}/feedback:
    post:
      operationId: WorkoutsFeedbackApi_submitWorkoutFeedback
      summary: Submit workout feedback
      description: |-

        ## Workout Rating & Comments

        Collect user feedback after workout completion including ratings, difficulty assessment, exercise performance data (weights and reps), and optional comments for continuous improvement.

        ---

        ### 📋 Feedback Components

        | Component | Required | Description | Options |
        |-----------|----------|-------------|---------|
        | **Session ID** | ✅ Yes | Links feedback to completed session | From session start |
        | **Overall Rating** | ❌ Optional | General workout satisfaction | 1-5 stars |
        | **Difficulty Rating** | ❌ Optional | Perceived workout difficulty | Too easy → Too hard |
        | **Weight Unit** | ❌ Optional | Unit system for weights | metric (kg) or imperial (lbs) |
        | **Exercise Data** | ❌ Optional | Per-exercise weights and reps | Array of exercise feedback |
        | **Comments** | ❌ Optional | Free-text feedback | Max 1000 characters |

        ---

        ### 🏋️ Exercise Performance Tracking

        **Exercise Data Structure:**
        - Each entry corresponds to an exercise from the workout playlist (excluding rest segments)
        - Maintain the same order as the workout playlist
        - Filter out rest segments and irrelevant exercises client-side before submission

        **Weight Tracking:**
        - Required for weight-based exercises
        - Specify `weightUnit` ('metric' for kg, 'imperial' for lbs) when providing weights
        - Weight range: 0-1000 (supports both kg and lbs)
        - Example: `{ instanceId: "...", weight: 25.5 }` with `weightUnit: "metric"`

        **Reps Tracking:**
        - Required for AMRAP/time-based exercises (capture actual reps completed)
        - Required for rep-based exercises (capture actual reps completed)
        - Reps range: 1-100
        - Example: `{ instanceId: "...", reps: 15 }`

        **Combined:**
        - Some exercises may track both weight and reps
        - Example: `{ instanceId: "...", weight: 20.0, reps: 12 }`

        ---

        ### 🎯 When to Collect Feedback

        ✅ **After completion** - User finished entire workout  
        ✅ **After early exit** - User stopped mid-workout  
        ✅ **Optional prompts** - Don't force feedback  
        ✅ **Quick ratings** - Minimize friction

        ---

        ### 🔄 Integration Flow

        1. **Complete Workout**: User finishes or stops workout
        2. **End Session**: `POST /v1/workouts/{id}/sessions/end` → Get session ID
        3. **Get Playlist**: `GET /v1/workouts/{id}/playlist` → Get exercise order and instance IDs
        4. **Show Feedback UI**: Present rating interface + exercise performance tracking
        5. **Submit Feedback**: `POST /v1/workouts/{id}/feedback` → **This endpoint**
        6. **Thank User**: Acknowledge feedback submission

        ---

        ### 📊 Feedback Options

        **Get Available Options:**
        `GET /v1/workouts/feedback/options` → Returns current rating scales

        **Rating Scales:**
        - Overall: 1 (Poor) → 5 (Excellent)
        - Difficulty: 1 (Too Easy) → 5 (Too Hard)

        ---

        ### 💡 Best Practices

        ✅ **Make optional** - Don't require feedback to proceed  
        ✅ **Quick UI** - Star ratings over complex forms  
        ✅ **Contextual timing** - Collect when experience is fresh  
        ✅ **Anonymous option** - Allow feedback without login  
        ✅ **Order matters** - Maintain playlist order when submitting exerciseData  
        ✅ **Filter client-side** - Remove rest segments before submission  
        ✅ **Validate instanceIds** - Ensure instanceIds match workout playlist  
        ✅ **Unit consistency** - Use same weightUnit for all exercises in a submission

        ---

        ### 🔗 Related Endpoints

        - Feedback Options: `GET /v1/workouts/feedback/options` - Get rating scales
        - End Session: `POST /v1/workouts/{id}/sessions/end` - Complete before feedback
        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin tracking
        - Get Workout: `GET /v1/workouts/{id}` - Workout details
        - Get Playlist: `GET /v1/workouts/{id}/playlist` - Get exercise order and instance IDs
            
      parameters:
        - name: workoutId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout receiving feedback.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        description: Workout feedback with ratings, optional comments, and exercise performance data.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitWorkoutFeedbackBody'
            examples:
              full-feedback:
                summary: Complete Feedback
                description: Full feedback with rating, difficulty, and comments
                value:
                  workoutSessionId: 64f1a2b3c4d5e6f7a8b9c0d1
                  ratingId: rating-5-stars
                  difficultyId: difficulty-just-right
                  comment: Great workout! The exercises were challenging but doable. Would love more variety in the warm-up.
              rating-only:
                summary: Rating Only
                description: Quick rating without difficulty or comments
                value:
                  workoutSessionId: 64f1a2b3c4d5e6f7a8b9c0d1
                  ratingId: rating-4-stars
              anonymous-feedback:
                summary: Anonymous Feedback
                description: Feedback from non-authenticated user session
                value:
                  workoutSessionId: 64f1a2b3c4d5e6f7a8b9c0d1
                  ratingId: rating-5-stars
                  difficultyId: difficulty-moderate
                  comment: Perfect for beginners!
              with-exercise-data:
                summary: Feedback with Exercise Performance Data
                description: Feedback including weights and reps tracking
                value:
                  workoutSessionId: 64f1a2b3c4d5e6f7a8b9c0d1
                  ratingId: rating-5-stars
                  difficultyId: difficulty-just-right
                  weightUnit: metric
                  exerciseData:
                    - instanceId: 64f1a2b3c4d5e6f7a8b9c0d2
                      weight: 25.5
                    - instanceId: 64f1a2b3c4d5e6f7a8b9c0d3
                      reps: 15
                    - instanceId: 64f1a2b3c4d5e6f7a8b9c0d4
                      weight: 20
                      reps: 12
                  comment: Great workout!
      responses:
        '201':
          description: Feedback submitted successfully.
          schema:
            example:
              data:
                id: 67d1a2b3c4e5f6789abc0d2
                createdAt: '2025-01-10T09:30:00.000Z'
                updatedAt: '2025-01-10T09:30:00.000Z'
                workoutId: 12ab3efd45c67c1234566cd1
                workoutSessionId: 67d1a2b3c4e5f6789abc0d1
                rating:
                  id: rating-4-stars
                  label: Very Good
                  value: 4
                difficulty:
                  id: difficulty-challenging
                  label: Challenging
                  value: 4
                comment: Great workout! Felt appropriately challenging.
                weightUnit: metric
                exercises:
                  - instanceId: 64f1a2b3c4d5e6f7a8b9c0d2
                    reps: 15
                  - instanceId: 64f1a2b3c4d5e6f7a8b9c0d3
                    weight: 25
                    reps: 12
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutFeedbackResponse'
        '400':
          description: Invalid feedback data provided (e.g., missing required rating, invalid rating value, missing weightUnit when weights provided, invalid instanceIds). Check feedback options endpoint.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed (API key invalid or Bearer token invalid if provided).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified workout ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - workouts
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/feedback' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function submitWorkoutFeedback() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/feedback', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/workouts/<WORKOUT_ID>/feedback",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/plans/metadata:
    get:
      operationId: PlansApi_getPlanMetadata
      summary: Get available plan goals and difficulties
      description: |-

        Retrieves all fitness goals and difficulty levels available across training plans.

        **Use this endpoint to populate:**
        - `goalIds` parameter in `POST /v1/orgs/{orgId}/plans/generate`
        - Plan goal filters in your application UI

        **Response includes:**
        - `goals`: Array of {id, name} for each fitness goal
        - `difficulties`: Array of difficulty strings (beginner, intermediate, advanced)

        **Example Goals:**
        - Lose weight (63c92926f920a9005c4e619c)
        - Build strength (63c92926f920a9005c4e619d)
        - Improve endurance (63c92926f920a9005c4e619e)
        - Increase mobility (63c92926f920a9005c4e619f)
        - Get toned (63c92926f920a9005c4e61a0)
        - Physiotherapy (63c92926f920a9005c4e61a1)

        **Related Metadata Endpoints:**
        - `GET /v1/plans/metadata` - Goals & difficulties (for plan generation/filtering)
        - `GET /v1/workouts/metadata` - Categories & difficulties (for workout generation)
        - `GET /v1/workouts/equipment/metadata` - Equipment items & categories
        - `GET /v1/workouts/exercises/metadata` - Muscle groups & collections

        **For Plan Generation:** Call this endpoint + equipment/metadata
        **For Workout Generation:** Call workouts/metadata + equipment/metadata + exercises/metadata (advanced)

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Goal names

        ---

        **Related Endpoints:**
        - Generate: `POST /v1/orgs/{orgId}/plans/generate`
        - List: `GET /v1/orgs/{orgId}/plans`
        - Recommend: `POST /v1/orgs/{orgId}/plans/recommend`
            
      parameters:
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved plan goals and difficulty lists.
          content:
            application/json:
              schema:
                type: object
                properties:
                  goals:
                    type: array
                    description: List of all available plan goals.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          description: Goal ID
                          example: 63c92926f920a9005c4e619c
                        name:
                          type: string
                          description: Goal display name
                          example: Lose weight
                      required:
                        - id
                        - name
                  difficulties:
                    type: array
                    description: List of all available plan difficulty levels.
                    items:
                      type: string
                      example: intermediate
                example:
                  goals:
                    - id: 63c92926f920a9005c4e619c
                      name: Lose weight
                    - id: 63c92926f920a9005c4e619d
                      name: Build strength
                    - id: 63c92926f920a9005c4e619e
                      name: Improve endurance
                  difficulties:
                    - beginner
                    - intermediate
                    - advanced
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/plans/metadata' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getPlanMetadata() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/plans/metadata', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/plans/metadata", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/plans/{planId}:
    get:
      operationId: PlansApi_getPlan
      summary: Get training plan details
      description: |-

        ## Complete Training Plan Details

        Retrieves comprehensive information about a specific multi-week training program including metadata, goals, and trainer information.

        ---

        ### 📋 What's Included

        | Field | Description | Example |
        |-------|-------------|---------|
        | **Core Info** | Name, description, difficulty, visibility | "4-Week Strength Builder", intermediate, public |
        | **Program Duration** | Duration in weeks and workouts per week | 8 weeks, 3 workouts/week |
        | **Goals** | Primary fitness objectives | ["Build Strength", "Increase Endurance"] |
        | **Trainer** | Coach name and ID | "Sarah Johnson", trainer123 |
        | **Preview** | Video and thumbnail links | HLS stream URL, poster image |
        | **Share Link** | Shareable URL for the plan | https://app.hyperhuman.cc/plans/... |
        | **Organization** | Team/brand information (if applicable) | Logo URL, organization name |

        **Note:** To get the workouts in this plan, call `GET /v1/plans/{id}/workouts`

        ---

        ### 🎯 Use Cases

        ✅ **Plan Preview** - Show details before starting program  
        ✅ **Goal Alignment** - Match plan goals to user objectives  
        ✅ **Trainer Information** - Display coach name and credentials  
        ✅ **Program Overview** - Understand plan structure and goals  
        ✅ **Duration Planning** - Display program length and weekly commitment  
        ✅ **Program Comparison** - Compare different program durations and intensities

        ---

        ### ⏱️ Program Duration Fields

        The response includes two key duration fields:

        - **`durationInWeeks`**: Total program duration (1-24 weeks)
        - **`workoutsPerWeek`**: Weekly workout frequency (1-7 workouts)

        **Example Response:**
        ```json
        {
          "data": {
            "id": "64f1a2b3c4d5e6f7a8b9c0d2",
            "name": "8-Week Strength Program",
            "description": "A comprehensive strength building program",
            "difficulty": "intermediate",
            "visibility": "public",
            "durationInWeeks": 8,
            "workoutsPerWeek": 3,
            "goals": [...],
            "trainer": {...},
            "preview": {...}
          }
        }
        ```

        ---

        ### 🔄 Integration Flow

        1. **Browse Plans**: `GET /v1/orgs/{orgId}/plans` → Get plan list (with duration filters)
        2. **Get Plan Details**: `GET /v1/plans/{id}` → **This endpoint** (full details including duration)
        3. **Get Workouts**: `GET /v1/plans/{id}/workouts` → Associated workouts list
        4. **Start Program**: Begin first workout in sequence
        5. **Track Progress**: Monitor completion across weeks

        ---

        ### 🌍 Localization

        Content localized based on `locale` query parameter:
        - **Supported**: 13 languages (en-US, fr-FR, de-DE, es-ES, etc.)
        - **Fallback**: English if locale unsupported
        - **Affects**: Plan name, description, goal names

        ---

        ### 🔗 Related Endpoints

        - Plan List: `GET /v1/orgs/{orgId}/plans` - Browse organization plans (with duration filtering)
        - Plan Workouts: `GET /v1/plans/{id}/workouts` - Get associated workouts
        - Plan Metadata: `GET /v1/plans/metadata` - Get goals and difficulties
        - Generate Plan: `POST /v1/orgs/{orgId}/plans/generate` - Create new plan with duration
        - Filter Plans: `GET /v1/orgs/{orgId}/plans?durationInWeeks=8&workoutsPerWeek=3` - Find specific duration programs
            
      parameters:
        - name: planId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout plan to retrieve.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: Preferred language locale for localized content (e.g., en-US, fr-FR, de-DE). Affects plan name, description, and goal names.
          example: en-US
          schema:
            type: string
            enum:
              - en-US
              - en-GB
              - en-AU
              - fr-FR
              - de-DE
              - es-ES
              - it-IT
              - pt-PT
              - he-IL
              - ro-RO
              - cs-CZ
              - fi-FI
              - nl-NL
      responses:
        '200':
          description: Workout plan details retrieved successfully with duration information.
          content:
            application/json:
              examples:
                8-week-program:
                  summary: 8-Week Strength Program
                  description: Example of an 8-week program with 3 workouts per week
                  value:
                    data:
                      id: 64f1a2b3c4d5e6f7a8b9c0d2
                      name: 8-Week Strength Program
                      description: A comprehensive strength building program designed for intermediate fitness levels
                      difficulty: intermediate
                      visibility: public
                      durationInWeeks: 8
                      workoutsPerWeek: 3
                      goals:
                        - id: 64f1a2b3c4d5e6f7a8b9c0d3
                          name: Build Strength
                          nameTranslations: {}
                      trainer:
                        id: 64f1a2b3c4d5e6f7a8b9c0d4
                        name: Sarah Johnson
                      preview:
                        url: https://stream.hyperhuman.cc/plan-preview.m3u8
                        poster: https://images.hyperhuman.cc/plan-poster.jpg
                        thumbnail: https://images.hyperhuman.cc/plan-thumb.jpg
                      shareLink:
                        url: https://app.hyperhuman.cc/plans/64f1a2b3c4d5e6f7a8b9c0d2
                      organization:
                        id: org-hyperhuman-llc
                        name: Hyperhuman LLC
                        logo:
                          url: https://images.hyperhuman.cc/logo.png
                12-week-program:
                  summary: 12-Week Transformation Program
                  description: Example of a longer 12-week program with 4 workouts per week
                  value:
                    data:
                      id: 64f1a2b3c4d5e6f7a8b9c0d5
                      name: 12-Week Transformation Program
                      description: An intensive 12-week program for advanced fitness levels
                      difficulty: advanced
                      visibility: public
                      durationInWeeks: 12
                      workoutsPerWeek: 4
                      goals:
                        - id: 64f1a2b3c4d5e6f7a8b9c0d6
                          name: Weight Loss
                          nameTranslations: {}
                        - id: 64f1a2b3c4d5e6f7a8b9c0d7
                          name: Build Muscle
                          nameTranslations: {}
                      trainer:
                        id: 64f1a2b3c4d5e6f7a8b9c0d8
                        name: Mike Chen
                      preview:
                        url: https://stream.hyperhuman.cc/transformation-preview.m3u8
                        poster: https://images.hyperhuman.cc/transformation-poster.jpg
                        thumbnail: https://images.hyperhuman.cc/transformation-thumb.jpg
                      shareLink:
                        url: https://app.hyperhuman.cc/plans/64f1a2b3c4d5e6f7a8b9c0d5
                      organization: null
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified plan ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getPlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/plans/{planId}/workouts:
    get:
      operationId: PlansApi_getPlanWorkouts
      summary: Get workouts in training plan
      description: |-

        ## Plan Workout Collection

        Retrieves the complete list of workouts that comprise a specific training plan, ordered as they appear in the program sequence.

        ---

        ### 🎯 Plan Context

        | Aspect | Plan Workouts | General Workouts |
        |--------|---------------|------------------|
        | **Ordering** | Sequential program flow | Alphabetical/date |
        | **Progression** | Structured difficulty curve | Independent difficulty |
        | **Coherence** | Designed to work together | Standalone sessions |
        | **Collection** | Returns all workouts in plan | Filtered/paginated results |

        ---

        ### 📋 Use Cases

        ✅ **Program Navigation** - Browse workouts in sequence  
        ✅ **Progress Tracking** - Show completed vs remaining workouts  
        ✅ **Workout Preview** - Display individual workout details  
        ✅ **Plan Management** - Admin oversight of program content

        ---

        ### 🔍 Response Structure

        **Returns:**
        - Complete list of ALL workouts in the plan (no pagination)
        - Workouts ordered as designed in the plan sequence
        - Each workout includes: name, duration, difficulty, categories, trainer, preview

        **Note:** This endpoint returns all workouts at once. For plans with many workouts, consider implementing client-side pagination for display purposes.

        ---

        ### 💡 Best Practices

        ✅ **Respect workout order** - Maintain the sequence returned by the API  
        ✅ **Show progress** - Track which workouts user has completed  
        ✅ **Fetch workout details** - Call `GET /v1/workouts/{id}` for full details  
        ✅ **Cache workout list** - Workout order rarely changes within a plan  
        ✅ **Client-side pagination** - Implement display pagination if needed

        ---

        ### 🔗 Related Endpoints

        - Plan Details: `GET /v1/plans/{id}` - Get plan information
        - Workout Details: `GET /v1/workouts/{id}` - Get individual workout
        - Start Session: `POST /v1/workouts/{id}/sessions/start` - Begin workout
        - Plan List: `GET /v1/orgs/{orgId}/plans` - Browse all plans
            
      parameters:
        - name: planId
          required: true
          in: path
          description: The unique identifier (UUID) of the workout plan.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: Preferred language locale (e.g., fr-FR)
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved complete list of workouts for the plan.
          schema:
            example:
              data:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  name: Upper Body Strength
                  description: Focus on chest, shoulders, and arms
                  duration: 2700
                  difficulty: intermediate
                  visibility: public
                  locked: false
                  createdAt: '2023-10-26T10:00:00.000Z'
                  updatedAt: '2023-10-27T11:30:00.000Z'
                  trainer:
                    id: 64f1a2b3c4d5e6f7a8b9c0d4
                    name: Sarah Johnson
                  categories:
                    - id: 615aa3dadbe7140012c59e90
                      name: Strength
                  preview:
                    url: https://stream.hyperhuman.cc/workout-preview.m3u8
                    poster: https://images.hyperhuman.cc/workout-poster.jpg
                    thumbnail: https://images.hyperhuman.cc/workout-thumb.jpg
                  images:
                    thumbnail: https://images.hyperhuman.cc/workout-thumb.jpg
                  rating: 4.5
                  mixBgMusic: true
                  presentationStyle: full
                  allowAssessment: false
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  name: Lower Body Power
                  description: Intense leg and glute workout
                  duration: 2400
                  difficulty: intermediate
                  visibility: public
                  locked: false
                  createdAt: '2023-10-26T10:00:00.000Z'
                  updatedAt: '2023-10-27T11:30:00.000Z'
                  trainer:
                    id: 64f1a2b3c4d5e6f7a8b9c0d4
                    name: Sarah Johnson
                  categories:
                    - id: 615aa3dadbe7140012c59e90
                      name: Strength
                  preview:
                    url: https://stream.hyperhuman.cc/workout-preview-2.m3u8
                    poster: https://images.hyperhuman.cc/workout-poster-2.jpg
                    thumbnail: https://images.hyperhuman.cc/workout-thumb-2.jpg
                  images:
                    thumbnail: https://images.hyperhuman.cc/workout-thumb-2.jpg
                  rating: 4.7
                  mixBgMusic: true
                  presentationStyle: full
                  allowAssessment: false
              pagination:
                page: 1
                limit: 20
                total: 24
                pages: 2
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkoutListResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified plan ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>/workouts' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getPlanWorkouts() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>/workouts', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/plans/<PLAN_ID>/workouts", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/video-assets:
    get:
      operationId: OrganizationExercisesApi_getOrganizationExercises
      summary: List workspace exercise videos for an organization
      description: |-

        ## Workspace Exercise Library

        Paginated **published** workspace exercise videos for `organizationId` - previews, metadata, and creator references for catalogs, workout builders, and players. Sorted newest first.

        ---

        ### What you get

        Only the videos this workspace uploaded itself. Use it to power your in-product catalog, workout builder, or video player with content you own.

        - `trainer` - the workspace member who uploaded the asset
        - `organization` - the workspace you queried, repeated on every row

        ---

        ### Video type guide

        | Video type | API `kind` | Audio behavior | Playback notes |
        |---|---|---|---|
        | **EXERCISE** - Smart video for flexible workout building | `single-exercise` | **Original audio removed; multilingual instructions in `audioInstructions[]`** | Configurable reps or duration in workout builder; auto-loops to match your configured time; shows exercise labels and overlays in player |
        | **ORIGINAL** - Video plays as uploaded | `multi-exercise` (no separate `original` enum) | Original audio preserved on the video | Plays once from start to finish; added to workouts as-is |
        | **PROMO** - Clean playback for branding | `promo` | Original audio preserved on the video | No exercise overlays or labels; great for intros, outros, or splash screens |
        | **TUTORIAL** - Educational content | `educational` | Original audio with instructor explanations | Perfect for explaining proper form and technique; great for beginners or complex movements |
        | **CLASS** - Long-format instructor-led workout | `class` | Original audio with instructor guidance | Complete workout session format; ideal for yoga, pilates, dance, or instructor-led classes |

        ---

        ### Pagination

        - `offset` - number of items to skip (default: `0`)
        - `limit` - items per page (service default: `10`, max: `50`)
        - Prefer following `links.next` from the response over computing offsets manually

        ---

        ### Filtering

        All filters AND-combine; multi-value filters are OR-internally (`$in`). Every filter is applied at the DB level so `links.total` stays exact.

        | Param | Type | Behavior |
        |---|---|---|
        | `q` | string | Case-insensitive substring on `name`. With `?locale=`, also matches the locale-specific name. |
        | `equipmentIds` | CSV of 24-hex ids | Returns assets whose `equipment[]` includes ANY id. |
        | `muscleGroupIds` | CSV of 24-hex ids | Returns assets whose `muscleGroups[]` includes ANY id. |
        | `kinds` | CSV of `VideoAssetKind` | See **Video type guide** above for the product-name mapping. |
        | `skillLevels` | CSV of `SkillLevel` | `beginner` / `intermediate` / `advanced`. |
        | `executionSides` | CSV of `ExecutionSide` | `both` / `left` / `right` / `alternating`. |
        | `coach` | `male` / `female` | Single value. |
        | `collectionNames` | CSV of strings | Exact match (case-sensitive); rows with empty `collectionName` are excluded when set. |

        Bad values (non-hex ids, unknown enum members, empty CSV) return `400 ValidationError` with the offending field in `error.target`.

        ---

        ### Sorting

        Use `?sort=` with `+` / `-` prefix and comma-separated multi-keys.

        | Public name | DB field | Notes |
        |---|---|---|
        | `date` (alias of `createdAt`) | `createdAt` | Default: `-date` (newest first). |
        | `name` | `name` | Sorts by canonical `name`. Locale-aware sort is not yet supported. |
        | `kind` | `kind` | Useful for grouping; pair with `+name` for stable secondary order. |

        Examples: `?sort=-date`, `?sort=+name`, `?sort=-kind,+name`. Unknown fields return `400 ValidationError`.

        ---

        ### Localization

        Optional `locale` (BCP-47, e.g. `en-US`) localizes:

        - `name`
        - `muscleGroups[].name`
        - `equipment[].name`
        - `audioInstructions[]` (see below)

        When omitted, raw values fall back to English. Full supported locale list: see `AGENTS.md` section 5.

        ---

        ### Audio instructions (`audioInstructions[]`)

        Populated **only** for `kind: single-exercise` rows - the smart-clip product type that strips original audio in favor of multilingual instructions.

        - **With `?locale=`** - items narrow to matching locales via the standard locale chain (English fallback)
        - **Without `?locale=`** - returns **all** available locales so catalog UIs can render a "narrated in N languages" indicator
        - **Other kinds** (`multi-exercise`, `educational`, `promo`, `class`) keep their original audio baked into the video and return `[]`

        Each entry carries:

        - `id` - audio resource id (24-character hex)
        - `createdAt` - ISO 8601 timestamp
        - `assetUri` - **short-lived presigned URL** to the encoded MP4A clip (do not cache long-term; refresh by re-listing)
        - `type` - audio role; for instruction tracks this is `exerciseInstruction`
        - `locale` - BCP-47 tag of this specific track (e.g. `en-US`, `fr-FR`)
        - `scriptText` *(optional)* - **verbatim transcript** the narrator reads in `assetUri`. Use it for closed captions, accessibility overlays, search indexing, and AI summarization. Omitted on single exercise clips with no intructions at all, no text based instructions or having recorded or audio file instructions - **always null-check** before rendering.

        Full per-asset audio (cues + instructions, including `scriptText` per track) is exposed on the per-asset detail endpoint when listed in `/openapi.json`.

        ---

        ### Related Endpoints

        - Micro Workouts: `GET /v1/orgs/{organizationId}/groups` - circuit / sets-based collections built on top of these exercises
        - Workout Metadata: `GET /v1/workouts/metadata` - categories and difficulties shared across the catalog
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: Unique organization (workspace) resource id for Hyperhuman Teams - opaque 24-character hex string.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Maximum number of items to return per page.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: q
          required: false
          in: query
          description: Search text
          schema:
            type: string
        - name: sort
          required: false
          in: query
          description: 'Sortable fields (use `+` / `-` prefix, comma-separated for multi-key). Allowed: `date` (alias of `createdAt`), `name`, `kind`. Default: `-date` (newest first). Examples: `-date`, `+name`, `-kind,+name`.'
          example: '-date'
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US). Localizes text and locale-aware media when supported; falls back to English.
          example: en-US
          schema:
            type: string
        - name: equipmentIds
          required: false
          in: query
          description: Comma-separated equipment ids (24-character hex). Returns assets whose `equipment[]` includes ANY of these.
          example: 60d21b4667d0d8992e610c90,60d21b4667d0d8992e610c91
          schema:
            type: string
        - name: muscleGroupIds
          required: false
          in: query
          description: Comma-separated muscle-group ids (24-character hex). Returns assets whose `muscleGroups[]` includes ANY of these.
          example: 60d21b4667d0d8992e610c85
          schema:
            type: string
        - name: kinds
          required: false
          in: query
          description: 'Comma-separated video kinds. Allowed: `single-exercise`, `multi-exercise`, `class`, `promo`, `educational`. See the **Video type guide** in the endpoint description for product-name-to-`kind` mapping.'
          example: single-exercise,educational
          schema:
            type: string
        - name: skillLevels
          required: false
          in: query
          description: 'Comma-separated skill levels. Allowed: `beginner`, `intermediate`, `advanced`.'
          example: beginner,intermediate
          schema:
            type: string
        - name: executionSides
          required: false
          in: query
          description: 'Comma-separated execution sides. Allowed: `both`, `left`, `right`, `alternating`.'
          example: both,alternating
          schema:
            type: string
        - name: coach
          required: false
          in: query
          description: Coach gender as recorded on the asset.
          example: female
          schema:
            enum:
              - male
              - female
            type: string
        - name: collectionNames
          required: false
          in: query
          description: Comma-separated collection names (exact match, case-sensitive). Rows with empty `collectionName` are excluded when this filter is set.
          example: Morning cardio,Yoga flow
          schema:
            type: string
      responses:
        '200':
          description: Paginated workspace exercise videos with previews and metadata.
          schema:
            example:
              data:
                - id: 60812dea606fc90011eb4405
                  createdAt: '2025-09-15T10:30:00Z'
                  name: Jumping Jacks
                  kind: single-exercise
                  trainer:
                    id: 63a1c2b4f0e1a200126616a1
                    name: Sarah Johnson
                  muscleGroups:
                    - id: 60d21b4667d0d8992e610c85
                      name: Full Body
                  equipment:
                    - id: 60d21b4667d0d8992e610c90
                      name: Bodyweight
                  preview:
                    url: https://stream.hyperhuman.cc/video/ex-60812dea/master.m3u8?token=...
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea.jpg
                  playsInLoop: true
                  organization:
                    id: 63415bf67a9c7000126616c1
                    name: My Gym
                    logo:
                      url: https://hhcontent.s3.eu-central-1.amazonaws.com/logos/org-63415bf67a9c7000126616c1.png
                  audioInstructions:
                    - id: 65a1b2c3d4e5f600126616a1
                      createdAt: '2025-09-15T10:31:00Z'
                      assetUri: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/inst-60812dea-en-US.m4a?token=...
                      type: exerciseInstruction
                      locale: en-US
                      scriptText: Stand tall with your feet shoulder-width apart. Jump up while raising your arms overhead and spreading your legs out to the sides.
                    - id: 65a1b2c3d4e5f600126616a2
                      createdAt: '2025-09-15T10:31:00Z'
                      assetUri: https://hhcontent.s3.eu-central-1.amazonaws.com/audio/inst-60812dea-fr-FR.m4a?token=...
                      type: exerciseInstruction
                      locale: fr-FR
                      scriptText: Tenez-vous droit, pieds écartés à la largeur des épaules. Sautez en levant les bras au-dessus de la tête et en écartant les jambes sur les côtés.
                  skillLevel: beginner
                  tags:
                    - warmup
                  collectionName: Morning cardio
              links:
                next: https://content.api.hyperhuman.cc/v1/orgs/63415bf67a9c7000126616c1/video-assets?limit=10&offset=10
                total: 142
              explanation: Published exercise videos from your workspace.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VideoAssetsListResponse'
        '400':
          description: Request validation failed. `error.code` is `ValidationError`; `error.target` is the DTO class name; `error.details[]` lists the offending fields.
          schema:
            example:
              error:
                code: ValidationError
                message: ValidationError
                target: GetVideoAssetsByOrganizationIdParams
                details:
                  - code: ConstraintError
                    message: organizationId must be a mongodb id
                    target: organizationId
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing, malformed, or unknown `X-Api-Key` header.
          schema:
            example:
              error:
                code: Unauthorized
                message: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is valid but is not authorized for this `organizationId` (the key belongs to a different workspace, or no API key was sent on a guarded route).
          schema:
            example:
              error:
                code: Forbidden
                message: API key not authorized for this organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: No workspace exists for the supplied `organizationId`.
          schema:
            example:
              error:
                code: NotFound
                message: Organization not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - library-exercises
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/video-assets' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationExercises() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/video-assets', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/video-assets", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/groups:
    get:
      operationId: OrganizationExerciseGroupsApi_getOrganizationExerciseGroups
      summary: List organization micro workouts (exercise groups)
      description: |-

        ## Micro Workouts (Exercise Groups)

        **Micro workouts** are short, focused exercise collections designed for quick sessions. Use these endpoints to surface them in your app.

        Retrieves paginated list of exercise collections (micro workouts) for your organization. Each collection has simple execution details: circuit or sets format, rounds, rest periods, and per-exercise config (time-based or reps-based).

        ---

        ### Use Cases

        - **White-label Apps** - Show organization micro workouts
        - **Quick Workout Browsing** - Circuit and sets-based collections
        - **Integration with Workouts** - Collections can be used in workout generation (excludeExerciseCollections)

        ---

        ### Execution Details (per collection)

        - **kind**: circuit | sets
        - **rounds**: Number of rounds
        - **roundBreakDuration**: Rest between rounds (ms)
        - **exerciseBreakDuration**: Rest between exercises (ms)
        - **exerciseConfig**: timeBasedConfig (duration, pace, rpe, amrap) or repsBasedConfig (reps, weightLevel, pace, rpe)

        ---

        ### Filtering and Pagination

        **Visibility:**
        - `public` - Publicly accessible collections (default)
        - `private` - Organization-only (requires API key for same org)
        - `all` - Both (requires API key for same org)

        **Pagination:**
        - `offset` - Pagination offset (default: 0)
        - `limit` - Items per page (default: 10, max: 50)

        ---

        ### Related Endpoints

        - Get Group Detail: `GET /v1/orgs/{orgId}/groups/{groupId}` - Full detail with execution config
        - Get Group Exercises: `GET /v1/orgs/{orgId}/groups/{groupId}/exercises` - Exercises in collection
        - List Workouts: `GET /v1/orgs/{orgId}/workouts` - Organization workouts
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Items per page. Defaults to 10, max 50.
          example: 10
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US, fr-FR). Localizes text and locale-aware media when this operation supports it. Falls back to English when unsupported.
          example: en-US
          schema:
            type: string
        - name: visibility
          required: false
          in: query
          description: Filter groups by their visibility status.
          example: public
          schema:
            enum:
              - private
              - public
              - all
            type: string
        - name: offset
          required: false
          in: query
          description: Pagination offset. Defaults to 0.
          example: 0
          schema:
            type: number
      responses:
        '200':
          description: Successfully retrieved paginated list of micro workouts (exercise collections).
          schema:
            example:
              data:
                - id: 507f1f77bcf86cd799439011
                  createdAt: '2025-09-15T10:30:00Z'
                  updatedAt: '2025-09-16T14:20:00Z'
                  name: Quick HIIT Circuit
                  kind: circuit
                  preview:
                    url: https://stream.hyperhuman.cc/video/group-507f1f77/master.m3u8?token=...
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f77.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f77.jpg
                  rounds: 3
                  roundBreakDuration: 10000
                  exerciseBreakDuration: 0
                  exerciseConfig:
                    timeBasedConfig:
                      kind: timeBased
                      duration: 30000
                      pace: medium
                      rpe: 7
                      amrap: false
                  trainer:
                    id: trainer123
                    name: Sarah Johnson
                - id: 507f1f77bcf86cd799439012
                  createdAt: '2025-09-10T08:00:00Z'
                  updatedAt: '2025-09-12T11:15:00Z'
                  name: Upper Body Sets
                  kind: sets
                  preview:
                    url: https://stream.hyperhuman.cc/video/group-507f1f78/master.m3u8?token=...
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f78.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f78.jpg
                  rounds: 2
                  roundBreakDuration: 60000
                  exerciseBreakDuration: 15000
                  exerciseConfig:
                    repsBasedConfig:
                      kind: repsBased
                      reps: 12
                      weightLevel: medium
                      pace: medium
                      rpe: 8
                  trainer:
                    id: trainer456
                    name: Mike Chen
              links:
                next: https://content.api.hyperhuman.cc/v1/orgs/63415bf67a9c7000126616c1/groups?limit=10&offset=10
                total: 24
              explanation: Your organization micro workouts - circuit and sets-based collections for quick sessions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupListResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key not authorized for this organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - exercise-groups
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationExerciseGroups() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/groups/{groupId}:
    get:
      operationId: OrganizationExerciseGroupsApi_getOrganizationExerciseGroupById
      summary: Get micro workout (exercise group) by ID
      description: |-

        ## Micro Workout Detail

        Returns full detail for a micro workout (exercise collection) belonging to your organization. Includes execution config (circuit/sets, rounds, rest, time-based or reps-based per exercise).

        **Response structure:**
        - `kind` - circuit | sets
        - `rounds`, `roundBreakDuration`, `exerciseBreakDuration`
        - `exerciseConfig` - timeBasedConfig (duration, pace, rpe, amrap) or repsBasedConfig (reps, weightLevel, pace, rpe)
        - `preview` - Video preview URLs
        - `trainer`, `organization`

        **Access:** Only collections created by organization trainers. Private collections require API key for the same organization.

        ---

        ### Related Endpoints

        - List Collections: `GET /v1/orgs/{orgId}/groups` - Browse organization collections
        - Get Exercises: `GET /v1/orgs/{orgId}/groups/{groupId}/exercises` - Exercises in this collection
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: groupId
          required: true
          in: path
          description: The unique identifier of the exercise collection (group).
          example: 507f1f77bcf86cd799439011
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US, fr-FR). Localizes text and locale-aware media when this operation supports it. Falls back to English when unsupported.
          example: en-US
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved micro workout (exercise collection) detail.
          schema:
            example:
              data:
                id: 507f1f77bcf86cd799439011
                createdAt: '2025-09-15T10:30:00Z'
                updatedAt: '2025-09-16T14:20:00Z'
                name: Quick HIIT Circuit
                kind: circuit
                preview:
                  url: https://stream.hyperhuman.cc/video/group-507f1f77/master.m3u8?token=...
                  poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f77.jpg
                  thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/group-507f1f77.jpg
                rounds: 3
                roundBreakDuration: 10000
                exerciseBreakDuration: 0
                exerciseConfig:
                  timeBasedConfig:
                    kind: timeBased
                    duration: 30000
                    pace: medium
                    rpe: 7
                    amrap: false
                trainer:
                  id: trainer123
                  name: Sarah Johnson
                organization:
                  id: 63415bf67a9c7000126616c1
                  name: My Gym
                  logo:
                    url: https://hhcontent.s3.eu-central-1.amazonaws.com/logos/org-63415bf67a9c7000126616c1.png
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key not authorized for this organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Group not found or not accessible
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - exercise-groups
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationExerciseGroupById() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/groups/{groupId}/exercises:
    get:
      operationId: OrganizationExerciseGroupsApi_getOrganizationGroupExercises
      summary: Get exercises in micro workout
      description: |-

        ## Get Micro Workout Exercises

        Returns the list of exercises in a micro workout (exercise collection). Each exercise includes video preview, metadata (muscle groups, equipment), and trainer info.

        **Use this endpoint to:**
        - Display the exercise sequence for a micro workout
        - Build a preview or playback UI for the collection
        - Get exercise details before starting a session

        ---

        ### Related Endpoints

        - Get Collection: `GET /v1/orgs/{orgId}/groups/{groupId}` - Collection detail with execution config
        - List Collections: `GET /v1/orgs/{orgId}/groups` - Browse organization collections
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: groupId
          required: true
          in: path
          description: The unique identifier of the exercise collection (group) whose exercises are requested.
          example: 507f1f77bcf86cd799439011
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US, fr-FR). Localizes text and locale-aware media when this operation supports it. Falls back to English when unsupported.
          example: en-US
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved list of exercises in the micro workout with instance config (reps, duration, pace, rpe).
          schema:
            example:
              data:
                - id: 60812dea606fc90011eb4405
                  createdAt: '2025-09-15T10:30:00Z'
                  name: Jumping Jacks
                  kind: singleExercise
                  muscleGroups:
                    - id: mg_full_body
                      name: Full Body
                  equipment:
                    - id: eq_bodyweight
                      name: Bodyweight
                  trainer:
                    id: trainer123
                    name: Sarah Johnson
                  preview:
                    url: https://stream.hyperhuman.cc/video/ex-60812dea/master.m3u8?token=...
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea.jpg
                  duration: 30
                  reps: null
                  pace: medium
                  weightLevel: null
                  rpe: 7
                  amrap: false
                - id: 60812dea606fc90011eb4406
                  createdAt: '2025-09-15T10:30:00Z'
                  name: Push-ups
                  kind: singleExercise
                  muscleGroups:
                    - id: mg_chest
                      name: Chest
                  equipment:
                    - id: eq_bodyweight
                      name: Bodyweight
                  trainer:
                    id: trainer123
                    name: Sarah Johnson
                  preview:
                    url: https://stream.hyperhuman.cc/video/ex-60812dea6/master.m3u8?token=...
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea6.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/thumbnails/ex-60812dea6.jpg
                  duration: 24
                  reps: 12
                  pace: medium
                  weightLevel: medium
                  rpe: 8
              links:
                next: null
                total: 5
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GroupExercisesListResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key not authorized for this organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Group not found or not accessible
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - exercise-groups
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>/exercises' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationGroupExercises() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>/exercises', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/groups/<GROUPID>/exercises", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/plans:
    get:
      operationId: OrganizationPlansApi_getOrganizationPlans
      summary: List organization-specific training plans
      description: |-

        ## Organization Training Plans

        Retrieves paginated list of multi-week training programs specific to your organization.

        **Note:** DTOs reference `WorkoutCollection` types - this is the same as "Plan" (historical naming).

        ---

        ### 🔄 Choose Your Endpoint

        | Need | Use | Speed | Result |
        |------|-----|-------|--------|
        | Browse library | `GET /orgs/{id}/plans` | <50ms | Filtered list |
        | Smart match | `POST /plans/recommend` | <100ms | Top 12 matches |
        | Custom program | `POST /plans/generate` | 5-8s | Unique plan |

        **Note:** Generated plans are NOT included in this list - use `GET /v1/plans/{id}` with stored ID.

        ---

        ### 🎯 Organization Context

        | Aspect | Organization Plans | Public Plans |
        |--------|-------------------|--------------|
        | **Content** | Your branded programs | Global library |
        | **Customization** | Team-specific goals | Generic fitness |
        | **Branding** | Your trainers/style | Mixed sources |
        | **Access Control** | Organization members | Public access |

        ---

        ### 📋 Use Cases

        ✅ **White-label Apps** - Show only your organization's content  
        ✅ **Corporate Wellness** - Company-specific fitness programs  
        ✅ **Trainer Platforms** - Personal trainer's program library  
        ✅ **Gym Management** - Facility-specific training plans

        ---

        ### 🔍 Filtering & Pagination

        **Visibility Filtering:**
        - `private` - Organization-only content (requires ownership)
        - `public` - Publicly accessible plans
        - `all` - Both private and public (default)

        **Additional Filters:**
        - `difficulties` - Filter by difficulty levels (comma-separated: beginner,intermediate,advanced)
        - `goalIds` - Filter by goal IDs (comma-separated)
        - `durationInWeeks` - Filter by program duration (e.g., ?durationInWeeks=8)
        - `workoutsPerWeek` - Filter by weekly frequency (e.g., ?workoutsPerWeek=3)
        - `q` - Search by plan name or description

        **Pagination:**
        - `offset` - Number of items to skip (default: 0)
        - `limit` - Items per page (default: 20, max: 50)
        - `sort` - Sort by: createdAt, updatedAt, name, difficulty, durationInWeeks, workoutsPerWeek
        - Prefer following `links.next` from the response over computing offsets manually.

        ---

        ### 💡 Best Practices

        ✅ **Cache responses** - Plans change infrequently  
        ✅ **Filter by visibility** - Use `public` for end-user apps, `all` for management  
        ✅ **Implement search** - Use `q` parameter for name/description filtering  
        ✅ **Handle empty results** - Graceful fallback to public plans

        ---

        ### 🔗 Related Endpoints

        - Generate Plan: `POST /v1/orgs/{orgId}/plans/generate` - Create new plan
        - Plan Details: `GET /v1/plans/{id}` - Get individual plan
        - Plan Metadata: `GET /v1/plans/metadata` - Get goals and difficulties
        - Recommend Plans: `POST /v1/orgs/{orgId}/plans/recommend` - Smart suggestions
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 64f1a2b3c4d5e6f7a8b9c0d1
          schema:
            type: string
        - name: limit
          required: false
          in: query
          description: Maximum number of items to return per page.
          example: 20
          schema:
            minimum: 1
            maximum: 50
            default: 20
            type: number
        - name: q
          required: false
          in: query
          description: Search text
          schema:
            type: string
        - name: sort
          required: false
          in: query
          description: 'Fields to sort. Prefix them with - (descending) or + (ascending): +someField,-otherField'
          schema:
            type: string
        - name: locale
          required: false
          in: query
          description: BCP-47 locale (e.g. en-US, fr-FR). Localizes text and locale-aware media when this operation supports it. Falls back to English when unsupported.
          example: en-US
          schema:
            type: string
        - name: visibility
          required: false
          in: query
          description: Filter plans by their visibility status.
          example: public
          schema:
            enum:
              - private
              - public
              - all
            type: string
        - name: difficulty
          required: false
          in: query
          description: 'Filter plans by difficulty level (single value). DEPRECATED: Use ''difficulties'' for multiple values.'
          example: intermediate
          deprecated: true
          schema:
            enum:
              - beginner
              - intermediate
              - advanced
            type: string
        - name: difficulties
          required: false
          in: query
          description: Filter plans by one or more difficulty levels (comma-separated). Preferred over 'difficulty'.
          example: beginner,intermediate
          schema:
            type: string
        - name: goalIds
          required: false
          in: query
          description: Filter plans by one or more goal IDs (provide comma-separated values if multiple).
          example: 64f1a2b3c4d5e6f7a8b9c0d3,64f1a2b3c4d5e6f7a8b9c0d7
          schema:
            type: string
        - name: durationInWeeks
          required: false
          in: query
          description: Filter plans by duration in weeks (1-24)
          example: 8
          schema:
            minimum: 1
            maximum: 24
            type: number
        - name: workoutsPerWeek
          required: false
          in: query
          description: Filter plans by workouts per week (1-7)
          example: 3
          schema:
            minimum: 1
            maximum: 7
            type: number
      responses:
        '200':
          description: Successfully retrieved paginated list of plans for the organization.
          schema:
            example:
              data:
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  name: 8-Week Strength Program
                  description: A comprehensive strength building program designed for intermediate fitness levels
                  difficulty: intermediate
                  visibility: public
                  durationInWeeks: 8
                  workoutsPerWeek: 3
                  createdAt: '2023-10-26T10:00:00.000Z'
                  updatedAt: '2023-10-27T11:30:00.000Z'
                  trainer:
                    id: 64f1a2b3c4d5e6f7a8b9c0d4
                    name: Sarah Johnson
                  goals:
                    - id: 64f1a2b3c4d5e6f7a8b9c0d3
                      name: Build Strength
                      nameTranslations: {}
                  preview:
                    url: https://stream.hyperhuman.cc/plan-preview.m3u8
                    poster: https://images.hyperhuman.cc/plan-poster.jpg
                    thumbnail: https://images.hyperhuman.cc/plan-thumb.jpg
                - id: 64f1a2b3c4d5e6f7a8b9c0d5
                  name: 12-Week Transformation Program
                  description: An intensive 12-week program for advanced fitness levels
                  difficulty: advanced
                  visibility: public
                  durationInWeeks: 12
                  workoutsPerWeek: 4
                  createdAt: '2023-10-26T10:00:00.000Z'
                  updatedAt: '2023-10-27T11:30:00.000Z'
                  trainer:
                    id: 64f1a2b3c4d5e6f7a8b9c0d8
                    name: Mike Chen
                  goals:
                    - id: 64f1a2b3c4d5e6f7a8b9c0d6
                      name: Weight Loss
                      nameTranslations: {}
                    - id: 64f1a2b3c4d5e6f7a8b9c0d7
                      name: Build Muscle
                      nameTranslations: {}
                  preview:
                    url: https://stream.hyperhuman.cc/transformation-preview.m3u8
                    poster: https://images.hyperhuman.cc/transformation-poster.jpg
                    thumbnail: https://images.hyperhuman.cc/transformation-thumb.jpg
              links:
                next: https://content.api.hyperhuman.cc/v1/orgs/63415bf67a9c7000126616c1/plans?offset=20&limit=20
                total: 45
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanListResponse'
        '400':
          description: Invalid pagination or filter parameters.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationPlans() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/plans/recommend:
    post:
      operationId: OrganizationPlanRecommendation_getPlanRecommendations
      summary: Get training plan recommendations from existing library
      description: |-

        ## Smart Matching to Existing Training Programs

        Returns ranked multi-week plan suggestions from your organization's library based on user profile analysis.

        ---

        ### 🔄 Choose Your Endpoint

        | Need | Use | Speed | Result |
        |------|-----|-------|--------|
        | Browse library | `GET /orgs/{id}/plans` | <50ms | Filtered list |
        | Smart match | `POST /plans/recommend` | <100ms | Top 12 matches |
        | Custom program | `POST /plans/generate` | 5-8s | Unique plan |

        ---

        ### 🎯 Recommendations vs. Generation

        | Aspect | **Recommendations** (This Endpoint) | **Generation** (`/generate`) |
        |--------|-------------------------------------|-------------------------------|
        | **Speed** | Instant (<100ms) | 3-8 seconds |
        | **Content** | Existing plan library | New, unique programs |
        | **Customization** | Matches to closest fit | Exact specifications |
        | **Use Case** | Browse existing programs | Build custom programs |
        | **Requires** | Pre-built plan library | Just metadata IDs |

        ---

        ### 📋 When to Use Recommendations

        ✅ **Quick discovery** - Show plan options immediately  
        ✅ **Curated programs** - You have expertly designed plans  
        ✅ **Consistency** - Multiple users follow same plan  
        ✅ **Track analytics** - See which plans are popular

        ---

        ### 📋 When to Use Generation

        ✅ **Unique programs** - Every plan is personalized  
        ✅ **Specific goals** - Exact duration, frequency, progression  
        ✅ **No library** - You don't have pre-built plans  
        ✅ **Dynamic content** - New plans every request

        ---

        ### 🔍 How Matching Works

        1. **Analyzes** user profile (age, fitness level, goals, training frequency)
        2. **Scores** each plan in your library (0.0 - 1.0)
        3. **Ranks** by match score
        4. **Returns** top 12 with match reasons

        **Match Factors:**
        - Goal alignment (40% weight)
        - Fitness level match (30% weight)
        - Training frequency compatibility (20% weight)
        - Age appropriateness (10% weight)

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### 🔗 Related Endpoints

        - Generate Plan: `POST /v1/orgs/{orgId}/plans/generate`
        - List Plans: `GET /v1/orgs/{orgId}/plans`
        - Plan Metadata: `GET /v1/plans/metadata`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: Organization/Team unique identifier
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanRecommendationRequestDto'
      responses:
        '200':
          description: Ranked list of recommended training plans with match scores and reasons
          schema:
            example:
              plans:
                - id: 507f1f77bcf86cd799439017
                  name: 8-Week Strength Building Program
                  description: Progressive strength program with balanced muscle group distribution
                  difficulty: intermediate
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/plans/507f1f77bcf86cd799439017/thumbnail.jpg
                  recommendation: Perfect match for your strength goals and intermediate fitness level
                  goals:
                    - id: 63c92926f920a9005c4e619d
                      name: Build Strength
                  preview:
                    url: https://example.com/plan-preview.m3u8
                    poster: https://hhcontent.s3.eu-central-1.amazonaws.com/plans/507f1f77bcf86cd799439017/thumbnail.jpg
                    thumbnail: https://hhcontent.s3.eu-central-1.amazonaws.com/plans/507f1f77bcf86cd799439017/thumbnail.jpg
                - id: 507f1f77bcf86cd799439018
                  name: 12-Week Transformation Program
                  description: Comprehensive program combining strength and cardio for complete transformation
                  difficulty: intermediate
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/plans/507f1f77bcf86cd799439018/thumbnail.jpg
                  recommendation: Matches your goals and training frequency preferences
                  goals:
                    - id: 63c92926f920a9005c4e619c
                      name: Lose Weight
                    - id: 63c92926f920a9005c4e61a0
                      name: Get Toned
                - id: 507f1f77bcf86cd799439019
                  name: 6-Week Beginner Foundation
                  description: Structured program for building fitness fundamentals
                  difficulty: beginner
                  thumbnailUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/plans/507f1f77bcf86cd799439019/thumbnail.jpg
                  recommendation: Ideal starting point for building a consistent training habit
                  goals:
                    - id: 63c92926f920a9005c4e619e
                      name: Improve Endurance
              reasoning: Plans recommended based on your profile and preferences. Top matches align with your fitness goals, current fitness level, and training frequency. The recommendations prioritize programs that match your objectives while considering your training schedule and capabilities.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanRecommendationResponseDto'
        '400':
          description: Bad Request - Invalid input data
        '401':
          description: Unauthorized - Invalid API key
        '404':
          description: Organization/Team not found
      tags:
        - ai-recommendation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/recommend' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getPlanRecommendations() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/recommend', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/recommend",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/plans/generate:
    post:
      operationId: OrganizationPlanGeneration_generatePlan
      summary: Generate personalized training programs based on user profile details, duration preferences, and workout collection sources.
      description: |-

        ## Generate Multi-Week Training Programs

        Create AI-powered, personalized training plans with progressive workout structures.

        ---

        ### ⚠️ CRITICAL: Store the Returned Plan ID

        Generated plans are **NOT** included in `GET /v1/orgs/{orgId}/plans` responses.

        **You MUST store the returned `id` in your database:**
        ```javascript
        const response = await fetch('/v1/orgs/{orgId}/plans/generate', {...});
        const planId = response.id;  // Store this in your database
        await db.userPlans.create({ userId, planId });

        // Later retrieve: GET /v1/plans/{planId}
        ```

        **Retrieval Pattern:**
        - Generated plans: `GET /v1/plans/{id}` with stored ID
        - Organization library: `GET /v1/orgs/{orgId}/plans`

        ---

        ### 🔄 Choose Your Endpoint

        | Need | Use | Speed | Result |
        |------|-----|-------|--------|
        | Browse library | `GET /orgs/{id}/plans` | <50ms | Filtered list |
        | Smart match | `POST /plans/recommend` | <100ms | Top 12 matches |
        | Custom program | `POST /plans/generate` | 5-8s | Unique plan |

        ---

        ### 📋 Quick Start

        1. **Fetch Metadata**: `GET /v1/plans/metadata` → Get goal IDs and difficulties
        2. **Generate Program**: `POST /v1/orgs/{orgId}/plans/generate` → **This endpoint**
        3. **Store Plan ID**: Save the returned `id` to your database/system
        4. **Retrieve Plan**: `GET /v1/plans/{id}` → Use stored ID to access full details
        5. **Get Workouts**: `GET /v1/plans/{id}/workouts` → Get workouts in program

        ---

        ### 🎯 Program Structure

        - **Duration**: 4-52 weeks of structured training
        - **Frequency**: 1-7 workouts per week
        - **Progressive**: Automatic intensity and volume progression
        - **Balanced**: Muscle group distribution across training cycle
        - **Complete**: Full workout details with exercises, sets, reps

        ---

        ### 📦 Workout Collection Sources

        | Source | Description | Use Case |
        |--------|-------------|----------|
        | `template` | Curated platform workout collections | **Recommended for variety** |
        | `team` | Your organization's custom workout collections | Brand consistency |

        **Default**: Uses both if omitted

        ---

        ### 💡 AI Personalization

        - **Goal Alignment**: Structures program based on fitness goals
        - **Difficulty Matching**: Adjusts complexity to user fitness level
        - **Age/Gender Adaptation**: Considers user demographics
        - **Duration Optimization**: Selects ideal program length within your range

        **Advanced Options:**
        - `userRequirements`: High-level context and guidelines for customer-specific training methodologies and program structure (e.g., "Critical: select and use only workouts that are named and contain the word 'minimal'", "Progressive overload with 3-week cycles"). Overrides default AI selection and structure behavior. Max 2000 characters.

        ---

        ### 🎯 What's Generated

        - **Duration**: 4-52 weeks of structured training
        - **Frequency**: 1-7 workouts per week
        - **Personalized**: Matched to age, fitness level, goals, equipment
        - **Progressive**: Automatic intensity progression across weeks
        - **Complete**: Full workout details with exercises

        **Duration Logic:**
        - Both min/max provided → AI selects optimal in range
        - Only one value → Uses as target
        - None → Defaults to 8 weeks

        **User Profile:**
        - Age → Appropriate intensity (16-24 Young, 25-34 Young Adult, 35-44 Early Middle Age, 45-54 Mid Life, 55-64 Late Middle Age, 65-74 Early Senior, 75+ Senior)
        - Fitness level → Uses first level if multiple provided
        - Goals → Structures program around objectives
        - Training days/week → Determines frequency and volume

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### 🔗 Related Endpoints

        - **Metadata**: `GET /v1/plans/metadata` - Get goal IDs and difficulties
        - **Metadata**: `GET /v1/workouts/equipment/metadata` - Get equipment category IDs
        - **Retrieve**: `GET /v1/plans/{id}` - Get generated plan details
        - **List**: `GET /v1/orgs/{orgId}/plans` - Browse organization library
        - **Recommend**: `POST /v1/orgs/{orgId}/plans/recommend` - Smart suggestions (faster)
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
      requestBody:
        required: true
        description: Plan generation request with user profile and preferences.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanGenerationRequestDto'
            examples:
              beginner-weight-loss-4weeks:
                summary: Beginner Weight Loss - 4 Weeks
                description: Beginner program focused on weight loss with 3 workouts per week
                value:
                  endUserProfileDetails:
                    age: 28
                    gender: female
                    fitnessLevels:
                      - beginner
                    goalIds:
                      - 63c92926f920a9005c4e619c
                    trainingDaysPerWeek: 3
                  workoutCollectionSources:
                    - template
                  durationOptions:
                    minWeeks: 4
                    maxWeeks: 4
                  workoutsPerWeek: 3
                  difficulty: beginner
              advanced-strength-8weeks:
                summary: Advanced Strength Building - 8 Weeks
                description: Advanced strength program with 5 workouts per week and equipment preferences
                value:
                  endUserProfileDetails:
                    age: 35
                    gender: male
                    fitnessLevels:
                      - advanced
                    goalIds:
                      - 63c92926f920a9005c4e619d
                      - 63c92926f920a9005c4e61a0
                    trainingDaysPerWeek: 5
                    preferredEquipmentCategoryIds:
                      - 67deb3696a5e49797c122f55
                      - 67deb36a6a5e49797c122f56
                  workoutCollectionSources:
                    - template
                    - team
                  durationOptions:
                    minWeeks: 6
                    maxWeeks: 8
                  workoutsPerWeek: 5
                  difficulty: advanced
                  userRequirements: Progressive overload with 3-week cycles. Include deload weeks every 4th week. Focus on compound movements and strength progression.
              intermediate-endurance-flexible:
                summary: Intermediate Endurance - Flexible Duration
                description: Endurance-focused program with AI-selected optimal duration
                value:
                  endUserProfileDetails:
                    age: 42
                    gender: female
                    fitnessLevels:
                      - intermediate
                    goalIds:
                      - 63c92926f920a9005c4e619e
                    trainingDaysPerWeek: 4
                  workoutCollectionSources:
                    - template
                  durationOptions:
                    minWeeks: 8
                    maxWeeks: 12
                  workoutsPerWeek: 4
                  difficulty: intermediate
              custom-team-plan:
                summary: Custom Team Workout Plan
                description: Use organization's workout collections for brand consistency
                value:
                  endUserProfileDetails:
                    age: 30
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 4
                  workoutCollectionSources:
                    - team
                  durationOptions:
                    minWeeks: 8
                    maxWeeks: 12
                  workoutsPerWeek: 4
              complete-all-parameters:
                summary: Complete Example - All Parameters
                description: Real-world example with ALL available parameters filled out
                value:
                  endUserProfileDetails:
                    age: 32
                    gender: male
                    fitnessLevels:
                      - intermediate
                    goalIds:
                      - 63c92926f920a9005c4e619c
                    trainingDaysPerWeek: 4
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                      - 67deb3696a5e49797c122f55
                    endUserId: 64e3bca9d1b7e600141a9712
                  goalIds:
                    - 63c92926f920a9005c4e619d
                  difficulty: intermediate
                  workoutsPerWeek: 4
                  workoutCollectionSources:
                    - template
                    - team
                  durationOptions:
                    minWeeks: 6
                    maxWeeks: 10
                  userRequirements: 'Progressive overload with 3-week cycles. Include deload weeks every 4th week. Focus on unilateral movements for balance. Critical: select and use only workouts that are named and contain the word "minimal".'
      responses:
        '200':
          description: Successfully generated training program with progressive workout structure.
          schema:
            example:
              id: 507f1f77bcf86cd799439017
              name: 8-Week Strength Building Program
              description: Progressive strength program with balanced muscle group distribution
              difficulty: intermediate
              goalIds:
                - 63c92926f920a9005c4e619d
              durationInWeeks: 8
              workoutsPerWeek: 3
              workouts:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  name: Upper Body Strength
                  duration: 2700
                  difficulty: intermediate
                  description: Focus on chest, back, and arms
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  name: Lower Body Power
                  duration: 2400
                  difficulty: intermediate
                  description: Legs, glutes, and core emphasis
                - id: 64f1a2b3c4d5e6f7a8b9c0d3
                  name: Full Body Conditioning
                  duration: 3000
                  difficulty: intermediate
                  description: Complete body workout with cardio elements
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanGenerationResponseDto'
        '400':
          description: Bad Request - Invalid input parameters.
        '401':
          description: Unauthorized - Invalid API key.
        '403':
          description: Forbidden - API key required or insufficient permissions.
        '404':
          description: Not Found - Organization or other resources not found.
        '500':
          description: Internal Server Error - Failed to generate program.
      tags:
        - ai-generation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/generate' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function generatePlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/generate', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/generate",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/plans/{planId}/adapt:
    post:
      operationId: OrganizationPlanAdaptation_adaptPlan
      summary: Adapt an existing program based on user profile and data
      description: |-

        ## Program Adaptation

        Personalizes an existing training program by modifying the workout schedule based on:
        - User profile (age, fitness level, goals, equipment)
        - Last 60 days of wearable health data (body/sleep/physical scores)
        - Workout feedback and session history
        - User-provided guidance and constraints

        ---

        ### Key Behaviors

        | Scenario | Behavior |
        |----------|----------|
        | **Team-owned program** | Creates a personal copy, original unchanged |
        | **User-generated program** | Updates in place |
        | **Completed workouts** | Never modified, only future workouts adapted |

        ---

        ### What Gets Adapted

        - **Add workouts**: Insert new workouts from library
        - **Remove workouts**: Shorten program or accommodate constraints
        - **Replace workouts**: Substitute with better alternatives
        - **Reshuffle**: Reorder for better progression/recovery

        ---

        ### Adaptation Triggers

        | Data Source | Impact on Adaptation |
        |-------------|---------------------|
        | **Low sleep scores** | Remove intense workouts, add recovery |
        | **Declining physical scores** | Shorten program, easier alternatives |
        | **"Too hard" feedback** | Replace with lower difficulty |
        | **Low completion rate** | Remove workouts to reduce overwhelm |
        | **Injury in userGuidance** | Remove workouts targeting injured area |
        | **Beginner fitness level** | Easier workouts throughout |

        ---

        ### Response Details

        - `wasDuplicated`: true if program was copied from team program
        - `originalProgramId`: ID of original program if duplicated
        - `workouts[].action`: 'kept', 'replaced', or 'added'

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - Generate Program: `POST /v1/orgs/{orgId}/plans/generate`
        - Recommend Program: `POST /v1/orgs/{orgId}/plans/recommend`
        - Get Program: `GET /v1/plans/{id}`
        - List Programs: `GET /v1/orgs/{orgId}/plans`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: Organization/Team ID
          example: 67e2e9d0e23f010013e19dec
          schema:
            type: string
        - name: planId
          required: true
          in: path
          description: Plan ID to adapt
          example: 67e2e9d0e23f010013e19def
          schema:
            type: string
      requestBody:
        required: true
        description: Program adaptation request with user profile and preferences
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanAdaptationRequestDto'
            examples:
              basic-adaptation:
                summary: Basic Adaptation - Intermediate User
                description: Adapt a program for an intermediate fitness level user
                value:
                  endUserProfileDetails:
                    age: 32
                    gender: female
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 4
                  workoutSources:
                    - template
                    - team
              injury-adaptation:
                summary: Adaptation with Injury Guidance
                description: Adapt a program considering user injury
                value:
                  endUserProfileId: 64e3bca9d1b7e600141a9712
                  endUserProfileDetails:
                    age: 45
                    gender: male
                    fitnessLevels:
                      - beginner
                    trainingDaysPerWeek: 3
                  workoutSources:
                    - template
                  userGuidance: I have a knee injury. Please remove high-impact workouts and focus on low-impact alternatives.
              full-personalization:
                summary: Full Personalization with User Data
                description: Adapt using 60-day wearable data and full user profile
                value:
                  endUserProfileId: 64e3bca9d1b7e600141a9712
                  endUserProfileDetails:
                    age: 28
                    gender: female
                    fitnessLevels:
                      - advanced
                    goalIds:
                      - 63c92926f920a9005c4e619c
                    trainingDaysPerWeek: 5
                    preferredEquipmentCategoryIds:
                      - 67deb36a6a5e49797c122f56
                  workoutSources:
                    - template
                    - team
                  userGuidance: My sleep has been poor lately. Please reduce intensity and add more recovery-focused workouts.
              shorten-program:
                summary: Shorten Program
                description: User wants a shorter version of their program
                value:
                  endUserProfileDetails:
                    age: 35
                    gender: male
                    fitnessLevels:
                      - intermediate
                    trainingDaysPerWeek: 3
                  workoutSources:
                    - team
                  userGuidance: I only have time for 3 workouts per week now instead of 5. Please remove workouts to fit my schedule.
      responses:
        '200':
          description: Adapted program with personalized workout modifications
          schema:
            example:
              id: 507f1f77bcf86cd799439020
              name: 'Adapted: 8-Week Strength Building Program'
              description: Personalized strength program adapted for your fitness level and schedule
              difficulty: intermediate
              durationInWeeks: 8
              workoutsPerWeek: 3
              totalWorkouts: 24
              wasDuplicated: true
              originalProgramId: 507f1f77bcf86cd799439017
              adaptationReasoning: Program adapted to match your intermediate fitness level and 3-day training schedule. Removed 2 high-intensity workouts per week to accommodate recovery needs based on your sleep data. Replaced 3 advanced workouts with intermediate alternatives. Added 2 recovery-focused sessions to support your training progression.
              workouts:
                - id: 64f1a2b3c4d5e6f7a8b9c0d1
                  name: Upper Body Strength
                  duration: 2700
                  difficulty: intermediate
                  description: Focus on chest, back, and arms
                  position: 0
                  action: kept
                - id: 64f1a2b3c4d5e6f7a8b9c0d2
                  name: Lower Body Power
                  duration: 2400
                  difficulty: intermediate
                  description: Legs, glutes, and core emphasis
                  position: 1
                  action: kept
                - id: 64f1a2b3c4d5e6f7a8b9c0d3
                  name: Full Body Conditioning - Adapted
                  duration: 3000
                  difficulty: intermediate
                  description: Complete body workout with reduced intensity
                  position: 2
                  action: replaced
                - id: 64f1a2b3c4d5e6f7a8b9c0d4
                  name: Recovery & Mobility
                  duration: 1800
                  difficulty: beginner
                  description: Gentle recovery session for active rest
                  position: 3
                  action: added
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanAdaptationResponseDto'
        '400':
          description: Invalid request or program not found
        '401':
          description: Unauthorized - Invalid API key
        '403':
          description: Forbidden - Cannot adapt programs from other organizations
        '404':
          description: Program or organization not found
      tags:
        - ai-adaptation
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/<PLAN_ID>/adapt' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function adaptPlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/<PLAN_ID>/adapt', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/plans/<PLAN_ID>/adapt",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/metadata:
    get:
      operationId: OrganizationMetadataApi_getOrganizationMetadata
      summary: Get organization metadata
      description: |-

        ## Organization Branding & Configuration

        Retrieves your organization's public metadata including branding, configuration, and client joining settings.

        ---

        ### What's Included

        **Branding:**
        - `name`, `handle`, `description`, `website`
        - `logoUrl` — single pre-derived 320x320 PNG variant served from CDN. There are no other size variants exposed today; resize client-side if you need smaller.
        - `watermarkUrl` — single pre-derived 320x320 PNG variant. Square, transparent background. Used in the embedded player and in rendered video exports.
        - `brandMainColor`, `brandSecondaryColor`, `brandTextColor` (hex strings). Any of these may be `null` if the org has not configured them.

        **Configuration:**
        - `clientsJoinSetting` — `OPEN` | `INVITE_ONLY` | `SUBSCRIPTION_REQUIRED`. For full join-flow context (e.g. paid join, available subscription products), call `GET /v1/orgs/{orgId}/join-options` instead.

        **Module Status (booleans, always present):**
        - `hasAssenseiModuleActive` — Asensei Assessment add-on (real-time AI form analysis on supported exercises). When `false`, AI assessment endpoints will not produce data for this org's content.
        - `hasWearableModuleActive` — ROOK Wearables add-on (Apple Health / Garmin / Fitbit / Oura sync). When `false`, end-user insights pillars that depend on wearables fall back to workout-derived data.
        - `hasWhiteLabelAppActive` — Org has a paid white-label consumer app build. Use this to gate "open in app" deeplinks and white-label-only UI.

        **Identifiers:**
        - `id` — pass to every `/v1/orgs/{organizationId}/...` endpoint.
        - `handle` — URL-friendly slug, may be `null`.

        ---

        ### Common Use Cases

        - **White-label mobile apps** - Fetch branding on app launch and on org switch.
        - **Custom web portals** - Apply organization colors/logo at the document root.
        - **Multi-tenant platforms** - Resolve organization context once per session.
        - **Onboarding flows** - Combine with `/join-options` to render the right CTA.

        ---

        ### Best Practices

        - **Cache metadata** - Treat as essentially-static. Refresh daily or on app restart; a 5-minute in-memory cache is also fine.
        - **Fallback colors** - Always have hard-coded fallbacks; any of the brand color fields may be `null`.
        - **Logo size** - Logo and watermark are served at a fixed 320x320 resolution; downscale in the client if you need smaller.
        - **Module gates** - Drive UI off the `has*ModuleActive` flags rather than trying to infer from feature responses.

        ---

        ### 🔗 Related Endpoints

        - Join Options: `GET /v1/orgs/{orgId}/join-options`
        - Generate Workout: `POST /v1/orgs/{orgId}/workouts/generate`
        - List Workouts: `GET /v1/orgs/{orgId}/workouts`
        - List Plans: `GET /v1/orgs/{orgId}/plans`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved organization metadata with complete branding information.
          schema:
            example:
              id: 63415bf67a9c7000126616c1
              name: DEMO - Brave Fitness Team
              handle: bravefitnessdemo
              logoUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/t/63415bf67a9c7000126616c1/logo/i/logo-320x320.png
              watermarkUrl: https://hhcontent.s3.eu-central-1.amazonaws.com/t/63415bf67a9c7000126616c1/watermark/i/watermark-320x320.png
              description: This is a demo account for showcasing Hyperhuman's AI-powered video production platform made for the health & fitness industry.
              website: https://bogdanpred.wixsite.com/bravefitnessdemo
              brandMainColor: '#eeeb3c'
              brandSecondaryColor: '#F3F8F8'
              brandTextColor: '#ffffff'
              clientsJoinSetting: OPEN
              hasAssenseiModuleActive: false
              hasWearableModuleActive: true
              hasWhiteLabelAppActive: false
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationMetadataResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - organization
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/metadata' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationMetadata() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/metadata', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/metadata", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/join-options:
    get:
      operationId: OrganizationJoinOptionsApi_getOrganizationJoinOptions
      summary: Get organization join options
      description: |-

        ## User Onboarding Configuration

        Retrieves information about how users can join your organization, including join settings, subscription requirements, and available plans.

        ---

        ### 📋 What's Included

        **Join Settings:**
        - `clientsJoinSetting`: OPEN, INVITE_ONLY, or SUBSCRIPTION_REQUIRED
        - `canJoinDirectly`: Boolean flag for self-signup
        - `inviteOnlyMode`: Requires invitation to join
        - `requiresSubscription`: Payment required to access

        **Free Plans:**
        - `hasFreePlanWithAutoJoin`: Free access available
        - `freeJoinOptions`: List of free plans with auto-enrollment
        - `totalProductsAvailable`: Count of subscription products

        ---

        ### 🎯 Join Settings Explained

        | Setting | Description | User Flow |
        |---------|-------------|-----------|
        | **OPEN** | Anyone can join | Self-signup enabled |
        | **INVITE_ONLY** | Requires invitation | Admin must invite |
        | **SUBSCRIPTION_REQUIRED** | Payment required to join | User subscribes for access |

        ---

        ### 💡 Integration Patterns

        **Self-Signup Flow (OPEN):**
        ```
        1. GET /v1/orgs/{orgId}/join-options → Check if open
        2. POST /v1/orgs/{orgId}/endusers/invite → Create user
        3. User receives email/access
        ```

        **Invitation Flow (INVITE_ONLY):**
        ```
        1. Admin invites via dashboard or API
        2. User receives invitation
        3. User accepts and creates account
        ```

        **Subscription Required:**
        ```
        1. GET /v1/orgs/{orgId}/join-options → Check products
        2. Display subscription options to user
        3. User subscribes → Access granted
        ```

        ---

        ### 🔗 Related Endpoints

        - Organization Metadata: `GET /v1/orgs/{orgId}/metadata`
        - Invite Users: `POST /v1/orgs/{orgId}/endusers/invite`
        - Paywall Products: `GET /v1/orgs/{orgId}/paywall/products`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved organization join options and configuration.
          schema:
            example:
              clientsJoinSetting: OPEN
              canJoinDirectly: true
              requiresSubscription: false
              inviteOnlyMode: false
              hasFreePlanWithAutoJoin: false
              freeJoinOptions: []
              totalProductsAvailable: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationJoinOptionsResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - organization
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/join-options' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationJoinOptions() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/join-options', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/join-options", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/plans/active/progress:
    get:
      operationId: OrganizationEndUserPlansApi_getActivePlanProgress
      summary: Get plan progress for an end user
      description: |-

        ## Plan progress

        Returns per-workout progress for the end user's active plan. Keys are position indices (as strings); values include completed, latestCompletionDate, workoutName, difficulty, duration, categories, workoutId, positionInPlan.

        When the end user has no active plan, the endpoint responds with `200 OK` and `{ "data": null }` (rather than 404), so callers can render a "no active plan" state without treating it as an error.

        ---

        ### Related endpoints

        - `GET .../plans/active` - Get active plan details
        - `POST .../plans/start` - Start a plan
        - `POST .../plans/{planId}/end` - End active plan
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The organization id (24-character hex string).
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: The user identifier. Can be email, externalUUID, or internal user ID.
          example: john.doe@acme.com
          schema:
            type: string
      responses:
        '200':
          description: 'Plan progress for the end user, or `data: null` when there is no active plan.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanProgressResponseDto'
        '401':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active/progress' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getActivePlanProgress() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active/progress', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active/progress", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/plans/active:
    get:
      operationId: OrganizationEndUserPlansApi_getActivePlan
      summary: Get active plan for an end user
      description: |-

        ## Active plan

        Returns the end user's active workout plan if any, with schedule (workoutsPerWeek, durationInWeeks, currentWeekNumber, daysSinceStart, completedWorkouts, totalWorkouts, completionPercentage).

        ---

        ### Related endpoints

        - `GET .../plans/active/progress` - Get per-workout progress
        - `POST .../plans/start` - Start a plan
        - `POST .../plans/{planId}/end` - End active plan
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The organization id (24-character hex string).
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: The user identifier. Can be email, externalUUID, or internal user ID.
          example: john.doe@acme.com
          schema:
            type: string
      responses:
        '200':
          description: Active plan or null.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActivePlanResponseDto'
        '401':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getActivePlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/active", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/plans/start:
    post:
      operationId: OrganizationEndUserPlansApi_startPlan
      summary: Start a plan for an end user
      description: |-

        ## Start plan

        Starts the given plan as the end user's active plan. Any existing active plan is deactivated.

        ---

        ### Related endpoints

        - `GET .../plans/active` - Get active plan details
        - `GET .../plans/active/progress` - Get plan progress
        - `POST .../plans/{planId}/end` - End active plan
        - `GET /v1/plans/{id}` - Plan catalog details
        - `GET /v1/plans/{id}/workouts` - Workouts in plan
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The organization id (24-character hex string).
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: The user identifier. Can be email, externalUUID, or internal user ID.
          example: john.doe@acme.com
          schema:
            type: string
      requestBody:
        required: true
        description: Plan ID to start as the active plan.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartPlanBody'
      responses:
        '200':
          description: Plan access record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanResponseDto'
        '401':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/start' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function startPlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/start', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/start",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/plans/{planId}/end:
    post:
      operationId: OrganizationEndUserPlansApi_endPlan
      summary: End an active plan for an end user
      description: |-

        ## End plan

        Ends the specified plan for the end user. The plan must be the user's current active plan. Returns 404 if no active plan matches the given planId.

        ---

        ### Related endpoints

        - `GET .../plans/active` - Get active plan details
        - `GET .../plans/active/progress` - Get plan progress
        - `POST .../plans/start` - Start a plan
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The organization id (24-character hex string).
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: The user identifier. Can be email, externalUUID, or internal user ID.
          example: john.doe@acme.com
          schema:
            type: string
        - name: planId
          required: true
          in: path
          description: The plan ID to end.
          example: 60f1b3b3b3b3b3b3b3b3b3b3
          schema:
            type: string
      responses:
        '200':
          description: Updated plan access record.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlanResponseDto'
        '401':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-plans
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/<PLAN_ID>/end' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function endPlan() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/<PLAN_ID>/end', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/plans/<PLAN_ID>/end", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers:
    get:
      operationId: OrganizationEndUsersApi_getOrganizationEndUsers
      summary: Get organization end users
      description: |-
        Retrieves a paginated list of end users associated with the organization.

        `endUserId` is present only when the API key is for this organization and the end user has an active (non-suspended) team membership.

        ### Pagination
        Use the standard `offset`/`limit` cursors. The response contains the canonical `links` envelope:
        - `links.next` — fully qualified URL for the next page (omitted on the last page)
        - `links.total` — total number of matching end users

        The top-level `total` field is **deprecated** and kept only for backwards compatibility; new integrations should read `links.total` instead.
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
        - name: offset
          required: false
          in: query
          description: Offset for pagination. Defaults to 0.
          schema:
            default: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Number of items per page. Defaults to 20, Max 100.
          schema:
            default: 20
            type: number
        - name: status
          required: false
          in: query
          description: 'Filter clients by status: "active", "suspended", or "all"'
          schema:
            enum:
              - active
              - suspended
              - all
            type: string
        - name: sortBy
          required: false
          in: query
          description: Sort clients by "name", "status", or "joined" (default)
          schema:
            enum:
              - name
              - status
              - joined
            type: string
        - name: sortDirection
          required: false
          in: query
          description: 'Sort direction: "asc" (default) or "desc"'
          schema:
            enum:
              - asc
              - desc
            type: string
      responses:
        '200':
          description: Successfully retrieved list of end users for the organization.
          schema:
            example:
              data:
                - email: john.doe@acme.com
                  externalUUID: ext-user-12345
                  firstName: John
                  lastName: Doe
                  status: active
                  joinedDate: '2025-09-15T10:30:00Z'
                  endUserId: 507f1f77bcf86cd799439011
                - email: jane.smith@acme.com
                  externalUUID: ext-user-67890
                  firstName: Jane
                  lastName: Smith
                  status: suspended
                  joinedDate: '2025-09-20T14:20:00Z'
              links:
                next: https://api.hyperhuman.club/v1/orgs/12ab3efd45c67c1234566cd1/endusers?limit=20&offset=20
                total: 142
              total: 142
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EndUserProfileListResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: The specified organization ID does not exist.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationEndUsers() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers", headers=headers)
            response.raise_for_status()
            print(response.json())
    delete:
      operationId: OrganizationEndUsersApi_removeEndUser
      summary: Remove end user from organization
      description: |-

        ## Permanently Remove User

        Completely removes a user from your organization. This action is **irreversible** and will:

        - Delete all user data and progress
        - Remove access to organization content
        - Clear workout history and sessions
        - Cannot be undone

        ---

        ### ⚠️ Important Considerations

        **Before Removing:**
        - User will lose all progress and data
        - Consider suspending instead for temporary access removal
        - Backup any important user data first
        - Notify user if required by your policies

        **Use Cases:**
        - GDPR compliance (right to be forgotten)
        - Account closure requests
        - Data cleanup and maintenance
        - User requested permanent deletion

        ---

        ### 🔄 Alternative Actions

        **Temporary Removal:**
        - `PUT /v1/orgs/{orgId}/endusers/suspend` - Temporarily disable access
        - User data preserved, can be reactivated later
        - Better for temporary access issues

        **Permanent Removal:**
        - `DELETE /v1/orgs/{orgId}/endusers` - This endpoint
        - Complete data deletion, cannot be undone
        - Use for final account closure

        ---

        ### 💡 Best Practices

        ✅ **Verify user identity** - Double-check email/UUID before deletion  
        ✅ **Consider suspension first** - Try suspend before permanent removal  
        ✅ **Log deletion events** - Track for audit and compliance  
        ✅ **Handle gracefully** - 404 is expected if user already removed  
        ❌ **Don't delete active users** - Consider suspending instead

        ---

        ### 🔗 Related Endpoints

        - Find User: `GET /v1/orgs/{orgId}/endusers/find` - Locate user first
        - Suspend User: `PUT /v1/orgs/{orgId}/endusers/suspend` - Temporary removal
        - Reactivate User: `PUT /v1/orgs/{orgId}/endusers/reactivate` - Restore suspended user
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserIdentifierDto'
      responses:
        '200':
          description: Successfully removed end user from organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: End user not found in the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X DELETE 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function removeEndUser() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers', {
              method: 'DELETE',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.delete(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/invite:
    post:
      operationId: OrganizationEndUsersApi_inviteEndUsers
      summary: Invite end users to organization
      description: |-

        ## Add Users to Your Organization

        Send invitations to one or more end users. Each user receives access to your organization's content and features.

        ---

        ### 📋 Identifier Options

        **Email Only:**
        - User invited via email address
        - Hyperhuman creates account on first login
        - Email must be valid and unique

        **Email + External UUID:**
        - Map to your existing user system
        - Track users across platforms
        - Sync user data between systems
        - **Recommended for integrations**

        ---

        ### 🎯 Typical User Lifecycle

        1. **Invite**: `POST /v1/orgs/{orgId}/endusers/invite` → Add users
        2. **Verify**: `GET /v1/orgs/{orgId}/endusers/find?email=...` → Check status
        3. **List**: `GET /v1/orgs/{orgId}/endusers` → View all users
        4. **Manage**: Suspend/reactivate as needed
        5. **Remove**: `DELETE /v1/orgs/{orgId}/endusers` → Permanent deletion

        ---

        ### 💡 Best Practices

        ✅ **Batch invitations** - Send up to 100 users at once for efficiency  
        ✅ **Use externalUUID** - Map to your user IDs for sync  
        ✅ **Validate emails** - Check format before sending  
        ✅ **Handle failures** - Review failed array for issues  
        ❌ **Don't re-invite** - Check if user exists first

        ---

        ### 🔍 Error Handling

        Common failure reasons:
        - `User already exists` - Email already in organization
        - `Invalid email format` - Email validation failed
        - `Duplicate in batch` - Same email appears twice
        - `Organization quota exceeded` - User limit reached

        ---

        ### 🔗 Related Endpoints

        - Find User: `GET /v1/orgs/{orgId}/endusers/find`
        - List Users: `GET /v1/orgs/{orgId}/endusers`
        - Suspend User: `PUT /v1/orgs/{orgId}/endusers/suspend`
        - Remove User: `DELETE /v1/orgs/{orgId}/endusers`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      requestBody:
        required: true
        description: List of users to invite with optional external UUID mapping for integration with your user system.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InviteEndUsersDto'
            examples:
              single-email-only:
                summary: Single User - Email Only
                description: Invite one user with just an email address
                value:
                  users:
                    - email: john.doe@acme.com
              batch-with-external-ids:
                summary: Batch Invite - With External UUIDs
                description: Invite multiple users and map to your system IDs for synchronization
                value:
                  users:
                    - email: john.doe@acme.com
                      externalUUID: user-12345
                    - email: jane.smith@acme.com
                      externalUUID: user-67890
                    - email: bob.jones@acme.com
                      externalUUID: user-11111
              large-batch:
                summary: Large Batch - 10+ Users
                description: Efficiently invite many users at once (up to 100 per request)
                value:
                  users:
                    - email: user1@acme.com
                      externalUUID: ext-user-1001
                    - email: user2@acme.com
                      externalUUID: ext-user-1002
                    - email: user3@acme.com
                      externalUUID: ext-user-1003
                    - email: user4@acme.com
                      externalUUID: ext-user-1004
                    - email: user5@acme.com
                      externalUUID: ext-user-1005
                    - email: user6@acme.com
                      externalUUID: ext-user-1006
                    - email: user7@acme.com
                      externalUUID: ext-user-1007
                    - email: user8@acme.com
                      externalUUID: ext-user-1008
                    - email: user9@acme.com
                      externalUUID: ext-user-1009
                    - email: user10@acme.com
                      externalUUID: ext-user-1010
      responses:
        '200':
          description: Invitation processing complete. Returns success count, any failures, and optionally invited with endUserId when the user already has an active team membership.
          content:
            application/json:
              schema:
                type: object
                properties:
                  successful:
                    type: number
                    description: Number of successful invitations sent
                    example: 12
                  failed:
                    type: array
                    description: List of failed invitations with error reasons
                    items:
                      type: object
                      properties:
                        email:
                          type: string
                          example: invalid@email
                        reason:
                          type: string
                          example: Invalid email format
                    example:
                      - email: duplicate@acme.com
                        reason: User already exists
                      - email: bad-email
                        reason: Invalid email format
                  invited:
                    type: array
                    description: Successful invites; endUserId present only when the user already has an active team membership.
                    items:
                      type: object
                      properties:
                        email:
                          type: string
                        endUserId:
                          type: string
                          description: Internal user ID; present only for active members.
                example:
                  successful: 12
                  failed:
                    - email: duplicate@acme.com
                      reason: User already exists
                  invited:
                    - email: user1@acme.com
                      endUserId: 507f1f77bcf86cd799439011
                    - email: user2@acme.com
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/invite' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function inviteEndUsers() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/invite', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/invite",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/suspend:
    put:
      operationId: OrganizationEndUsersApi_suspendEndUser
      summary: Suspend end user in organization
      description: |-

        ## Temporarily Suspend User Access

        Suspends a user's access to your organization content while preserving their data and progress. This is a **reversible action** that:

        - Blocks access to workouts and plans
        - Preserves user data and progress
        - Can be reactivated later
        - User cannot log in during suspension

        ---

        ### 🎯 When to Suspend

        **Temporary Access Issues:**
        - Payment/billing problems
        - Policy violations (temporary)
        - Account security concerns
        - User requested break

        **vs. Permanent Removal:**
        - Suspension: Temporary, data preserved
        - Deletion: Permanent, data lost
        - Choose suspension for reversible actions

        ---

        ### 🔄 User Experience During Suspension

        **What Users See:**
        - Cannot access organization content
        - Login blocked with suspension message
        - All data and progress preserved
        - Can be reactivated by admin

        **What Admins Can Do:**
        - View suspended users in user list
        - Reactivate anytime with reactivate endpoint
        - See suspension status in user details
        - Track suspension history

        ---

        ### 💡 Best Practices

        ✅ **Communicate with user** - Explain why and duration  
        ✅ **Set clear policies** - Define suspension criteria  
        ✅ **Monitor suspension duration** - Don't leave users suspended indefinitely  
        ✅ **Use for temporary issues** - Permanent problems may need deletion  
        ✅ **Document reasons** - Track why users were suspended

        ---

        ### 🔗 Related Endpoints

        - Find User: `GET /v1/orgs/{orgId}/endusers/find` - Locate user first
        - Reactivate User: `PUT /v1/orgs/{orgId}/endusers/reactivate` - Restore access
        - Remove User: `DELETE /v1/orgs/{orgId}/endusers` - Permanent deletion
        - List Users: `GET /v1/orgs/{orgId}/endusers` - View all users (including suspended)
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserIdentifierDto'
      responses:
        '200':
          description: Successfully suspended end user in organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: End user not found in the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X PUT 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/suspend' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function suspendEndUser() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/suspend', {
              method: 'PUT',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.put(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/suspend",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/reactivate:
    put:
      operationId: OrganizationEndUsersApi_reactivateEndUser
      summary: Reactivate end user in organization
      description: |-

        ## Restore Suspended User Access

        Reactivates a previously suspended user, restoring full access to your organization content. This action:

        - Restores login access immediately
        - Preserves all user data and progress
        - Returns user to active status
        - Can be done anytime after suspension

        ---

        ### 🎯 When to Reactivate

        **Common Scenarios:**
        - Payment issues resolved
        - Policy violations addressed
        - Security concerns cleared
        - User requested restoration
        - Administrative error correction

        **Prerequisites:**
        - User must be currently suspended
        - Cannot reactivate already active users
        - Cannot reactivate permanently deleted users

        ---

        ### 🔄 User Experience After Reactivation

        **Immediate Access:**
        - User can log in immediately
        - Full access to organization content
        - All previous data and progress intact
        - No data loss from suspension period

        **Status Changes:**
        - User status changes from "suspended" to "active"
        - Appears in active user lists
        - Can participate in workouts and plans
        - Normal user functionality restored

        ---

        ### 💡 Best Practices

        ✅ **Verify suspension reason resolved** - Ensure original issue is fixed  
        ✅ **Communicate with user** - Notify them of reactivation  
        ✅ **Monitor user activity** - Ensure they can access content  
        ✅ **Update user records** - Track reactivation for audit  
        ✅ **Test user access** - Verify login and content access works

        ---

        ### 🔗 Related Endpoints

        - Find User: `GET /v1/orgs/{orgId}/endusers/find` - Check current status
        - Suspend User: `PUT /v1/orgs/{orgId}/endusers/suspend` - Suspend if needed again
        - List Users: `GET /v1/orgs/{orgId}/endusers` - View all users
        - Remove User: `DELETE /v1/orgs/{orgId}/endusers` - Permanent deletion (if needed)
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 12ab3efd45c67c1234566cd1
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserIdentifierDto'
      responses:
        '200':
          description: Successfully reactivated end user in organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: End user not found in the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X PUT 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/reactivate' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function reactivateEndUser() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/reactivate', {
              method: 'PUT',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.put(
                "https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/reactivate",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/find:
    get:
      operationId: OrganizationEndUsersApi_getEndUserById
      summary: Find end user by email or external UUID
      description: |-

        ## Find Specific User

        Retrieve a single user from your organization by email or external UUID. Useful for checking if a user exists before inviting.

        ---

        ### 📋 Identifier Options

        **By Email:**
        ```bash
        GET /v1/orgs/{orgId}/endusers/find?email=john.doe@acme.com
        ```

        **By External UUID:**
        ```bash
        GET /v1/orgs/{orgId}/endusers/find?externalUUID=ext-user-12345
        ```

        **Required:** Must provide either `email` OR `externalUUID` (not both)

        ---

        ### 🎯 Use Cases

        ✅ **Pre-invite Check** - Verify user doesn't exist before inviting  
        ✅ **User Lookup** - Find user details for support queries  
        ✅ **Sync Validation** - Confirm external UUID mapping is correct  
        ✅ **Duplicate Prevention** - Check before creating user in your system

        ---

        ### 💡 Best Practices

        ✅ **Email is case-insensitive** - john@acme.com = John@acme.com  
        ✅ **Use external UUID for integrations** - More reliable than email  
        ✅ **Handle 404 gracefully** - User not found is an expected case  
        ✅ **Cache lookups** - Reduce API calls for frequently accessed users

        ---

        ### 🔗 Related Endpoints

        - Invite Users: `POST /v1/orgs/{orgId}/endusers/invite` - Add new users
        - List Users: `GET /v1/orgs/{orgId}/endusers` - Browse all users
        - Suspend User: `PUT /v1/orgs/{orgId}/endusers/suspend` - Deactivate user
        - Remove User: `DELETE /v1/orgs/{orgId}/endusers` - Permanently delete
            
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: email
          required: false
          in: query
          description: Email address of the user to find (case-insensitive)
          example: john.doe@acme.com
          schema:
            type: string
        - name: externalUUID
          required: false
          in: query
          description: External UUID of the user to find
          example: ext-user-12345
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved end user profile. endUserId is present only when the end user has an active (non-suspended) team membership.
          schema:
            example:
              email: john.doe@acme.com
              externalUUID: ext-user-12345
              firstName: John
              lastName: Doe
              status: active
              joinedDate: '2025-09-15T10:30:00Z'
              endUserId: 507f1f77bcf86cd799439011
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EndUserProfileDto'
        '400':
          description: Missing required identifier (email or externalUUID).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The API key is not associated with the requested organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: End user not found in the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-management
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/find' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getEndUserById() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/find', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/find", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/insights/digest:
    get:
      operationId: UserInsightsApi_getUserDailyDigest
      summary: Get daily AI-powered user insights digest
      description: |-

        ## Daily Health & Fitness Digest

        Returns a personalized daily digest of insight pillars selected from: `health_pulse`, `training`, `recovery`, `movement`, `nutrition`, `body`. The exact set returned depends on which data sources the user has connected and on the current data completeness — typically 3-5 pillars per day.

        Each pillar in the digest is intentionally **summary-only**. Coaching signals such as readiness band, recommended intensity, risk triggers, form cue, why-explanations, and alternative actions are surfaced inside the `headline` and `action` strings, but **are not exposed as separate fields on `InsightPillarDto`**. To get the full coaching context for a single pillar, drill into `GET /v1/orgs/{organizationId}/endusers/{endUserId}/insights/pillars/{pillarType}`.

        ---

        ### Pillars Overview

        | Pillar | Description | Primary Data Source |
        |--------|-------------|---------------------|
        | **Health Pulse** | Overall health status and main driver | Rook wearables / workout adherence |
        | **Training** | Workout progress and next session | Workout sessions, AI assessments |
        | **Recovery** | Sleep and recovery readiness | Rook sleep score / workout intensity |
        | **Movement** | Daily activity and cardio | Rook activity / workout frequency |
        | **Nutrition** | Nutrition quality (when available) | Photo logs (coming soon) |
        | **Body** | Body metrics and momentum | Rook body score / workout streak |

        ---

        ### Status Indicators

        - **Green** (75-100): On track
        - **Yellow** (55-74): Watch it
        - **Red** (0-54): Priority action needed

        ---

        ### Data Completeness

        The `dataCompleteness` field (0-1) indicates how much user data is available:
        - **0.8+**: Full wearable + workout data
        - **0.5-0.8**: Partial data (some wearables or workout history)
        - **<0.5**: Limited data (fallback insights provided)

        ---

        ### Fallback Behavior

        When data is missing:
        - Health Pulse calculates a "Hyperhuman Pulse" from workout adherence
        - Recovery uses workout intensity to estimate readiness
        - Nutrition shows a CTA to start tracking

        ---

        ### Enhanced Coaching Signals

        The digest includes intelligent coaching signals embedded in pillar headlines:

        | Signal | Description | Pillars |
        |--------|-------------|---------|
        | **Readiness** | Push/Maintain/Recover recommendation based on recovery data | Health Pulse, Recovery |
        | **Risk Detection** | Fatigue warning when multiple triggers present | Training |
        | **Form Focus** | Primary technique cue from AI assessments | Training |
        | **Program Pacing** | On track/behind status for weekly goals | Training |

        These signals adjust the `action` field to provide intensity-appropriate recommendations based on current readiness state.

        ---

        ### Use Cases

        - Daily digest screen in mobile app
        - Coach dashboard for client overview
        - Notification content generation
        - Personalized workout recommendations

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - Workout Sessions: `GET /v1/me/workouts/sessions`
        - Workout Feedback: `POST /v1/workouts/{id}/feedback`
        - AI Assessments: `GET /v1/me/workouts/measured-metrics`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: 'User identifier: email, externalUUID, or internal user ID.'
          example: john.doe@acme.com
          schema:
            type: string
        - name: date
          required: false
          in: query
          description: Date for the digest (ISO 8601, YYYY-MM-DD). Past dates within last 7 days and today supported; future or older dates return 400. Defaults to today.
          example: '2026-01-10'
          schema:
            type: string
        - name: forceRefresh
          required: false
          in: query
          description: Force refresh, bypassing cache.
          example: false
          schema:
            type: boolean
      responses:
        '200':
          description: Successfully retrieved daily digest.
          schema:
            example:
              userId: 63415bf67a9c7000126616c1
              organizationId: 63415bf67a9c7000126616c1
              date: '2026-01-10T00:00:00.000Z'
              pillars:
                - type: health_pulse
                  status: green
                  headline: '82 (+5 vs 7-day). Readiness: Push window today.'
                  action: Maintain your sleep routine
                  confidence: 0.85
                  score: 82
                  delta: 5
                  deltaDirection: up
                  driver: sleep
                - type: training
                  status: green
                  headline: '4 workouts this week. Form: 78% (improving). On pace.'
                  action: 'Next: Full Body Strength at high intensity'
                  confidence: 0.8
                  weeklyCompletions: 4
                  streak: 5
                  formScore: 78
                  formTrend: improving
                - type: movement
                  status: yellow
                  headline: Activity below target the last 2 days.
                  action: Add a 20-min walk this afternoon
                  confidence: 0.7
                - type: nutrition
                  status: yellow
                  headline: No meals logged today.
                  action: Log your next meal to keep your streak
                  confidence: 0.5
                  isFallback: true
              todaysFocus: 'Complete: Full Body Strength at high intensity'
              dataCompleteness: 0.75
              generatedAt: '2026-01-10T08:30:00.000Z'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserDigestResponse'
        '400':
          description: Invalid date (e.g., future date, more than 7 days in past, or invalid format).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: User or organization not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-insights
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/digest' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getUserDailyDigest() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/digest', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/digest", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/endusers/{endUserId}/insights/pillars/{pillarType}:
    get:
      operationId: UserInsightsApi_getPillarDetail
      summary: Get detailed view of a specific insight pillar
      description: |-

        ## Pillar Detail

        Returns expanded information for a specific insight pillar, including all available metrics and recommendations.

        ---

        ### Available Pillar Types

        | Type | Details Included |
        |------|------------------|
        | `health_pulse` | Score, delta, driver, readiness band, recommended intensity |
        | `training` | Last workout, next session, form score, form cue, pacing status, risk level, why explanations, alternative actions |
        | `recovery` | Sleep score, main issue, intensity, readiness band, HRV band, why explanations |
        | `movement` | Activity level, suggested minutes, cardio trend |
        | `nutrition` | Nutrition score (when available), wins/watches |
        | `body` | Body score, weekly trend, streak, biggest lever |

        ---

        ### Enhanced Coaching Details

        When drilling into pillar details, you get actionable coaching context:

        **Readiness (Health Pulse and Recovery pillars):**
        - `readinessBand`: Training capacity recommendation (`push` | `maintain` | `recover`)
        - `readinessMessage`: Explanation of the recommendation
        - `recommendedIntensity`: Target workout intensity (`light` | `moderate` | `high`)
        - `hrvBand`: HRV relative to personal baseline (`low` | `normal` | `high`)

        **Risk Detection (Training pillar):**
        - `riskLevel`: Fatigue risk severity (`low` | `moderate` | `high`)
        - `riskTriggers`: Array of up to 3 contributing factors
        - `alternativeActions`: Safe workout alternatives when risk detected

        **Form Coaching (Training pillar):**
        - `formCue`: Primary technique focus for today
        - `formSuggestion`: Adjustment if form is declining
        - `repAccuracy`: Rep accuracy percentage from AI assessment

        **Program Pacing (Training pillar):**
        - `pacingStatus`: Weekly pacing status (`on_track` | `behind` | `ahead`)
        - `pacingMessage`: Weekly progress summary
        - `workoutsPlannedThisWeek` / `workoutsCompletedThisWeek`

        **Explanations:**
        - `why`: Array of up to 3 reasons explaining the recommendation

        ---

        ### Use Cases

        - Drill-down from digest view
        - Detailed pillar cards in UI
        - Coach insights for specific areas

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier (UUID) of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
        - name: endUserId
          required: true
          in: path
          description: 'User identifier: email, externalUUID, or internal user ID.'
          example: john.doe@acme.com
          schema:
            type: string
        - name: pillarType
          required: true
          in: path
          description: Type of pillar to get details for.
          example: training
          schema:
            type: string
            enum:
              - health_pulse
              - training
              - recovery
              - movement
              - nutrition
              - body
      responses:
        '200':
          description: Successfully retrieved pillar details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PillarDetailResponse'
        '400':
          description: Invalid pillar type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: User, organization, or pillar not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-insights
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/pillars/<PILLARTYPE>' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getPillarDetail() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/pillars/<PILLARTYPE>', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/endusers/<END_USER_ID>/insights/pillars/<PILLARTYPE>", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/orgs/{organizationId}/stats:
    get:
      operationId: OrganizationStatsApi_getOrganizationStats
      summary: Get organization API usage statistics
      description: |-

        ## Organization API Usage Statistics

        Retrieves real-time API usage statistics for your organization including current hour requests, daily totals, and rate limits.

        ---

        ### 📋 What's Included

        **Current Usage:**
        - Current hour timestamp and request count
        - Total requests made today
        - Current date for reference

        **Rate Limits:**
        - Hourly rate limit from your subscription
        - Daily rate limit from your subscription

        **Organization Info:**
        - Organization ID and name
        - Response timestamp

        ---

        ### 🎯 Use Cases

        ✅ **API Monitoring** - Track real-time API usage  
        ✅ **Rate Limit Management** - Monitor against your limits  
        ✅ **Usage Analytics** - Understand API consumption patterns  
        ✅ **Alerting Systems** - Set up usage-based notifications

        ---

        ### 💡 Best Practices

        ✅ **Cache responses** - Stats update every 5 minutes  
        ✅ **Monitor trends** - Track usage patterns over time  
        ✅ **Set up alerts** - Monitor approaching rate limits  
        ✅ **Plan capacity** - Use data for subscription planning

        ---

        ### 🔗 Related Endpoints

        - Organization Metadata: `GET /v1/orgs/{orgId}/metadata`
        - Organization Workouts: `GET /v1/orgs/{orgId}/workouts`
        - Organization Plans: `GET /v1/orgs/{orgId}/plans`
                
      parameters:
        - name: organizationId
          required: true
          in: path
          description: The unique identifier of the organization.
          example: 63415bf67a9c7000126616c1
          schema:
            type: string
      responses:
        '200':
          description: Successfully retrieved organization API usage statistics.
          schema:
            example:
              organizationId: 63415bf67a9c7000126616c1
              organizationName: My Fitness Company
              currentStats:
                currentHour: '2023-11-06T14:00:00Z'
                currentHourRequests: 45
                totalDayRequests: 234
                currentDate: '2023-11-06'
              rateLimits:
                hourly: 1000
                daily: 15000
              timestamp: '2023-11-06T14:30:00Z'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationStatsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Organization not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - organization
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/stats' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getOrganizationStats() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/stats', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/orgs/<ORGANIZATION_ID>/stats", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/chat/conversations:
    post:
      operationId: ChatApi_startConversation
      summary: Start a new chat conversation
      description: |-

        ## Start Conversation

        Creates a new conversation with the AI fitness coach and returns the assistant's response to the initial message.

        ---

        ### User Identification

        Provide at least one of `userEmail` or `userExternalUUID` in the request body to identify the end user.

        ---

        ### Organization ID

        - Use `"default"` to automatically resolve the organization from the API key
        - Or provide a valid 24-character hex organization id

        ---

        ### Response

        Returns the created conversation metadata and the AI assistant's first response message. The assistant message may include `metadata.contentPreview` (workouts, programs, exercises) or `metadata.pendingAction` when the AI proposes a state-changing action.

        ---

        ### Pending Actions

        When the AI proposes a state-changing action (e.g. log nutrition, add workouts, generate workout), the assistant message will include `metadata.pendingAction` with an `id`, `type`, `summary`, and `payload`. Use the Confirm Action endpoint to execute it.

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - `POST /v1/chat/conversations/{conversationId}/messages` - Send follow-up messages
        - `GET /v1/chat/conversations` - List user conversations
        - `POST /v1/chat/conversations/{conversationId}/actions/confirm` - Confirm a pending action
                
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StartConversationBody'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatConversationResponse'
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/chat/conversations' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function startConversation() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/chat/conversations",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
    get:
      operationId: ChatApi_getConversations
      summary: Get user conversations
      description: |-

        ## List Conversations

        Returns a paginated list of the end user's chat conversations, ordered by most recent activity.

        ---

        ### User Identification

        Provide at least one of `userEmail` or `userExternalUUID` as query parameters to identify the end user.

        ---

        ### Pagination

        | Parameter | Default | Max |
        |-----------|---------|-----|
        | `page` | 1 | - |
        | `limit` | 20 | 100 |

        ---

        ### Related Endpoints

        - `POST /v1/chat/conversations` - Start a new conversation
        - `GET /v1/chat/conversations/{conversationId}/messages` - Get messages in a conversation
        - `DELETE /v1/chat/conversations/{conversationId}` - Archive a conversation
                
      parameters:
        - name: organizationId
          required: true
          in: query
          description: Organization ID - use "default" to use the user's default organization
          example: default
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: Page number
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page
          schema:
            minimum: 1
            maximum: 100
            default: 20
            type: number
        - name: userEmail
          required: false
          in: query
          description: User email address to identify the end user
          example: user@example.com
          schema:
            type: string
        - name: userExternalUUID
          required: false
          in: query
          description: External unique identifier for the end user
          example: user-12345
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatConversationsResponse'
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/chat/conversations?organizationId=default' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getConversations() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations?organizationId=default', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/chat/conversations?organizationId=default", headers=headers)
            response.raise_for_status()
            print(response.json())
  /v1/chat/conversations/{conversationId}/messages:
    get:
      operationId: ChatApi_getConversationMessages
      summary: Get conversation messages
      description: |-

        ## Get Messages

        Returns a paginated list of messages in a conversation, ordered chronologically.

        ---

        ### User Identification

        Provide at least one of `userEmail` or `userExternalUUID` as query parameters to identify the end user. The user must be the owner of the conversation.

        ---

        ### Message Structure

        Each message includes:
        - `role`: `"user"` or `"assistant"`
        - `content`: The message text
        - `status`: `"pending"`, `"delivered"`, or `"failed"`
        - `metadata`: Optional object containing `reasoning`, `topics`, `contentPreview`, `pendingAction`, or `confirmedResult`

        ---

        ### Pagination

        | Parameter | Default | Max |
        |-----------|---------|-----|
        | `page` | 1 | - |
        | `limit` | 50 | 100 |

        ---

        ### Related Endpoints

        - `POST /v1/chat/conversations/{conversationId}/messages` - Send a new message
        - `GET /v1/chat/conversations` - List conversations
                
      parameters:
        - name: conversationId
          required: true
          in: path
          schema:
            type: string
        - name: organizationId
          required: true
          in: query
          description: Organization ID - use "default" to use the user's default organization
          example: default
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: Page number
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page
          schema:
            minimum: 1
            maximum: 100
            default: 50
            type: number
        - name: userEmail
          required: false
          in: query
          description: User email address to identify the end user
          example: user@example.com
          schema:
            type: string
        - name: userExternalUUID
          required: false
          in: query
          description: External unique identifier for the end user
          example: user-12345
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChatMessagesResponse'
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X GET 'https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages?organizationId=default' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function getConversationMessages() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages?organizationId=default', {
              method: 'GET',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.get("https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages?organizationId=default", headers=headers)
            response.raise_for_status()
            print(response.json())
    post:
      operationId: ChatApi_sendMessage
      summary: Send message to conversation
      description: |-

        ## Send Message

        Sends a user message to an existing conversation and returns the AI coach's response.

        ---

        ### User Identification

        Provide at least one of `userEmail` or `userExternalUUID` in the request body to identify the end user. The user must be the owner of the conversation.

        ---

        ### Response

        Returns three objects:
        - `userMessage` - The saved user message
        - `assistantMessage` - The AI coach response
        - `conversation` - Updated conversation metadata (messageCount, lastMessageAt)

        ---

        ### AI Capabilities

        The AI coach can:
        - List, search, and recommend workouts, programs, and exercises (returned in `metadata.contentPreview`)
        - Propose state-changing actions like logging nutrition, adding/assigning workouts and plans, adapting or generating workouts and programs (returned in `metadata.pendingAction`)
        - Provide personalized advice based on user profile, training history, and goals

        ---

        ### Rate Limit

        This endpoint counts as 10x API calls toward your hourly and daily limits.

        ---

        ### Related Endpoints

        - `POST /v1/chat/conversations` - Start a new conversation
        - `POST /v1/chat/conversations/{conversationId}/actions/confirm` - Confirm a pending action
        - `GET /v1/chat/conversations/{conversationId}/messages` - Get message history
                
      parameters:
        - name: conversationId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendMessageBody'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendMessageResponse'
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Conversation not found or does not belong to the user.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function sendMessage() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/messages",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/chat/conversations/{conversationId}/actions/confirm:
    post:
      operationId: ChatApi_confirmAction
      summary: Confirm a pending AI action
      description: |-

        ## Confirm Action

        Executes a pending action proposed by the AI coach after user confirmation.

        ---

        ### How It Works

        1. The AI proposes an action via `assistantMessage.metadata.pendingAction`
        2. Your client shows a confirmation UI with the action `summary`
        3. User confirms, and you call this endpoint with the `pendingActionId`
        4. The action is executed and the result is returned

        ---

        ### Supported Action Types

        | Type | Description | Response Field |
        |------|-------------|----------------|
        | `log_nutrition` | Log a meal or nutrition entry | `nutritionOverview` |
        | `add_workouts` | Add workouts to user's library | `message` |
        | `add_plans` | Add plans to user's library | `message` |
        | `assign_workouts` | Assign workouts to the user | `message` |
        | `assign_plans` | Assign plans to the user | `message` |
        | `adapt_workout` | Adapt a workout on the fly | `adaptedWorkout` |
        | `adapt_program` | Adapt a program on the fly | `adaptedProgram` |
        | `generate_workout` | Generate a new workout | `generatedWorkout` |
        | `generate_program` | Generate a new program | `generatedProgram` |

        ---

        ### Adapted/Generated Content

        `adaptedWorkout` and `generatedWorkout` use the same response format as `POST /v1/orgs/{orgId}/workouts/{id}/adapt` and `POST /v1/orgs/{orgId}/workouts/generate` respectively. Same applies to program equivalents. Clients can reuse the same types and rendering logic.

        ---

        ### Related Endpoints

        - `POST /v1/chat/conversations/{conversationId}/messages` - Send a message (may return pendingAction)
        - `POST /v1/chat/conversations` - Start a conversation (may return pendingAction)
                
      parameters:
        - name: conversationId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmActionBody'
      responses:
        '200':
          description: Action executed successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConfirmActionResponseDto'
        '400':
          description: Action expired or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Pending action not found or already used.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X POST 'https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/actions/confirm' \
              -H 'X-Api-Key: YOUR_API_KEY' \
              -H 'Content-Type: application/json' \
              -d '{}'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function confirmAction() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/actions/confirm', {
              method: 'POST',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({}),
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.post(
                "https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>/actions/confirm",
                headers={**headers, "Content-Type": "application/json"},
                json={},
            )
            response.raise_for_status()
            print(response.json())
  /v1/chat/conversations/{conversationId}:
    delete:
      operationId: ChatApi_archiveConversation
      summary: Archive conversation
      description: |-

        ## Archive Conversation

        Soft-deletes a conversation by setting its status to `archived`. The conversation and its messages are retained in the database but will no longer appear in the conversations list.

        ---

        ### User Identification

        Provide at least one of `userEmail` or `userExternalUUID` as query parameters to identify the end user. The user must be the owner of the conversation.

        ---

        ### Related Endpoints

        - `GET /v1/chat/conversations` - List active conversations
        - `GET /v1/chat/conversations/{conversationId}/messages` - Get messages before archiving
                
      parameters:
        - name: conversationId
          required: true
          in: path
          schema:
            type: string
        - name: organizationId
          required: true
          in: query
          description: Organization ID - use "default" to use the user's default organization
          example: default
          schema:
            type: string
        - name: userEmail
          required: false
          in: query
          description: User email address to identify the end user
          example: user@example.com
          schema:
            type: string
        - name: userExternalUUID
          required: false
          in: query
          description: External unique identifier for the end user
          example: user-12345
          schema:
            type: string
      responses:
        '200':
          description: Conversation archived successfully.
        '400':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Authentication failed - API key is missing or invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: API key is not authorized for this organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      tags:
        - endusers-ai-chat
      security:
        - AccessToken: []
        - X-Api-Key:
            - X-Api-Key
      x-codeSamples:
        - lang: curl
          label: cURL
          source: |-
            curl -X DELETE 'https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>?organizationId=default' \
              -H 'X-Api-Key: YOUR_API_KEY'
        - lang: typescript
          label: TypeScript (fetch)
          source: |-
            async function archiveConversation() {
              const res = await fetch('https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>?organizationId=default', {
              method: 'DELETE',
              headers: {
                'X-Api-Key': process.env.HYPERHUMAN_API_KEY ?? '',
              },
              });
              if (!res.ok) {
                const err = await res.json().catch(() => ({}));
                throw new Error(err.error?.code ?? res.statusText);
              }
              return res.json();
            }
        - lang: python
          label: Python (requests)
          source: |-
            import os
            import requests

            headers = {"X-Api-Key": os.environ["HYPERHUMAN_API_KEY"]}
            response = requests.delete("https://content.api.hyperhuman.cc/v1/chat/conversations/<CONVERSATIONID>?organizationId=default", headers=headers)
            response.raise_for_status()
            print(response.json())
info:
  title: Hyperhuman Content API
  description: |
    <!--
      Do not add an `# H1` here. Swagger UI and Scalar both render `info.title`
      ("Hyperhuman Content API") above this description; an h1 would duplicate it.
      Start with the tagline blockquote and a positioning paragraph instead.
    -->

    > One API for delivery, personalization, and insights across your entire product.

    Fitness content infrastructure for modern health, wellness, and fitness products: workout API, AI recommendations, AI generation, AI adaptation, and insights in one platform. Most teams ship Publish + Recommend in the first week and add the AI layers as their audience signals demand it.

    ---

    ## Quick Start

    **1. Get credentials** -> [team.hyperhuman.cc/settings?tab=integrations](https://team.hyperhuman.cc/settings?tab=integrations)

    **2. First request:**
    ```bash
    curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/metadata' \
      -H 'X-Api-Key: YOUR_API_KEY'
    ```

    **3. Generate a workout:**
    ```bash
    curl -X POST 'https://content.api.hyperhuman.cc/v1/orgs/{organizationId}/workouts/generate' \
      -H 'X-Api-Key: YOUR_API_KEY' \
      -H 'Content-Type: application/json' \
      -d '{
        "endUserProfileDetails": {"age": 28, "fitnessLevels": ["beginner"]},
        "exerciseSources": ["premium_stock"],
        "durationOptions": {"minMinutes": 20, "maxMinutes": 20},
        "categoryId": "615aa3f0dbe7140012c59e94"
      }'
    ```

    ---

    ## For LLMs and AI agents

    If you are a coding assistant integrating against this API, prefer these machine-readable artifacts over scraping this HTML page:

    | Artifact | URL | Use it for |
    |----------|-----|------------|
    | Compact LLM index (markdown) | [https://content.api.hyperhuman.cc/llms.txt](https://content.api.hyperhuman.cc/llms.txt) | Short overview + links to deeper docs. Drop into context windows. |
    | Full LLM bundle (markdown) | [https://content.api.hyperhuman.cc/llms-full.txt](https://content.api.hyperhuman.cc/llms-full.txt) | Auth, error envelope, pagination, locales, and per-endpoint summaries in one file. |
    | OpenAPI 3 spec (JSON) | [https://content.api.hyperhuman.cc/openapi.json](https://content.api.hyperhuman.cc/openapi.json) | Source of truth for tool/function calling. Stable `operationId`s of the form `Controller_method`. |
    | OpenAPI 3 spec (YAML) | [https://content.api.hyperhuman.cc/openapi.yaml](https://content.api.hyperhuman.cc/openapi.yaml) | Same content as `openapi.json`, friendlier for diffing and most CLI codegen tools. |
    | Agent integration guide | [https://content.api.hyperhuman.cc/AGENTS.md](https://content.api.hyperhuman.cc/AGENTS.md) | Conventions for generated client code (auth, errors, pagination, locales) plus **§11–12**: strict whitelisted query/body keys, public `/openapi.json` scope, id wording, and **repository** notes for API maintainers (DTOs, `parse-csv-ids`, OpenAPI `include` list). |
    | Custom player guide | [https://content.api.hyperhuman.cc/docs/guides/custom-player.md](https://content.api.hyperhuman.cc/docs/guides/custom-player.md) | Reference implementation for building a custom interactive workout player on top of `/playlist` and `/music`. |

    > Need a copy-paste prompt? Send the agent the URL of `/llms-full.txt` plus the prose: "Use this Hyperhuman Content API. Authenticate with the `X-Api-Key` header. Every error response is `{ "error": { "code", "message" } }`. Pagination cursors are `offset` and `limit`."

    ---

    ## Five capabilities, one API

    Five product surfaces stack on the same library. Start where you are; add the AI layers as your product matures.

    | # | Capability | Primary endpoint | What it does | Latency band |
    |---|------------|------------------|--------------|--------------|
    | 1 | **Publish Content** | `GET /v1/orgs/{organizationId}/workouts` <br> `GET /v1/orgs/{organizationId}/plans` | List, filter, and play workouts and multi-week plans from your library. Your library becomes your product surface. | Fast |
    | 2 | **AI Recommend** | `POST /v1/orgs/{organizationId}/workouts/recommend` <br> `POST /v1/orgs/{organizationId}/plans/recommend` | Suggest the best next workout or plan from your library, ranked against goals and profile signals. | Sub-second |
    | 3 | **AI Generate** | `POST /v1/orgs/{organizationId}/workouts/generate` <br> `POST /v1/orgs/{organizationId}/plans/generate` | Create a brand-new workout or multi-week plan on the fly, scoped to the user's age, level, equipment, and time budget. | 2-8 seconds |
    | 4 | **AI Adapt** | `POST /v1/orgs/{organizationId}/workouts/{workoutId}/adapt` <br> `POST /v1/orgs/{organizationId}/plans/{planId}/adapt` | Evolve an existing workout or plan as the user progresses. Preserves the original goals; modifies intensity, duration, and exercise selection. Counts as 10x rate-limit weight. | 2-8 seconds |
    | 5 | **AI Insights** | `GET /v1/orgs/{organizationId}/endusers/{endUserId}/insights/digest?date=YYYY-MM-DD` <br> `GET /v1/orgs/{organizationId}/endusers/{endUserId}/insights/pillars/{pillarType}` | Daily digest plus per-pillar drill-downs (health pulse, training, recovery, movement, nutrition, body) for re-engagement loops. | Fast |

    > `{endUserId}` is the Hyperhuman end-user id (24-character hex DB id returned by the endusers endpoints), not the user's email. Treat all ids as opaque strings.

    ---

    ## Three delivery models

    The same library and intelligence layer ship through three integration paths. Pick by team capacity and product surface.

    ### 1. Embed & Go

    Drop Hyperhuman-hosted surfaces into a webview, landing page, or portal: a **single-workout or JSON player** on `team.hyperhuman.cc` (see **Embedded Player**), or a **full workouts or programs library grid** on the member web app with configurable discovery UI (see **Branded library embed**). Fastest path to live content; no custom player build required. Best for web apps, MVPs, corporate wellness portals, marketing pages.

    ### 2. Stream Videos

    Get a pre-rendered, full-length workout **video** or **narrative audio** as a **single presigned HTTPS URL** in the response body. Best for VOD catalogs, CMS publishing, YouTube workflows, audio-first products.

    ```bash
    curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/{workoutId}/export/video/stream_url?locale=en-US' \
      -H 'X-Api-Key: YOUR_API_KEY'
    ```

    ```bash
    curl -X GET 'https://content.api.hyperhuman.cc/v1/workouts/{workoutId}/export/audio/stream_url?locale=en-US' \
      -H 'X-Api-Key: YOUR_API_KEY'
    ```

    Returns **`200`** with **`Content-Type: text/plain`**: a **single** presigned URL string (not JSON). The URL points to the full-workout **video** or **narrative audio** object stored for that locale; format and container (for example **MP4**, **HLS** `.m3u8`, or **M4A** audio) depend on the export that was generated—follow the URL. URLs are time-limited (on the order of **7 days**). Pre-rendered video/audio takes 2-5 minutes to produce after a workout is created or generated; until then the export endpoint returns `404`. If the requested locale has not been rendered, the endpoint also returns `404` - retry with `locale=en-US` or trigger a render for the missing locale.

    ### 3. Build Your UX

    Power your own player UI with our structured playlist and pre-signed media URLs. Maximum control over UI, analytics, and offline behavior. Best for mobile apps, connected hardware, and premium coaching experiences. See the **Custom Interactive Workout Player** section below for the reference implementation.

    ---

    ## Embedded Player

    Two drop-in iframes for the most common integration paths. The same player powers both - only the data source differs.

    ### Pre-built Workout

    Renders any workout from your library by id.

    ```html
    <iframe
      src="https://team.hyperhuman.cc/embed/workout/{workoutId}?organizationId={organizationId}&apiKey={apiKey}&locale=en-US"
      style="width: 100%; aspect-ratio: 16/9; border: none; border-radius: 8px;"
      allow="autoplay; fullscreen"
      allowfullscreen>
    </iframe>
    ```

    #### Query Parameters

    | Param | Required | Type | Default | Description |
    |-------|----------|------|---------|-------------|
    | `organizationId` | yes | string | - | Organization id (24-character hex DB id) the workout belongs to. |
    | `apiKey` | yes | string | - | Your Content API key (`X-Api-Key` value). |
    | `locale` | no | string | `en-US` | BCP-47 locale. Falls back to English when unsupported. |
    | `segment` | no | string | first segment | Segment id to start playback from (e.g. resume from a specific exercise). |
    | `presentationStyle` | no | enum | workout default | One of `full`, `minimal`, `essential`, `noOverlays`. Overrides the workout's own `presentationStyle`. |
    | `muted` | no | boolean | `false` | Accept `1` or `true`. Pair with `autoplay=1` for unattended embeds. |
    | `autoplay` | no | boolean | `false` | Accept `1` or `true`. Browsers block sound autoplay without a user gesture - combine with `muted=1`. |
    | `brandLogoUrl` | no | string (URL) | org logo | Overrides the org logo shown in the player chrome. |
    | `brandWatermarkUrl` | no | string (URL) | org watermark | Overrides the bottom-right watermark. Square PNG with transparent background recommended. |
    | `brandMainColor` | no | hex string | org main color | Player accent color. URL-encode the `#` (`%23FF6600`). |
    | `brandSecondaryColor` | no | hex string | org secondary | Used for secondary accents. URL-encode the `#`. |
    | `brandTextColor` | no | hex string | org text color | Color of timer / next-exercise / outro text overlays. URL-encode the `#`. |

    > Tip: org-level branding (logo, watermark, colors) is exposed by `GET /v1/orgs/{organizationId}/metadata`. Pass overrides only when you need to differ from the org defaults (e.g. white-label per end-user).

    ---

    ### AI-Generated Workout

    For workouts produced on the fly by your own backend or by `POST /v1/orgs/{organizationId}/workouts/generate`. The iframe announces readiness; your page replies with the JSON payload.

    ```html
    <iframe id="player"
      src="https://team.hyperhuman.cc/embed/workout-json-receiver?organizationId={organizationId}&apiKey={apiKey}">
    </iframe>

    <script>
    window.addEventListener('message', (e) => {
      if (e.data === 'hyperhumanPlayerReadyForData') {
        document.getElementById('player').contentWindow.postMessage(workoutJSON, '*');
      }
    });
    </script>
    ```

    #### Query Parameters

    | Param | Required | Type | Default | Description |
    |-------|----------|------|---------|-------------|
    | `organizationId` | yes | string | - | Organization id (24-character hex DB id). |
    | `apiKey` | yes | string | - | Your Content API key. |
    | `locale` | no | string | `en-US` | BCP-47 locale. |
    | `segment` | no | string | first segment | Segment id to start playback from. |

    #### postMessage Protocol

    1. The iframe loads, validates credentials, then posts the literal string `'hyperhumanPlayerReadyForData'` to its parent.
    2. Your page replies with the workout JSON payload (shape below).
    3. Subsequent posts of the same shape replace the current workout (useful for "play next" flows).

    #### Workout JSON Payload Shape

    ```json
    {
      "name": "Quick Morning Burner",
      "totalDurationSeconds": 600,
      "difficulty": "intermediate",
      "categoryId": "615aa3f0dbe7140012c59e94",
      "initialSegmentId": "instance_1",
      "instances": [
        {
          "id": "instance_1",
          "kind": "single-exercise",
          "durationSeconds": 45,
          "pace": "medium",
          "weightLevel": "medium",
          "rpe": 7,
          "amrap": false,
          "skipIntro": false,
          "exercise": {
            "id": "507f1f77bcf86cd799439011",
            "name": "Bodyweight Squats",
            "thumbnailUrl": "https://images.hyperhuman.cc/squat-thumb.jpg"
          }
        },
        {
          "id": "instance_rest_1",
          "kind": "rest",
          "durationSeconds": 30
        }
      ]
    }
    ```

    | Field | Required | Notes |
    |-------|----------|-------|
    | `name` | yes | Workout title shown in the intro/outro. |
    | `instances[]` | yes | Ordered list of exercise + rest segments. |
    | `instances[].kind` | yes | `single-exercise` or `rest`. |
    | `instances[].exercise.id` | yes (for exercises) | Hyperhuman exercise id; the player fetches video/audio assets for this id via the Content API. |
    | `totalDurationSeconds` | recommended | Used for the progress bar. |
    | `initialSegmentId` | optional | Same effect as the `segment` query param. |

    #### Security Model

    The receiver intentionally accepts `postMessage` from **any parent origin** so third-party customer pages can drive the player without per-tenant allow-list configuration. The trust boundary is **payload-shape validation** - the receiver only honors objects matching the schema above. Treat this channel as untrusted: never include API keys, access tokens, PII, or anything you wouldn't put in a URL fragment.

    ---

    ### Player Cast Controls (optional)

    Both iframes accept playback control messages from any parent origin. Useful for casting, custom UI overlays, or remote control surfaces.

    ```javascript
    playerIframe.contentWindow.postMessage({
      type: 'CAST_CONTROL',
      action: 'play' // 'play' | 'pause' | 'next' | 'previous' | 'restart' | 'done'
    }, '*');
    ```

    Same security model as the JSON receiver: payload-shape validated, origin-open. Do not transmit secrets.

    ---

    ## Branded library embed (workouts and programs)

    Branded, responsive **library pages**: a searchable grid of your team's workouts or multi-week programs, hosted on the **member web app** (not the Content API origin in `https://content.api.hyperhuman.cc`). Visitors browse and open workouts without you building a catalog UI. There is **no API key in the URL** — access and visibility follow your org's member-app and publishing settings.

    In [Hyperhuman Teams](https://team.hyperhuman.cc), open **Share** on **Manage Content** (workouts or programs) and use the **Embed page** tab to copy a snippet and toggle options; the same query contract is documented here for hand-built URLs.

    ### Base URL

    Production host: `https://member.hyperhuman.cc`. Your team may use a different host in staging or white-label deployments — use the member app URL shown in Teams when copying the embed.

    ### Paths

    | Surface | Path |
    |---------|------|
    | Workout library grid | `/workouts` |
    | Program library grid | `/plans` |

    Always pass `orgId` (your organization id, same value as `{organizationId}` in Content API paths).

    ### Query parameters

    Only **non-default** options are serialized on the URL (short, readable links). Defaults match the Teams **Embed page** UI.

    | Param | Required | Type | Default | When it appears in the URL |
    |-------|----------|------|---------|----------------------------|
    | `orgId` | yes | string (24 hex chars) | - | Always. |
    | `showSearch` | no | boolean | `true` (search bar on) | Only as `showSearch=false` when the search bar is hidden. |
    | `showFilters` | no | boolean | `true` (filter chips on) | Only as `showFilters=false` when filters are hidden. |
    | `gridCols` | no | integer, one of 2, 3, or 4 | `3` | Only when not `3` (e.g. `gridCols=2` or `gridCols=4`). |
    | `playbackMode` | no | string | `overlay` | Only when `dedicated-page`. Default `overlay` opens playback in a lightbox over the embed; `dedicated-page` opens the workout in a **new browser tab** so the host page stays in place. |
    | `showDuration` | no | boolean | `true` (length badge on cards) | Only as `showDuration=false` when hidden. |
    | `showDifficulty` | no | boolean | `true` (difficulty badge on cards) | Only as `showDifficulty=false` when hidden. |

    ### Iframe snippet

    The Teams **Embed page** tab generates a container-filling iframe (your page controls the outer box size):

    ```html
    <iframe width="100%" height="100%" src="MEMBER_APP_URL_AND_QUERY" title="Your team title" frameborder="0" allow="encrypted-media; accelerometer; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
    ```

    Replace `MEMBER_APP_URL_AND_QUERY` with the full `https://member.hyperhuman.cc/workouts?...` or `https://member.hyperhuman.cc/plans?...` URL from Teams or built from the table above.

    ### Examples

    **Workouts grid** — search and filters off, 2 columns, open in new tab, length and difficulty badges off:

    ```html
    <iframe width="100%" height="100%" src="https://member.hyperhuman.cc/workouts?orgId=63415bf67a9c7000126616c1&showSearch=false&showFilters=false&gridCols=2&playbackMode=dedicated-page&showDuration=false&showDifficulty=false" title="Your Team's Workouts" frameborder="0" allow="encrypted-media; accelerometer; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
    ```

    **Programs grid** — same options with 4 columns:

    ```html
    <iframe width="100%" height="100%" src="https://member.hyperhuman.cc/plans?orgId=63415bf67a9c7000126616c1&showSearch=false&showFilters=false&gridCols=4&playbackMode=dedicated-page&showDuration=false&showDifficulty=false" title="Your Team's Programs" frameborder="0" allow="encrypted-media; accelerometer; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
    ```

    ### API parity

    To drive the same catalogs from your own UI, use the Content API:

    - `GET /v1/orgs/{organizationId}/workouts` — list and filter workouts (query params such as `offset`, `limit`, `q`, `sort`, `visibility`, `difficulty`, `categoryIds`, duration filters; no `page` — see [AGENTS.md](https://content.api.hyperhuman.cc/AGENTS.md) section 4).
    - `GET /v1/orgs/{organizationId}/plans` — list and filter plans (e.g. `difficulties`, `goalIds`, `durationInWeeks`, `workoutsPerWeek`).

    ---

    ## Custom Interactive Workout Player

    For full UI control, build your own player on top of the public API. The contract is small:

    | Endpoint | Returns |
    |----------|---------|
    | `GET /v1/workouts/{workoutId}` | Workout metadata (name, duration, difficulty, `videoAudioMode`, `mixBgMusic`). |
    | `GET /v1/workouts/{workoutId}/playlist?locale={locale}` | Ordered segments with media assets and timing. Drives the player. |
    | `GET /v1/workouts/{workoutId}/music` | Shuffled, deduplicated background music playlist (pre-signed S3 URLs, 7-day expiration). Respects org/trainer music preferences and the workout's `mixBgMusic` flag. |

    The full reference implementation - playlist manager, media controller, progress tracker, navigation handler, audio policy compliance - lives in the [Custom Player Guide](https://content.api.hyperhuman.cc/docs/guides/custom-player.md). It mirrors the Hyperhuman first-party players byte-for-byte and is the recommended starting point if you ship your own UX.

    ### Audio Policy

    Each workout has a `videoAudioMode` (see `GET /v1/workouts/{workoutId}`) that controls which audio tracks the player must mix. Mirror this matrix exactly so your custom player matches the rendered MP4 export and the Hyperhuman first-party players byte-for-byte.

    | `videoAudioMode` | Voice instructions | Beeps / countdowns | Background music* |
    |-------------------|---------------------|--------------------|-------------------|
    | `full` (default) | yes | yes | yes |
    | `instructionsOnly` | yes | no | yes |
    | `beepsOnly` | no | yes | yes |
    | `none` | no | no | no |

    \* Background music is additionally gated by the workout's `mixBgMusic` flag - if `mixBgMusic` is `false`, music never plays regardless of `videoAudioMode`.

    ```javascript
    // Reference snippet - matches backend export pipeline 1:1.
    const shouldIncludeVoiceInstructions = (mode) =>
      mode === undefined || mode === 'full' || mode === 'instructionsOnly';

    const shouldIncludeBeeps = (mode) =>
      mode === undefined || mode === 'full' || mode === 'beepsOnly';

    const shouldIncludeBackgroundMusic = (mode, mixBgMusic) =>
      mode !== 'none' && (mixBgMusic ?? true);
    ```

    ---

    ## Localization

    **Supported locales (13):** `en-US`, `en-GB`, `en-AU`, `fr-FR`, `de-DE`, `es-ES`, `it-IT`, `pt-PT`, `he-IL`, `ro-RO`, `cs-CZ`, `fi-FI`, `nl-NL`.

    ```bash
    curl 'https://content.api.hyperhuman.cc/v1/workouts/{workoutId}?locale=fr-FR' \
      -H 'X-Api-Key: YOUR_API_KEY'
    ```

    Localizes: workout titles and descriptions, exercise names, equipment, muscle groups, player metadata, and audio guidance (where enabled).

    #### Fallback Behavior

    | Endpoint family | Behavior when locale is unsupported |
    |-----------------|-------------------------------------|
    | Metadata, workout details, playlist (text + voice cues) | Falls back to English so playback never breaks. |
    | Pre-rendered video / audio exports (`/export/...`) | Returns `404` if no rendered asset exists in the requested locale. Re-request with `locale=en-US`, or trigger an export job for the missing locale. |

    ---

    ## Authentication

    Add to all requests:

    ```
    X-Api-Key: YOUR_API_KEY
    ```

    Get your key: [team.hyperhuman.cc/settings?tab=integrations](https://team.hyperhuman.cc/settings?tab=integrations).

    A handful of end-user-scoped endpoints (`/me/...`) additionally accept a JWT `Authorization: Bearer <token>` header in place of, or in addition to, the API key. The OpenAPI spec marks these explicitly with `bearer` security.

    ---

    ## Complete API Workflows

    ### Workflow 1: Browse and play pre-built content
    ```
    1. GET /v1/workouts/metadata             -> categories and filters
    2. GET /v1/orgs/{organizationId}/workouts -> browse the library
    3. GET /v1/workouts/{workoutId}           -> workout details
    4. GET /v1/workouts/{workoutId}/playlist  -> video segments
    5. (optional) GET /v1/workouts/{workoutId}/music         -> background music
    6. (optional) POST /v1/workouts/{workoutId}/sessions/start -> track progress
    ```

    ### Workflow 2: AI-generated workouts
    ```
    1. GET  /v1/orgs/{organizationId}/metadata           -> org settings
    2. POST /v1/orgs/{organizationId}/workouts/generate  -> create custom workout
    3. GET  /v1/workouts/{workoutId}/playlist            -> get generated content
    4. (optional) GET /v1/workouts/{workoutId}/music     -> background music
    5. POST  /v1/workouts/{workoutId}/sessions/start     -> begin tracking
    6. PATCH /v1/workouts/{workoutId}/sessions/{sessionId} -> update progress
    7. POST  /v1/workouts/{workoutId}/sessions/end       -> complete session
    8. POST  /v1/workouts/{workoutId}/feedback           -> collect user feedback
    ```

    ### Workflow 3: AI adaptation (evolve existing content)
    ```
    1. GET  /v1/orgs/{organizationId}/workouts                            -> pick a base workout
    2. POST /v1/orgs/{organizationId}/workouts/{workoutId}/adapt          -> personalized variant
    3. GET  /v1/workouts/{newWorkoutId}/playlist                          -> get the adapted content
    4. (then follow Workflow 2 from step 5 to track the session)
    ```

    ### Workflow 4: Multi-week training programs
    ```
    1. GET  /v1/plans/metadata                                -> plan goals and difficulties
    2. POST /v1/orgs/{organizationId}/plans/generate          -> create multi-week plan
    3. GET  /v1/plans/{planId}                                -> plan details
    4. GET  /v1/plans/{planId}/workouts                       -> plan workouts
    5. For each workout: follow Workflow 2.
    ```

    ### Workflow 5: End-user governance (B2B lifecycle)
    ```
    1. GET  /v1/orgs/{organizationId}/endusers          -> list users
    2. POST /v1/orgs/{organizationId}/endusers/invite   -> add new users
    3. GET  /v1/orgs/{organizationId}/endusers/find     -> check user status
    4. PUT  /v1/orgs/{organizationId}/endusers/suspend  -> temporarily disable access
    5. PUT  /v1/orgs/{organizationId}/endusers/reactivate -> restore access
    6. DELETE /v1/orgs/{organizationId}/endusers        -> remove user permanently
    ```

    ### Workflow 6: Daily insights and re-engagement
    ```
    1. GET /v1/orgs/{organizationId}/endusers/{endUserId}/insights/digest?date=2026-04-20
       -> 3-5 pillar summaries + todaysFocus + dataCompleteness
    2. GET /v1/orgs/{organizationId}/endusers/{endUserId}/insights/pillars/{pillarType}
       -> drill-down for any pillar (health_pulse, training, recovery, movement, nutrition, body)
    ```

    ---

    ## Error Handling

    ### Common HTTP Status Codes

    | Code | Meaning | Common Causes | How to Handle |
    |------|---------|----------------|---------------|
    | **200** | Success | Request completed successfully | Continue normal flow |
    | **201** | Created | Resource created (sessions, workouts) | Extract ID from response |
    | **400** | Bad Request | Invalid query/path parameters, malformed JSON body | Check request body and parameters |
    | **401** | Unauthorized | Missing, malformed or invalid API key (`X-Api-Key` header) | Verify the API key is sent on every request |
    | **403** | Forbidden | Valid API key, but not authorized for the requested organization or resource | Check that the API key belongs to the same org as the resource being accessed |
    | **404** | Not Found | Resource doesn't exist, was deleted, or the requested locale variant has not been rendered yet (export endpoints) | Verify IDs; for exports, retry without `locale` or with `locale=en-US` |
    | **409** | Conflict | Resource already exists (e.g. active session) or state transition not allowed | Reconcile against current state before retrying |
    | **422** | Unprocessable Entity | Body shape is valid JSON but fails business validation (`error.details` populated) | Inspect `error.details[]` for the offending fields |
    | **429** | Too Many Requests | Hourly or daily rate limit exceeded (see headers below) | Implement exponential backoff; respect `X-RateLimit-Reset` |
    | **500** | Internal Server Error | Server-side issue | Retry with exponential backoff |

    ### Error Response Format

    Every non-2xx response is wrapped in a single `error` envelope. The body is always JSON, even when the failing endpoint normally returns `text/plain` (e.g. stream URL endpoints).

    ```json
    {
      "error": {
        "code": "UnprocessableEntity",
        "message": "Validation failed",
        "target": "requestBody",
        "details": [
          {
            "code": "InvalidFormat",
            "message": "must be a positive number",
            "target": "durationOptions.minMinutes"
          }
        ]
      }
    }
    ```

    | Field | Type | Always present | Notes |
    |-------|------|----------------|-------|
    | `error.code` | string | yes | A stable machine-readable identifier from the closed enum below. Switch on this - never on `message`. |
    | `error.message` | string | yes | Human-readable English summary. Suitable for logs; not for end-user UI. |
    | `error.target` | string | no | The primary field/parameter related to the overall error (e.g. `requestBody`, `workoutId`). |
    | `error.details` | array | no | Field-level breakdown - populated for validation errors and entity-not-found errors. Each item has `code`, `message`, and optional `target`. |

    #### Stable error codes

    | HTTP status | `error.code` |
    |-------------|----------------|
    | 400 | `BadRequest` |
    | 401 | `Unauthorized` |
    | 403 | `Forbidden` |
    | 404 | `NotFound` |
    | 405 | `MethodNotAllowed` |
    | 408 | `RequestTimeout` |
    | 409 | `Conflict` |
    | 410 | `Gone` |
    | 413 | `PayloadTooLarge` |
    | 415 | `UnsupportedMediaType` |
    | 422 | `UnprocessableEntity` |
    | 500 | `InternalServerError` |
    | 501 | `NotImplemented` |
    | 502 | `BadGateway` |
    | 503 | `ServiceUnavailable` |
    | 504 | `GatewayTimeout` |

    > Treat the `error.code` enum as the contract. `error.message` wording can change between releases.

    ### Best Practices

    **Do:**
    - Always check HTTP status codes
    - Implement exponential backoff for 429/500 errors
    - Log error details for debugging
    - Provide user-friendly error messages
    - Handle network timeouts gracefully

    **Don't:**
    - Ignore error responses
    - Retry immediately on all errors
    - Expose internal error details to users
    - Make requests without proper error handling

    ### Retry Strategy

    ```javascript
    const retryWithBackoff = async (fn, maxRetries = 3) => {
      for (let i = 0; i < maxRetries; i++) {
        try {
          return await fn();
        } catch (error) {
          if (error.status === 429 || error.status >= 500) {
            const delay = Math.pow(2, i) * 1000;
            await new Promise(resolve => setTimeout(resolve, delay));
            continue;
          }
          throw error;
        }
      }
      throw new Error('Max retries exceeded');
    };
    ```

    ---

    ## Rate Limiting

    Every response carries:

    ```
    X-RateLimit-Limit: 1000
    X-RateLimit-Remaining: 999
    X-RateLimit-Reset: 1640995200
    ```

    - `X-RateLimit-Limit` - Maximum requests per window
    - `X-RateLimit-Remaining` - Requests remaining in current window
    - `X-RateLimit-Reset` - Unix timestamp when the window resets

    **Note:** AI and full-video endpoints (workout/plan generate, recommend, adapt, insights, chat, video generation, full video export) count as **10x** API calls toward your limits.

    **When rate limited (429):**
    1. Stop making requests immediately
    2. Wait until reset time (check `X-RateLimit-Reset`)
    3. Implement exponential backoff
    4. Consider upgrading your plan for higher limits

    **Best practices:**
    - Monitor remaining requests
    - Implement request queuing
    - Cache responses when possible
    - Use batch operations when available

    **Monitor usage:**
    - `GET /v1/orgs/{organizationId}/stats` - Real-time API usage statistics including current hour requests, daily totals, and rate limits.

    ---

    ## Hyperhuman product surfaces

    The Content API is one surface in a wider platform. If a capability you need isn't in this API, it likely lives in one of these:

    - **Teams workspace** ([team.hyperhuman.cc](https://team.hyperhuman.cc)) - production hub for the Smart Library, AI Workout Builder, Content Autopilot, Social Publishing, and team analytics. This is where API keys are issued.
    - **Hyperhuman Club** ([hyperhuman.cc/club](https://hyperhuman.cc/club)) - white-label branded member app for iOS and Android. Plug-and-play health HQ that companies launch in weeks instead of months.
    - **Wix widget** ([hyperhuman.cc/wix](https://hyperhuman.cc/wix)) - embeddable workout library and player for Wix sites.
    - **Pricing** ([hyperhuman.cc/pricing](https://hyperhuman.cc/pricing)) - plan-dependent quotas and module availability.
    - **Book a demo** ([hyperhuman.cc/book-a-demo](https://hyperhuman.cc/book-a-demo)) - if you're scoping a custom integration.

    ---

    ## Resources

    - **OpenAPI spec (JSON):** [https://content.api.hyperhuman.cc/openapi.json](https://content.api.hyperhuman.cc/openapi.json)
    - **OpenAPI spec (YAML):** [https://content.api.hyperhuman.cc/openapi.yaml](https://content.api.hyperhuman.cc/openapi.yaml)
    - **Modern reference (Scalar):** [https://content.api.hyperhuman.cc/docs](https://content.api.hyperhuman.cc/docs)
    - **Classic explorer (Swagger UI):** [https://content.api.hyperhuman.cc/docs/api-explorer](https://content.api.hyperhuman.cc/docs/api-explorer)
    - **LLM bundle:** [https://content.api.hyperhuman.cc/llms-full.txt](https://content.api.hyperhuman.cc/llms-full.txt)
    - **Agent guide:** [https://content.api.hyperhuman.cc/AGENTS.md](https://content.api.hyperhuman.cc/AGENTS.md)
    - **Custom player guide:** [https://content.api.hyperhuman.cc/docs/guides/custom-player.md](https://content.api.hyperhuman.cc/docs/guides/custom-player.md)
    - **Support:** support@hyperhuman.cc
    - **Website:** [hyperhuman.cc](https://hyperhuman.cc)
  version: '1.0'
  contact: {}
tags:
  - name: workouts
  - name: plans
  - name: library-exercises
  - name: exercise-groups
  - name: ai-generation
  - name: ai-recommendation
  - name: ai-adaptation
  - name: organization
  - name: social
  - name: content-autopilot
  - name: social-publish
  - name: endusers-ai-insights
  - name: endusers-ai-chat
  - name: endusers-plans
  - name: endusers-management
servers:
  - url: https://content.api.hyperhuman.cc
components:
  securitySchemes:
    X-Api-Key:
      type: apiKey
      in: header
      name: X-Api-Key
      description: Choose a plan that fits your expected API usage. Once activated, you'll receive your content key and organization ID in the [integrations tab](https://team.hyperhuman.cc/settings?tab=integrations).
  schemas:
    ApiErrorDetails:
      type: object
      properties:
        code:
          type: string
          description: A specific error code related to this detail.
          example: InvalidFormat
        message:
          type: string
          description: A human-readable message explaining this specific error detail.
          example: The provided email address is not valid.
        target:
          type: string
          description: The specific field or parameter that caused this error detail, if applicable.
          example: email
      required:
        - code
        - message
    ApiError:
      type: object
      properties:
        code:
          type: string
          description: A general error code classifying the error.
          example: BadRequest
        message:
          type: string
          description: A human-readable message summarizing the overall error.
          example: The request is invalid.
        target:
          type: string
          description: The primary field or parameter related to the overall error, if applicable.
          example: requestBody
        details:
          description: An array of specific error details, often related to validation failures on individual fields.
          type: array
          items:
            $ref: '#/components/schemas/ApiErrorDetails'
      required:
        - code
        - message
    ErrorResponse:
      type: object
      properties:
        error:
          description: Contains the details of the error that occurred.
          allOf:
            - $ref: '#/components/schemas/ApiError'
      required:
        - error
    TrainerRef:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the trainer.
          example: trainer-jane-doe
        name:
          type: string
          description: Display name of the trainer.
          example: Jane Doe
      required:
        - id
        - name
    WorkoutAudio:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the audio asset
          example: 68b0557adbaf49d17ee429bb
        createdAt:
          format: date-time
          type: string
          description: Timestamp when the audio was created
          example: '2025-08-28T13:11:22.242Z'
        isStock:
          type: boolean
          description: Whether this is a stock audio asset
          example: false
        assetUri:
          type: string
          description: Pre-signed URL to access the audio file
          format: url
          example: https://hhup-staging.s3.eu-central-1.amazonaws.com/a/...
        scriptText:
          type: string
          description: Script text for the audio
          example: Welcome to your workout!
        type:
          type: string
          description: Type of audio asset
          example: workoutIntro
        locale:
          type: string
          description: Locale/language of the audio
          example: en-US
        duration:
          type: number
          description: Duration of the audio in seconds
          example: 0.875
        status:
          type: string
          description: Processing status of the audio
          example: generated
      required:
        - id
        - createdAt
        - isStock
        - assetUri
        - type
        - locale
        - duration
        - status
    VideoLinks:
      type: object
      properties:
        url:
          type: string
          description: URL of the video resource (e.g., MP4, M3U8 playlist).
          format: url
          example: https://stream.hyperhuman.cc/video/workout-123/master.m3u8?token=...
        poster:
          type: object
          description: URL of a poster image to display before video playback.
          format: url
          example: https://assets.hyperhuman.cc/video/workout-123/poster.jpg
        thumbnail:
          type: object
          description: URL of a thumbnail image representing the video.
          format: url
          example: https://assets.hyperhuman.cc/video/workout-123/thumb.jpg
        loop:
          type: number
          description: Playback looping behavior hint. 0 = no loop, -1 = infinite loop, >0 = specific number of loops (if supported by player). Default is typically 0 or 1 depending on context.
          example: -1
          default: 0
      required:
        - url
    ImageLinks:
      type: object
      properties:
        url:
          type: string
          description: URL of the primary/original image.
          format: url
          example: https://assets.hyperhuman.cc/images/workout-cover-123.jpg
        thumbnail:
          type: object
          description: URL of a smaller (thumbnail) version of the image.
          format: url
          example: https://assets.hyperhuman.cc/images/workout-thumb-123.jpg
      required:
        - url
    Category:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the category.
          example: cat-hiit-123
        name:
          type: string
          description: Display name of the category. Localized based on locale query parameter.
          example: HIIT
      required:
        - id
        - name
    Equipment:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the equipment item.
          example: eq-dumbbell-abc
        name:
          type: string
          description: Display name of the equipment. Localized based on locale query parameter.
          example: Dumbbell
      required:
        - id
        - name
    MusicPlaylistLink:
      type: object
      properties:
        url:
          type: string
          description: URL of the music playlist on an external platform (e.g., Spotify, Apple Music).
          format: url
          example: https://open.spotify.com/playlist/37i9dQZF1DX...
      required:
        - url
    MusicPlaylists:
      type: object
      properties:
        spotify:
          description: Spotify music playlist
          allOf:
            - $ref: '#/components/schemas/MusicPlaylistLink'
        youtube:
          description: Youtube music playlist
          allOf:
            - $ref: '#/components/schemas/MusicPlaylistLink'
        appleMusic:
          description: Apple Music playlist
          allOf:
            - $ref: '#/components/schemas/MusicPlaylistLink'
        amazonMusic:
          description: Amazon Music playlist
          allOf:
            - $ref: '#/components/schemas/MusicPlaylistLink'
    ShareLink:
      type: object
      properties:
        url:
          type: string
          description: URL that can be shared to provide access or reference to the resource.
          format: url
          example: https://share.hyperhuman.cc/w/a1b2c3d4
      required:
        - url
    Organization:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the organization.
          example: org-fitness-first
        name:
          type: string
          description: Display name of the organization.
          example: Fitness First Gym
        logo:
          description: Links to the organization's logo images (if available).
          allOf:
            - $ref: '#/components/schemas/ImageLinks'
      required:
        - id
        - name
    MuscleGroupPercentage:
      type: object
      properties:
        muscleGroupId:
          type: string
          description: Unique identifier of the muscle group
          example: 507f1f77bcf86cd799439011
        muscleGroupName:
          type: string
          description: Localized name of the muscle group
          example: Chest
        percentage:
          type: number
          description: Percentage of workout focused on this muscle group
          minimum: 0
          maximum: 100
          example: 35.5
      required:
        - muscleGroupId
        - muscleGroupName
        - percentage
    Workout:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier (UUID) for the workout.
          example: 12ab3efd45c67c1234566cd1
        createdAt:
          format: date-time
          type: string
          description: Timestamp when the workout was created.
          example: '2023-10-26T10:00:00.000Z'
        updatedAt:
          format: date-time
          type: string
          description: Timestamp when the workout was last updated.
          example: '2023-10-27T11:30:00.000Z'
        trainer:
          description: Reference to the trainer associated with the workout.
          allOf:
            - $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
          description: Display name of the workout. Localized based on locale query parameter.
          example: Full Body Blast
        description:
          type: string
          description: Detailed description of the workout, potentially including goals and target audience. Localized based on locale query parameter.
          example: A 30-minute high-intensity interval training session designed to improve cardiovascular fitness and strength.
        audioIntro:
          description: Localized workout introduction audio. Selected based on locale query parameter and user preferences.
          allOf:
            - $ref: '#/components/schemas/WorkoutAudio'
        audioOutro:
          description: Localized workout outro audio. Selected based on locale query parameter and user preferences.
          allOf:
            - $ref: '#/components/schemas/WorkoutAudio'
        duration:
          type: number
          description: Estimated workout duration in seconds.
          example: 1800
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Raw difficulty enum value (beginner|intermediate|advanced). Clients should map to localized strings. Null if not specified.
          example: beginner
        preview:
          description: Links to preview video streams (e.g., HLS, MP4). Null if no preview is available.
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        images:
          description: Links to workout images (thumbnail, cover, etc.). Null if no images are available.
          allOf:
            - $ref: '#/components/schemas/ImageLinks'
        rating:
          type: number
          description: Average user rating (e.g., 1-5). Null if not rated.
          example: 4.5
        visibility:
          type: string
          enum:
            - private
            - public
          description: Visibility level of the workout.
          example: public
        locked:
          type: boolean
          description: Indicates if the workout requires a subscription or specific entitlement to access.
          example: false
        mixBgMusic:
          type: boolean
          description: Whether to mix background music with workout audio. If true, background music will be played alongside exercise instructions.
          example: true
        presentationStyle:
          type: string
          enum:
            - full
            - minimal
            - essential
            - noOverlays
          description: Video overlay presentation style. Controls which UI elements are shown during workout playback.
          example: full
        skipWorkoutPreview:
          type: boolean
          description: If true, skip workout preview/intro segment in interactive player
          example: false
        skipWorkoutCompletionScreen:
          type: boolean
          description: If true, skip workout completion/outro screen in interactive player
          example: false
        videoAudioMode:
          type: string
          enum:
            - full
            - instructionsOnly
            - beepsOnly
            - none
          description: Audio mode for video export. Controls which audio components are included.
          example: full
        categories:
          description: List of categories associated with the workout (e.g., HIIT, Strength, Yoga). Category names are localized based on locale query parameter.
          type: array
          items:
            $ref: '#/components/schemas/Category'
        allowAssessment:
          type: boolean
          description: Whether this workout supports AI assessment mode
          example: false
        assessmentType:
          type: string
          enum:
            - mobility_baseline
            - glp1_muscle_guard
            - movement_assessment
            - overall_assessment
            - learning_tutorial
            - learning_practice
          description: Type of assessment supported (if allowAssessment is true)
          example: mobility_baseline
          nullable: true
        equipment:
          description: List of equipment required or recommended for the workout. Equipment names are localized based on locale query parameter.
          type: array
          items:
            $ref: '#/components/schemas/Equipment'
        musicPlaylists:
          description: Links to suggested music playlists on various platforms (Spotify, Apple Music, etc.).
          allOf:
            - $ref: '#/components/schemas/MusicPlaylists'
        shareLink:
          description: A shareable link for the workout.
          allOf:
            - $ref: '#/components/schemas/ShareLink'
        organization:
          description: Reference to the organization that owns/published this workout, if applicable.
          allOf:
            - $ref: '#/components/schemas/Organization'
        video:
          description: Links to the full workout video streams (e.g., HLS, MP4). Use /export/video/stream_url for potentially temporary direct stream URLs.
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        muscleGroupPercentages:
          description: Percentage distribution of muscle groups in this workout, sorted by highest percentage first
          type: array
          items:
            $ref: '#/components/schemas/MuscleGroupPercentage'
      required:
        - id
        - createdAt
        - updatedAt
        - trainer
        - name
        - description
        - duration
        - visibility
        - locked
        - categories
        - equipment
        - shareLink
        - muscleGroupPercentages
    WorkoutResponse:
      type: object
      properties:
        data:
          description: Contains the detailed workout object.
          allOf:
            - $ref: '#/components/schemas/Workout'
      required:
        - data
    PageLinks:
      type: object
      properties:
        next:
          type: string
          description: URL of the next page. Missing if there is no next page.
          example: https://content.api.hyperhuman.cc/resource/next-page-link
        total:
          type: number
          description: Total number of items available across all pages.
          example: 100
    WorkoutListItem:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier (UUID) for the workout.
          example: 12ab3efd45c67c1234566cd1
        createdAt:
          format: date-time
          type: string
          description: Timestamp when the workout was created.
          example: '2023-10-26T10:00:00.000Z'
        updatedAt:
          format: date-time
          type: string
          description: Timestamp when the workout was last updated.
          example: '2023-10-27T11:30:00.000Z'
        trainer:
          description: Reference to the trainer associated with the workout.
          allOf:
            - $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
          description: Display name of the workout. Localized based on locale query parameter.
          example: Full Body Blast
        description:
          type: string
          description: Detailed description of the workout, potentially including goals and target audience. Localized based on locale query parameter.
          example: A 30-minute high-intensity interval training session designed to improve cardiovascular fitness and strength.
        audioIntro:
          description: Localized workout introduction audio. Selected based on locale query parameter and user preferences.
          allOf:
            - $ref: '#/components/schemas/WorkoutAudio'
        audioOutro:
          description: Localized workout outro audio. Selected based on locale query parameter and user preferences.
          allOf:
            - $ref: '#/components/schemas/WorkoutAudio'
        duration:
          type: number
          description: Estimated workout duration in seconds.
          example: 1800
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Raw difficulty enum value (beginner|intermediate|advanced). Clients should map to localized strings. Null if not specified.
          example: beginner
        preview:
          description: Links to preview video streams (e.g., HLS, MP4). Null if no preview is available.
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        images:
          description: Links to workout images (thumbnail, cover, etc.). Null if no images are available.
          allOf:
            - $ref: '#/components/schemas/ImageLinks'
        rating:
          type: number
          description: Average user rating (e.g., 1-5). Null if not rated.
          example: 4.5
        visibility:
          type: string
          enum:
            - private
            - public
          description: Visibility level of the workout.
          example: public
        locked:
          type: boolean
          description: Indicates if the workout requires a subscription or specific entitlement to access.
          example: false
        mixBgMusic:
          type: boolean
          description: Whether to mix background music with workout audio. If true, background music will be played alongside exercise instructions.
          example: true
        presentationStyle:
          type: string
          enum:
            - full
            - minimal
            - essential
            - noOverlays
          description: Video overlay presentation style. Controls which UI elements are shown during workout playback.
          example: full
        skipWorkoutPreview:
          type: boolean
          description: If true, skip workout preview/intro segment in interactive player
          example: false
        skipWorkoutCompletionScreen:
          type: boolean
          description: If true, skip workout completion/outro screen in interactive player
          example: false
        videoAudioMode:
          type: string
          enum:
            - full
            - instructionsOnly
            - beepsOnly
            - none
          description: Audio mode for video export. Controls which audio components are included.
          example: full
        categories:
          description: List of categories associated with the workout (e.g., HIIT, Strength, Yoga). Category names are localized based on locale query parameter.
          type: array
          items:
            $ref: '#/components/schemas/Category'
        allowAssessment:
          type: boolean
          description: Whether this workout supports AI assessment mode
          example: false
        assessmentType:
          type: string
          enum:
            - mobility_baseline
            - glp1_muscle_guard
            - movement_assessment
            - overall_assessment
            - learning_tutorial
            - learning_practice
          description: Type of assessment supported (if allowAssessment is true)
          example: mobility_baseline
          nullable: true
      required:
        - id
        - createdAt
        - updatedAt
        - trainer
        - name
        - description
        - duration
        - visibility
        - locked
        - categories
    WorkoutListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/WorkoutListItem'
        explanation:
          type: string
          description: Explanation for how this list was filtered or sorted
      required:
        - links
        - data
    EndUserProfileDetailsDto:
      type: object
      properties:
        age:
          type: number
          description: 'User age. Maps to age groups (16-24: Young, 25-34: Young Adult, 35-44: Early Middle Age, 45-54: Mid Life, 55-64: Late Middle Age, 65-74: Early Senior, 75+: Senior) for appropriate exercise intensity selection.'
          minimum: 16
          maximum: 99
          example: 32
        gender:
          type: string
          enum:
            - male
            - female
            - other
          description: User gender. Influences coach gender matching preference (not guaranteed match).
          example: female
        fitnessLevels:
          type: array
          description: User fitness levels. Only the FIRST level is used for exercise difficulty selection. Provide only one for clarity. AI may adjust actual workout difficulty based on exercise availability and safety considerations.
          example:
            - intermediate
          items:
            type: string
            enum:
              - beginner
              - intermediate
              - advanced
        goalIds:
          description: Goal IDs the user is interested in. Currently accepted but not used in workout generation logic.
          example:
            - 63c92926f920a9005c4e619c
          type: array
          items:
            type: string
        trainingDaysPerWeek:
          type: number
          description: Number of days per week the user wants to train. Currently accepted but not used in workout generation logic.
          minimum: 1
          maximum: 7
          example: 4
        preferredEquipmentCategoryIds:
          description: Preferred equipment category IDs. Used as guidance (not strict filter). AI may include bodyweight exercises for safety. Use GET /v1/workouts/equipment/metadata to fetch available equipment categories.
          example:
            - 67deb36a6a5e49797c122f56
            - 67deb3696a5e49797c122f55
          type: array
          items:
            type: string
        endUserId:
          type: string
          description: End user profile ID for personalization. When provided, user context (workout history, digest, metrics) is used for AI workout generation and recommendations. Must belong to the same organization as the request.
          example: 64e3bca9d1b7e600141a9712
    WorkoutRecommendationRequestDto:
      type: object
      properties:
        endUserProfileDetails:
          description: Detailed user profile information for personalized recommendations
          allOf:
            - $ref: '#/components/schemas/EndUserProfileDetailsDto'
        locale:
          type: string
          description: Preferred BCP-47 locale for recommendation text when the stack supports it.
          example: en-US
    RecommendedWorkoutDto:
      type: object
      properties:
        id:
          type: string
          description: Workout ID
        name:
          type: string
          description: Workout name
        description:
          type: string
          description: Workout description
        duration:
          type: number
          description: Workout duration in seconds
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
        thumbnailUrl:
          type: string
          description: URL to workout thumbnail image
        recommendation:
          type: string
          description: Reasoning for this recommendation
        categories:
          description: Workout categories
          items:
            type: array
          type: array
        preview:
          description: Preview video (playable URL when available). url is empty when only a thumbnail image exists.
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
      required:
        - id
        - name
        - description
        - duration
        - difficulty
        - thumbnailUrl
        - recommendation
        - categories
    WorkoutRecommendationResponseDto:
      type: object
      properties:
        workouts:
          description: List of recommended workouts (max 12)
          type: array
          items:
            $ref: '#/components/schemas/RecommendedWorkoutDto'
        reasoning:
          type: string
          description: Overall explanation for the recommendation strategy used
      required:
        - workouts
        - reasoning
    WorkoutDurationOptionsDto:
      type: object
      properties:
        minMinutes:
          type: number
          description: Minimum workout duration in minutes
          minimum: 5
          example: 5
        maxMinutes:
          type: number
          description: Maximum workout duration in minutes
          minimum: 5
          example: 30
    WorkoutGenerationRequestDto:
      type: object
      properties:
        endUserProfileDetails:
          description: Detailed user profile information for personalized workout generation.
          allOf:
            - $ref: '#/components/schemas/EndUserProfileDetailsDto'
        exerciseSources:
          type: array
          description: Preferred source(s) of exercises. Use only `premium_stock` for consistent quality, or `team_exercises` for brand consistency. Avoid mixing `free_stock` with `premium_stock` for visual consistency.
          example:
            - premium_stock
          items:
            type: string
            enum:
              - premium_stock
              - free_stock
              - team_exercises
        durationOptions:
          description: Preferred workout duration range in minutes. You can specify minimum and maximum duration to generate workouts within a specific time range.
          example:
            minMinutes: 5
            maxMinutes: 30
          allOf:
            - $ref: '#/components/schemas/WorkoutDurationOptionsDto'
        categoryId:
          type: string
          description: Workout category ID to theme the workout. Use GET /v1/workouts/metadata to fetch available categories (HIIT, Strength, Mobility, Cardio, etc.).
          example: 615aa3f0dbe7140012c59e94
        muscleGroupIds:
          description: Muscle group IDs to focus on during the workout. The workout will be generated with emphasis on exercises that target these muscle groups. Use the GET /v1/workouts/exercises/metadata endpoint to fetch the available muscle groups. Note that this is used for guidance, not as a strict filter - the workout will still include exercises for complementary muscle groups as needed.
          example:
            - 604b0129beaba770c284ff40
            - 604b0165076fe2727354d73e
          type: array
          items:
            type: string
        excludeExerciseCollections:
          description: Array of exercise collection names to exclude from workout generation. Exercises with matching collectionName (case-insensitive) will be filtered out. Use GET /v1/workouts/exercises/metadata to fetch the current list of available exercise collections with exercise counts.
          example:
            - Free - Eclectic Home
            - Premium - Industrial
          type: array
          items:
            type: string
        userRequirements:
          type: string
          description: High-level context, definitions, and guidelines for workout generation. Provides customer-specific grounding (e.g., "intermediate osteoporosis strength training", "one-sided exercises, rep schemes"). Used to inform exercise selection, intensity, and structure.
          example: Intermediate strength / stimulus, one-sided exercises, rep schemes. Focus on controlled movements suitable for osteoporosis patients.
          maxLength: 2000
    ApiExerciseDto:
      type: object
      properties:
        id:
          type: string
          description: Exercise id (24-character hex DB id)
        name:
          type: string
          description: Name of the exercise
        description:
          type: string
          description: Description of the exercise
        thumbnailUrl:
          type: string
          description: Thumbnail URL for the exercise video
        videoUri:
          type: string
          description: Main video URI (e.g., signed S3 URL for MP4 or HLS master)
        estimatedRepDuration:
          type: number
          description: Estimated duration of one repetition in milliseconds
        muscleGroups:
          description: Primary muscle groups targeted
          type: array
          items:
            type: string
        equipment:
          description: Equipment needed for this exercise
          type: array
          items:
            type: string
        collectionName:
          type: string
          description: Collection name (free text)
        coach:
          type: string
          enum:
            - male
            - female
          description: Coach gender
        tags:
          description: User-defined tags (up to 5)
          type: array
          items:
            type: string
        skillLevel:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Skill level
        categories:
          type: array
          description: Exercise categories (up to 3)
          items:
            type: string
            enum:
              - strength
              - cardio
              - mobility
              - balance
              - endurance
              - flexibility
              - plyometrics
              - recovery
              - running
        executionSide:
          type: string
          enum:
            - both
            - left
            - right
            - alternating
          description: Execution side
        showcasedReps:
          type: number
          description: Showcased number of reps
      required:
        - id
        - name
    ApiInstanceDto:
      type: object
      properties:
        id:
          type: string
          description: Instance id (24-character hex DB id)
        kind:
          type: string
          enum:
            - rest
            - single-exercise
            - multi-exercise
            - class
            - promo
            - educational
          description: Kind of instance (e.g., rest, singleExercise)
        durationSeconds:
          type: number
          description: Duration in seconds (for time-based exercises and rests). Check service implementation for actual unit and convert if necessary.
        reps:
          type: number
          description: Number of repetitions (for reps-based exercises)
        exercise:
          description: Exercise details, if this instance is an exercise.
          allOf:
            - $ref: '#/components/schemas/ApiExerciseDto'
        skipIntro:
          type: boolean
          description: Whether to skip intro for the exercise video.
        pace:
          type: string
          enum:
            - slow
            - medium
            - fast
          nullable: true
          description: Pacing for time-based exercises.
        weightLevel:
          type: string
          enum:
            - light
            - medium
            - heavy
          nullable: true
          description: Weight level for reps-based exercises.
        rpe:
          type: number
          description: Rate of Perceived Exertion (0-10). Target intensity for this exercise. When not provided, no specific RPE guidance.
          minimum: 0
          maximum: 10
        amrap:
          type: boolean
          description: As Many Reps As Possible (duration-based only)
          default: false
        weight:
          type: number
          description: Prescribed/target weight (0-1000). Unit in weightUnit.
          minimum: 0
          maximum: 1000
        weightUnit:
          type: string
          enum:
            - metric
            - imperial
          description: 'Unit for weight: metric (kg) or imperial (lbs).'
      required:
        - id
        - kind
    WorkoutGenerationResponseDto:
      type: object
      properties:
        name:
          type: string
          description: Name of the generated workout.
        instances:
          description: List of instances (exercises and rests) in the workout.
          type: array
          items:
            $ref: '#/components/schemas/ApiInstanceDto'
        totalDurationSeconds:
          type: number
          description: Estimated total duration of the workout in seconds. Calculated if possible.
        difficulty:
          type: string
          description: Overall difficulty of the workout, as determined or used by the generator.
        categoryId:
          type: string
          description: The category ID used for generating the workout.
      required:
        - name
        - instances
    AdaptationEndUserProfileDetailsDto:
      type: object
      properties:
        age:
          type: number
          description: User age
          minimum: 16
          maximum: 99
          example: 32
        gender:
          type: string
          enum:
            - male
            - female
            - other
          description: User gender
          example: female
        fitnessLevels:
          type: array
          description: User fitness levels. First level is primary.
          example:
            - intermediate
          items:
            type: string
            enum:
              - beginner
              - intermediate
              - advanced
        goalIds:
          description: Goal IDs
          example:
            - 63c92926f920a9005c4e619c
          type: array
          items:
            type: string
        trainingDaysPerWeek:
          type: number
          description: Training days per week
          minimum: 1
          maximum: 7
          example: 4
        preferredEquipmentCategoryIds:
          description: Preferred equipment category IDs
          type: array
          items:
            type: string
    WorkoutAdaptationRequestDto:
      type: object
      properties:
        endUserProfileId:
          type: string
          description: End user profile ID for fetching 60-day wearable data, workout feedback, and completed sessions
          example: 64e3bca9d1b7e600141a9712
        endUserProfileDetails:
          description: User profile information for workout adaptation
          allOf:
            - $ref: '#/components/schemas/AdaptationEndUserProfileDetailsDto'
        exerciseSources:
          type: array
          description: Exercise sources for potential substitutions
          example:
            - premium_stock
            - team_exercises
          items:
            type: string
            enum:
              - premium_stock
              - free_stock
              - team_exercises
        userGuidance:
          type: string
          description: User free text for guidance/feedback/context/injury/environment/constraints
          example: I have a slight knee injury, avoid high-impact exercises. Working out at home with limited space.
          maxLength: 2000
      required:
        - endUserProfileDetails
        - exerciseSources
    WorkoutAdaptationResponseDto:
      type: object
      properties:
        name:
          type: string
          description: Adapted workout name
        instances:
          description: Adapted instances
          type: array
          items:
            $ref: '#/components/schemas/ApiInstanceDto'
        totalDurationSeconds:
          type: number
          description: Total duration in seconds
        difficulty:
          type: string
          description: Adapted workout difficulty
        categoryId:
          type: string
          description: Original category ID (preserved)
        adaptationReasoning:
          type: string
          description: Explanation of adaptations made
      required:
        - name
        - instances
        - adaptationReasoning
    AutopilotTaskResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Task ID
        organizationId:
          type: string
          description: Organization ID
        ownerId:
          type: string
          description: Task owner ID
        name:
          type: string
          description: Task name
        status:
          type: string
          enum:
            - active
            - draft
          description: Task status
        scope:
          type: string
          enum:
            - ai_generate
            - create_similar
            - publish_existing
          description: Task scope
        contentType:
          type: string
          enum:
            - workout
            - program
          description: Content type
        sourceContentId:
          type: string
          description: Source content ID (for create_similar)
        existingContentId:
          type: string
          description: Existing content ID (for publish_existing)
        categoryIds:
          description: Category IDs
          type: array
          items:
            type: string
        goalIds:
          description: Goal IDs
          type: array
          items:
            type: string
        durationMin:
          type: number
          description: Min duration
        durationMax:
          type: number
          description: Max duration
        workoutsPerWeekMin:
          type: number
          description: Min workouts per week
        workoutsPerWeekMax:
          type: number
          description: Max workouts per week
        difficultyOptions:
          description: Difficulty options
          type: array
          items:
            type: string
        includeFreeStock:
          type: boolean
          description: Include free stock exercises
        includePremiumStock:
          type: boolean
          description: Include premium stock exercises
        includeTeamContent:
          type: boolean
          description: Include team exercises
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
          description: Repeat schedule
        repeatUntil:
          format: date-time
          type: string
          description: Repeat until date
        nextRunAt:
          type: object
          description: Next scheduled execution
          format: date-time
          nullable: true
        lastRunAt:
          type: object
          description: Last execution time
          format: date-time
          nullable: true
        assignToClientUserIds:
          description: Client user IDs for content assignment
          type: array
          items:
            type: string
        promptGuidanceMode:
          type: string
          enum:
            - none
            - custom
            - ai_tuned
            - ai_driven
          description: Prompt guidance mode
        customPromptGuidance:
          type: string
          description: Custom prompt guidance text
        createdAt:
          format: date-time
          type: string
          description: Created at
        updatedAt:
          format: date-time
          type: string
          description: Updated at
      required:
        - id
        - organizationId
        - ownerId
        - name
        - status
        - scope
        - contentType
        - difficultyOptions
        - includeFreeStock
        - includePremiumStock
        - includeTeamContent
        - repeatMode
        - createdAt
        - updatedAt
    CreateAutopilotTaskDto:
      type: object
      properties:
        name:
          type: string
          description: User-friendly task name (max 200 chars)
          example: Daily HIIT Generator
        scope:
          type: string
          enum:
            - ai_generate
            - create_similar
            - publish_existing
          description: 'Task scope: ai_generate, create_similar, or publish_existing'
        contentType:
          type: string
          enum:
            - workout
            - program
          description: 'Content type to create: workout or program'
        sourceContentId:
          type: string
          description: Source workout/program ID (required for create_similar scope)
        existingContentId:
          type: string
          description: Existing workout/program ID (required for publish_existing scope)
        categoryIds:
          description: Workout category IDs. One picked randomly per run when multiple.
          type: array
          items:
            type: string
        goalIds:
          description: Program goal IDs. One picked randomly per run when multiple.
          type: array
          items:
            type: string
        durationMin:
          type: number
          description: Min duration (minutes for workouts, weeks for programs)
          minimum: 1
        durationMax:
          type: number
          description: Max duration (minutes for workouts, weeks for programs). Must be >= durationMin.
          minimum: 1
        workoutsPerWeekMin:
          type: number
          description: Min workouts per week (programs only)
          minimum: 1
          maximum: 7
        workoutsPerWeekMax:
          type: number
          description: Max workouts per week (programs only). Must be >= workoutsPerWeekMin.
          minimum: 1
          maximum: 7
        difficultyOptions:
          type: array
          description: Difficulty options (1-3 values). One picked randomly per run when multiple.
          example:
            - beginner
            - intermediate
          items:
            type: string
            enum:
              - beginner
              - intermediate
              - advanced
        includeFreeStock:
          type: boolean
          description: Include free stock exercises
          default: true
        includePremiumStock:
          type: boolean
          description: Include premium stock exercises (requires premiumStock entitlement)
          default: false
        includeTeamContent:
          type: boolean
          description: Include team exercises
          default: false
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
          description: 'Repeat schedule: once, daily, weekly, biweekly, monthly'
        repeatUntil:
          type: string
          description: Repeat until date (ISO 8601). Omit for indefinite scheduling.
        nextRunAt:
          type: string
          description: Initial scheduled execution date (ISO 8601). When omitted, computed on activation.
        assignToClientUserIds:
          description: Client user IDs to assign created content to (max 100)
          type: array
          items:
            type: string
        promptGuidanceMode:
          type: string
          enum:
            - none
            - custom
            - ai_tuned
            - ai_driven
          description: 'Prompt guidance mode: none, custom, ai_tuned, ai_driven'
          default: none
        customPromptGuidance:
          type: string
          description: Custom prompt guidance text (max 2000 chars). Used when promptGuidanceMode is custom.
          maxLength: 2000
      required:
        - name
        - scope
        - contentType
        - difficultyOptions
        - repeatMode
    UpdateAutopilotTaskDto:
      type: object
      properties:
        name:
          type: string
          description: Task name (max 200 chars)
        categoryIds:
          description: Workout category IDs
          type: array
          items:
            type: string
        goalIds:
          description: Program goal IDs
          type: array
          items:
            type: string
        durationMin:
          type: number
          description: Min duration
        durationMax:
          type: number
          description: Max duration
        workoutsPerWeekMin:
          type: number
          description: Min workouts per week (programs only)
        workoutsPerWeekMax:
          type: number
          description: Max workouts per week (programs only)
        difficultyOptions:
          type: array
          description: Difficulty options
          items:
            type: string
            enum:
              - beginner
              - intermediate
              - advanced
        includeFreeStock:
          type: boolean
          description: Include free stock exercises
        includePremiumStock:
          type: boolean
          description: Include premium stock exercises
        includeTeamContent:
          type: boolean
          description: Include team exercises
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
          description: Repeat schedule
        repeatUntil:
          type: string
          description: Repeat until date (ISO 8601)
        nextRunAt:
          type: string
          description: Next run date (ISO 8601). Use to reschedule an active task.
        assignToClientUserIds:
          description: Client user IDs to assign content to
          type: array
          items:
            type: string
        promptGuidanceMode:
          type: string
          enum:
            - none
            - custom
            - ai_tuned
            - ai_driven
          description: Prompt guidance mode
        customPromptGuidance:
          type: string
          description: Custom prompt guidance text (max 2000 chars)
          maxLength: 2000
    ExportDropDto:
      type: object
      properties:
        channelPreset:
          type: string
          enum:
            - ig_reels
            - ig_stories
            - ig_carousel
            - tiktok
            - yt_shorts
            - fb_reels
            - yt_longform
          description: Channel preset; if omitted, uses drop channelPreset
        aspectRatio:
          type: string
          enum:
            - '9:16'
            - '1:1'
            - '16:9'
          description: Aspect ratio override
        duration:
          type: number
          enum:
            - 15
            - 30
            - 60
          description: Duration in seconds override
    OrganizationConnectedPlatformsResponseDto:
      type: object
      properties:
        connectedPlatforms:
          type: array
          description: Social platforms (instagram, tiktok, youtube, facebook) that have a connected account id stored for this organization
          items:
            type: string
            enum:
              - instagram
              - tiktok
              - youtube
              - facebook
      required:
        - connectedPlatforms
    OrganizationSocialPublishTaskResponseDto:
      type: object
      properties:
        _id:
          type: string
          deprecated: true
          description: Deprecated. Legacy internal id; use `id` instead. Will be removed in the next major Content API release.
        _teamId:
          type: string
          deprecated: true
          description: Deprecated. Legacy internal team id; use `organizationId` instead. Will be removed in the next major Content API release.
        _ownerId:
          type: string
          deprecated: true
          description: Deprecated. Legacy internal owner id; use `ownerId` instead. Will be removed in the next major Content API release.
        name:
          type: string
        status:
          type: string
          enum:
            - active
            - draft
        publishAssetType:
          type: string
          enum:
            - social_drop
            - workout_full_video
        sourceMode:
          type: string
          enum:
            - manual_fixed
            - random_ready
            - ai_insights
            - ai_pick
        dropId:
          type: string
        workoutId:
          type: string
        publishCopyPacks:
          type: object
          description: 'workout_full_video: sanitized copy packs per channel (same shape as drop copyPacks).'
        workoutExportLocale:
          type: string
        coverOverridesByChannel:
          type: object
          description: 'workout_full_video: S3 object keys for social/AI covers by channel preset and aspect ratio (same shape as Drop.coverOverridesByChannel). Not workout library thumbnails.'
        readyDropPick:
          type: string
          enum:
            - random
            - latest
        allowedDropSourceTypes:
          type: array
          items:
            type: string
            enum:
              - exercise
              - exerciseCollection
              - workout
              - workoutCollection
        primaryChannelPreset:
          type: string
          enum:
            - ig_reels
            - ig_stories
            - ig_carousel
            - tiktok
            - yt_shorts
            - fb_reels
            - yt_longform
        channelPresets:
          type: array
          items:
            type: string
            enum:
              - ig_reels
              - ig_stories
              - ig_carousel
              - tiktok
              - yt_shorts
              - fb_reels
              - yt_longform
        exportAspectRatio:
          type: string
          enum:
            - '9:16'
            - '1:1'
            - '16:9'
        exportDurationSeconds:
          type: number
          enum:
            - 15
            - 30
            - 60
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
        repeatUntil:
          type: object
          nullable: true
        nextRunAt:
          type: object
        lastRunAt:
          type: object
        createdAt:
          format: date-time
          type: string
        updatedAt:
          format: date-time
          type: string
        id:
          type: string
          description: Automation ID. Use this for all subsequent /v1/orgs/{orgId}/social-publish/{taskId} calls.
        organizationId:
          type: string
          description: Organization (team) ID that owns this automation.
        ownerId:
          type: string
          description: User ID of the organization owner that the automation runs on behalf of.
        lastRunOutcome:
          type: string
          enum:
            - success
            - failed
            - skipped_limit
            - skipped_no_drop
            - skipped_no_workout_export
            - skipped_zernio_config
          description: Outcome of the most recent execution event for this automation
        lastErrorSummary:
          type: string
          description: Error or skip message from the most recent execution when it was not a success
        lastExecutionAt:
          format: date-time
          type: string
          description: Timestamp of the most recent execution event
      required:
        - name
        - status
        - publishAssetType
        - sourceMode
        - readyDropPick
        - allowedDropSourceTypes
        - primaryChannelPreset
        - channelPresets
        - repeatMode
        - createdAt
        - updatedAt
        - id
        - organizationId
        - ownerId
    OrganizationSocialPublishTaskListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/OrganizationSocialPublishTaskResponseDto'
      required:
        - links
        - data
    CreateSocialDropPublishTaskDto:
      type: object
      properties:
        name:
          type: string
          description: Automation name
        publishAssetType:
          type: string
          enum:
            - social_drop
            - workout_full_video
          description: Defaults to social_drop. Use workout_full_video for full WorkoutExport video (not a social drop).
        sourceMode:
          type: string
          enum:
            - manual_fixed
            - random_ready
            - ai_insights
            - ai_pick
          description: Required for social_drop automations. When publishAssetType is workout_full_video, omit to default to manual_fixed.
        dropId:
          type: string
          description: Required when sourceMode is manual_fixed and publishAssetType is social_drop
        workoutId:
          type: string
          description: Required when publishAssetType is workout_full_video
        publishCopyPacks:
          type: object
          description: 'workout_full_video: copy packs per channel (same fields as drop copyPacks). The outbound publish payload uses copy for primaryChannelPreset; if hook and caption are both empty at run time, Gemini generates and the result is saved on the task.'
        workoutExportLocale:
          type: string
          description: Locale for choosing WorkoutExport variant when publishAssetType is workout_full_video
        locale:
          type: string
          description: Alias for workoutExportLocale when publishAssetType is workout_full_video. If both are set, workoutExportLocale wins.
        readyDropPick:
          type: string
          enum:
            - random
            - latest
          description: 'For random_ready / ai_insights: random among up to 80 most recently updated ready drops, or single latest by updatedAt. Ignored for manual_fixed.'
          default: random
        allowedDropSourceTypes:
          type: array
          description: Pool of drop source types (exercise=clip/video, exerciseCollection=exercise groups, workout, workoutCollection=program). Omit or empty = all types.
          items:
            type: string
            enum:
              - exercise
              - exerciseCollection
              - workout
              - workoutCollection
        primaryChannelPreset:
          type: string
          enum:
            - ig_reels
            - ig_stories
            - ig_carousel
            - tiktok
            - yt_shorts
            - fb_reels
            - yt_longform
        channelPresets:
          type: array
          description: Target channel presets for publishing; must include primary.
          items:
            type: string
            enum:
              - ig_reels
              - ig_stories
              - ig_carousel
              - tiktok
              - yt_shorts
              - fb_reels
              - yt_longform
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
        repeatUntil:
          type: string
          description: Repeat until (ISO 8601)
        nextRunAt:
          type: string
          description: Next run (ISO 8601)
        exportAspectRatio:
          type: string
          enum:
            - '9:16'
            - '1:1'
            - '16:9'
          description: Export variant aspect ratio override
        exportDurationSeconds:
          type: number
          enum:
            - 15
            - 30
            - 60
          description: Export variant duration override (seconds)
      required:
        - name
        - primaryChannelPreset
        - channelPresets
        - repeatMode
    OrganizationPatchSocialPublishTaskDto:
      type: object
      properties:
        name:
          type: string
        publishAssetType:
          type: string
          enum:
            - social_drop
            - workout_full_video
        sourceMode:
          type: string
          enum:
            - manual_fixed
            - random_ready
            - ai_insights
            - ai_pick
        dropId:
          type: object
          nullable: true
          description: Id of the drop, or null to clear (omit to leave unchanged)
        workoutId:
          type: object
          nullable: true
          description: Id of the workout, or null to clear (omit to leave unchanged)
        publishCopyPacks:
          type: object
          description: 'workout_full_video: merges into existing publishCopyPacks by channel key (same semantics as PATCH drop copyPacks).'
        workoutExportLocale:
          type: object
        locale:
          type: object
          description: Alias for workoutExportLocale on workout_full_video tasks. If both are set in one request, workoutExportLocale wins.
        readyDropPick:
          type: string
          enum:
            - random
            - latest
        allowedDropSourceTypes:
          type: array
          items:
            type: string
            enum:
              - exercise
              - exerciseCollection
              - workout
              - workoutCollection
        primaryChannelPreset:
          type: string
          enum:
            - ig_reels
            - ig_stories
            - ig_carousel
            - tiktok
            - yt_shorts
            - fb_reels
            - yt_longform
        channelPresets:
          type: array
          items:
            type: string
            enum:
              - ig_reels
              - ig_stories
              - ig_carousel
              - tiktok
              - yt_shorts
              - fb_reels
              - yt_longform
        repeatMode:
          type: string
          enum:
            - once
            - daily
            - weekly
            - biweekly
            - monthly
        repeatUntil:
          type: object
          nullable: true
          description: ISO 8601 end of recurrence, or null to clear
        nextRunAt:
          type: string
        exportAspectRatio:
          type: string
          enum:
            - '9:16'
            - '1:1'
            - '16:9'
        exportDurationSeconds:
          type: number
          enum:
            - 15
            - 30
            - 60
        status:
          type: string
          enum:
            - active
            - draft
          description: Set to active to schedule runs (requires connected accounts for all channel preset platforms). Set to draft to pause and clear nextRunAt.
    WorkoutPlaylistResponse:
      type: object
      properties:
        data:
          description: An ordered array of workout segments. Each object in the array has a single key indicating the segment type (e.g., 'intro', 'exercise', 'break') and the value is the corresponding segment object.
          example:
            - intro:
                kind: workout-intro
                id: intro
                duration: 5.2
            - narrative:
                kind: workout-narrative
                id: narrative_background
                duration: 1800
            - exercise:
                kind: exercise
                id: exercise_squats_1
                exerciseId: 507f1f77bcf86cd799439011
                duration: 45
                name: Bodyweight Squats
            - break:
                kind: break
                id: break_1
                duration: 30
            - exercise:
                kind: exercise
                id: exercise_pushups_1
                exerciseId: 507f1f77bcf86cd799439012
                duration: 45
                name: Push-ups
            - outro:
                kind: workout-outro
                id: outro
                duration: 45.5
          type: array
          items:
            type: string
        presentationStyle:
          type: string
          enum:
            - full
            - minimal
            - essential
            - noOverlays
          description: Video overlay presentation style for this workout. Determines which UI elements the player should render. Null if not specified.
          example: full
        links:
          type: object
          description: Related links for the workout playlist (currently unused).
          example: {}
      required:
        - data
        - links
    WorkoutMusicTrack:
      type: object
      properties:
        id:
          type: string
          description: Track ID
          example: track_123
        name:
          type: string
          description: Track name
          example: Upbeat Workout Mix
        duration:
          type: number
          description: Track duration in seconds
          example: 180
        url:
          type: string
          description: Pre-signed S3 URL for the track
          example: https://s3.amazonaws.com/bucket/track.mp4a?signature=...
        filename:
          type: string
          description: Track filename
          example: upbeat-mix.mp4a
        bpm:
          type: number
          description: Track BPM (beats per minute)
          example: 128
      required:
        - id
        - name
        - duration
        - url
    WorkoutMusicPlaylistResponse:
      type: object
      properties:
        tracks:
          description: Ordered list of music tracks
          type: array
          items:
            $ref: '#/components/schemas/WorkoutMusicTrack'
        totalDuration:
          type: number
          description: Total playlist duration in seconds
          example: 1800
        workoutDuration:
          type: number
          description: Workout duration in seconds
          example: 1650
      required:
        - tracks
        - totalDuration
        - workoutDuration
    WorkoutSession:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the workout session.
          example: 12ab3efd45c67c1234566cd1
        createdAt:
          format: date-time
          type: string
          description: Timestamp when the session was created.
          example: '2023-10-28T10:00:00.000Z'
        updatedAt:
          format: date-time
          type: string
          description: Timestamp when the session was last updated.
          example: '2023-10-28T10:30:15.500Z'
        workoutId:
          type: string
          description: ID of the workout associated with this session.
          example: 12ab3efd45c67c1234566cd1
        workoutSegmentId:
          type: string
          description: ID of the current workout segment being played (from playlist). Use this to track which part of the workout the user is on.
          example: seg-exercise-2
        status:
          type: string
          description: Current status of the workout session.
          enum:
            - started
            - completed
          example: started
        duration:
          type: number
          description: Total actual playback time in seconds (not including pauses). This is the duration the user has been actively engaged with the workout.
          example: 125.5
          minimum: 0
        progress:
          type: number
          description: Completion progress as a fraction (0.0 = not started, 1.0 = 100% complete). Calculated based on current segment position within the total workout.
          example: 0.75
          minimum: 0
          maximum: 1
      required:
        - id
        - createdAt
        - updatedAt
        - workoutId
        - workoutSegmentId
        - status
        - duration
        - progress
    WorkoutSessionResponse:
      type: object
      properties:
        data:
          description: Contains the detailed workout session object.
          allOf:
            - $ref: '#/components/schemas/WorkoutSession'
      required:
        - data
    PatchWorkoutSessionBody:
      type: object
      properties:
        workoutSegmentId:
          type: string
          description: ID of the current workout segment.
          example: seg-exercise-squat-1
        progressSeconds:
          type: number
          description: Actual playback time in seconds. This is the primary method for tracking session duration accurately. Send this value on each PATCH to record how much time the user has actually spent playing the workout (excluding paused time). Duration is capped at 2x the expected workout duration.
          example: 125.5
          minimum: 0
        state:
          type: string
          description: '[Deprecated] This field is accepted for backward compatibility but does not affect duration calculation. Duration is tracked via progressSeconds.'
          enum:
            - active
            - paused
          example: paused
          deprecated: true
    EndWorkoutSessionBody:
      type: object
      properties:
        sessionId:
          type: string
          description: The ID of the session to end.
          example: session-uuid-12345
        progress:
          type: number
          description: '[Deprecated] This field is accepted but the actual progress is calculated from the last progressSeconds sent via PATCH.'
          example: 100
          deprecated: true
      required:
        - sessionId
    CompleteWorkoutSessionBody:
      type: object
      properties:
        sessionId:
          type: string
          description: The ID of the specific workout session to mark as completed with 100% progress.
          example: session-uuid-12345
      required:
        - sessionId
    WorkoutFeedbackRatingOption:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for this rating option
          example: 507f1f77bcf86cd799439011
        label:
          type: string
          description: Human-readable label for this rating option
          example: Very Good
        value:
          type: number
          description: Numeric value representing this rating
          example: 4
          minimum: 1
          maximum: 5
      required:
        - id
        - label
        - value
    WorkoutFeedbackDifficultyOption:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for this difficulty option
          example: 507f1f77bcf86cd799439012
        label:
          type: string
          description: Human-readable label for this difficulty level
          example: Challenging
        value:
          type: number
          description: Numeric value representing this difficulty level
          example: 4
          minimum: 1
          maximum: 5
      required:
        - id
        - label
        - value
    WorkoutFeedbackOptions:
      type: object
      properties:
        rating:
          type: array
          items:
            $ref: '#/components/schemas/WorkoutFeedbackRatingOption'
        difficulty:
          type: array
          items:
            $ref: '#/components/schemas/WorkoutFeedbackDifficultyOption'
      required:
        - rating
        - difficulty
    WorkoutFeedbackOptionsResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/WorkoutFeedbackOptions'
      required:
        - data
    ExerciseFeedbackData:
      type: object
      properties:
        instanceId:
          type: string
          description: Instance ID from workout playlist segment
          example: 64f1a2b3c4d5e6f7a8b9c0d1
        weight:
          type: number
          description: Weight used for this exercise (in the unit specified by weightUnit). Can be provided alone or together with reps.
          minimum: 0
          maximum: 1000
          example: 25.5
        reps:
          type: number
          description: Number of reps completed. Can be provided alone or together with weight. Required for AMRAP/time-based exercises or rep-based exercises.
          minimum: 1
          maximum: 100
          example: 15
      required:
        - instanceId
    SubmitWorkoutFeedbackBody:
      type: object
      properties:
        workoutSessionId:
          type: string
          description: The ID of the completed workout session this feedback pertains to.
          example: 12ab3efd45c67c1234566cd1
        ratingId:
          type: string
          description: Overall rating option ID. Refer to `GET /workouts/feedback/options` for possible values.
          example: rating-opt-5star
        difficultyId:
          type: string
          description: Perceived difficulty option ID. Refer to `GET /workouts/feedback/options` for possible values.
          example: difficulty-opt-moderate
        comment:
          type: string
          description: Optional free-text user comment about the workout.
          example: Great workout, but the music was a bit too loud.
          maxLength: 1000
        weightUnit:
          type: string
          enum:
            - metric
            - imperial
          description: Unit system for weight values. Required if exerciseData contains weight values.
          example: metric
        exerciseData:
          description: Exercise-specific data (weights and reps) in the same order as workout playlist (excluding rest segments).
          type: array
          items:
            $ref: '#/components/schemas/ExerciseFeedbackData'
      required:
        - workoutSessionId
    ExerciseFeedbackDataResponse:
      type: object
      properties:
        instanceId:
          type: string
          description: Instance ID from workout playlist identifying which exercise this feedback is for
          example: 64f1a2b3c4d5e6f7a8b9c0d2
        weight:
          type: number
          description: Weight used for this exercise (in weightUnit specified in feedback)
          example: 25.5
        reps:
          type: number
          description: Number of repetitions completed for this exercise
          example: 12
          minimum: 0
      required:
        - instanceId
    WorkoutFeedback:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for this feedback record
          example: 67d1a2b3c4e5f6789abc0d2
        createdAt:
          format: date-time
          type: string
          description: When this feedback was submitted
          example: '2025-01-10T09:30:00.000Z'
        updatedAt:
          format: date-time
          type: string
          description: When this feedback was last updated
          example: '2025-01-10T09:30:00.000Z'
        workoutId:
          type: string
          description: ID of the workout this feedback is for
          example: 12ab3efd45c67c1234566cd1
        workoutSessionId:
          type: string
          description: ID of the workout session this feedback is associated with
          example: 67d1a2b3c4e5f6789abc0d1
        rating:
          nullable: true
          description: User rating of the workout experience
          allOf:
            - $ref: '#/components/schemas/WorkoutFeedbackRatingOption'
        difficulty:
          nullable: true
          description: User assessment of workout difficulty level
          allOf:
            - $ref: '#/components/schemas/WorkoutFeedbackDifficultyOption'
        comment:
          type: string
          description: Optional user comment or additional feedback
          nullable: true
          example: Great workout! Felt appropriately challenging.
        weightUnit:
          type: string
          enum:
            - metric
            - imperial
          nullable: true
          description: Unit system used for weight measurements
          example: metric
        exerciseData:
          nullable: true
          description: Detailed performance data for individual exercises
          type: array
          items:
            $ref: '#/components/schemas/ExerciseFeedbackDataResponse'
      required:
        - id
        - createdAt
        - updatedAt
        - workoutId
        - workoutSessionId
        - rating
        - difficulty
    WorkoutFeedbackResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/WorkoutFeedback'
      required:
        - data
    MuscleGroup:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the muscle group.
          example: mg-legs-abc
        name:
          type: string
          description: Display name of the muscle group. Localized based on locale query parameter.
          example: Legs
      required:
        - id
        - name
    ExerciseBundleRefDto:
      type: object
      properties:
        id:
          type: string
          description: Bundle ID
        bundleIdentifier:
          type: string
          description: Asensei bundle identifier
        downloadUrl:
          type: string
          description: Pre-signed download URL for bundle JSON content
        displayName:
          type: string
          description: Human-readable display name
      required:
        - id
        - bundleIdentifier
        - downloadUrl
    AudioDto:
      type: object
      properties:
        id:
          type: string
        createdAt:
          format: date-time
          type: string
        assetUri:
          type: string
        type:
          type: string
        locale:
          type: string
        scriptText:
          type: string
          description: 'Verbatim transcript / script of the spoken instruction (the text the narrator reads in the `assetUri` clip). Useful for closed captions, accessibility, search indexing, and AI summarization. Optional: legacy or stock recordings without a stored script omit this field.'
          example: Stand tall with your feet shoulder-width apart. Lower into a squat, keeping your chest up.
      required:
        - id
        - createdAt
        - assetUri
        - type
        - locale
    VideoAssetListItem:
      type: object
      properties:
        id:
          type: string
        createdAt:
          format: date-time
          type: string
        trainer:
          description: Creator reference for the workspace member who owns this asset in Hyperhuman Teams. The JSON field name remains `trainer` for API compatibility.
          allOf:
            - $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
        kind:
          type: string
          enum:
            - single-exercise
            - multi-exercise
            - class
            - promo
            - educational
          description: Video kind. See the VIDEO TYPE GUIDE on the list operation for product names and audio behavior.
        muscleGroups:
          type: array
          items:
            $ref: '#/components/schemas/MuscleGroup'
        equipment:
          type: array
          items:
            $ref: '#/components/schemas/Equipment'
        preview:
          description: Preview video stream
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        collectionName:
          type: string
        coach:
          type: string
          enum:
            - male
            - female
        tags:
          type: array
          items:
            type: string
        skillLevel:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
        categories:
          type: array
          items:
            type: string
            enum:
              - strength
              - cardio
              - mobility
              - balance
              - endurance
              - flexibility
              - plyometrics
              - recovery
              - running
        executionSide:
          type: string
          enum:
            - both
            - left
            - right
            - alternating
        showcasedReps:
          type: number
        bundle:
          description: Asensei movement bundle for this exercise
          allOf:
            - $ref: '#/components/schemas/ExerciseBundleRefDto'
        playsInLoop:
          type: boolean
          description: When true, preview playback is intended to loop (for example smart clips aligned with reps or duration).
        organization:
          nullable: true
          description: Workspace (organization) this exercise belongs to. `null` when the workspace cannot be resolved.
          allOf:
            - $ref: '#/components/schemas/Organization'
        audioInstructions:
          description: 'Locale-specific instruction audio tracks. Emitted only for `kind: single-exercise` (the smart-clip product type that strips original audio in favor of multilingual instructions). When `?locale=` is supplied, narrowed to matching locales via the standard locale chain (English fallback); when omitted, returns all available locales so catalog UIs can render a "languages available" indicator. Empty array for `single-exercise` rows that have not yet been narrated. Always empty for the other kinds (`multi-exercise`, `educational`, `promo`, `class`) which keep their original audio baked into the video. Currently populated by `GET /v1/orgs/{organizationId}/video-assets`; other endpoints that share this list-item shape do not yet emit this field.'
          type: array
          items:
            $ref: '#/components/schemas/AudioDto'
      required:
        - id
        - createdAt
        - trainer
        - name
        - kind
        - muscleGroups
        - equipment
        - playsInLoop
        - organization
    VideoAssetsListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/VideoAssetListItem'
        explanation:
          type: string
          description: Explanation for how this list was filtered or scoped.
      required:
        - links
        - data
    TimeBasedConfig:
      type: object
      properties:
        kind:
          type: string
          enum:
            - timeBased
        duration:
          type: number
        pace:
          type: string
          enum:
            - slow
            - medium
            - fast
          nullable: true
        weightLevel:
          type: string
          enum:
            - light
            - medium
            - heavy
          nullable: true
        rpe:
          type: number
          description: Rate of Perceived Exertion (0-10). Target intensity level for this exercise.
          minimum: 0
          maximum: 10
        amrap:
          type: boolean
          description: As Many Reps As Possible mode. Only applicable for time-based exercises.
      required:
        - kind
        - duration
    RepsBasedConfig:
      type: object
      properties:
        kind:
          type: string
          enum:
            - repsBased
        reps:
          type: number
        weightLevel:
          type: string
          enum:
            - light
            - medium
            - heavy
          nullable: true
        pace:
          type: string
          enum:
            - slow
            - medium
            - fast
          nullable: true
        rpe:
          type: number
          description: Rate of Perceived Exertion (0-10). Target intensity level for this exercise.
          minimum: 0
          maximum: 10
      required:
        - kind
        - reps
    SingleExerciseConfig:
      type: object
      properties:
        timeBasedConfig:
          description: Time based configuration
          allOf:
            - $ref: '#/components/schemas/TimeBasedConfig'
        repsBasedConfig:
          description: Reps based configuration
          allOf:
            - $ref: '#/components/schemas/RepsBasedConfig'
    GroupListItem:
      type: object
      properties:
        id:
          type: string
        createdAt:
          format: date-time
          type: string
        updatedAt:
          format: date-time
          type: string
        trainer:
          $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
        kind:
          type: string
          enum:
            - circuit
            - sets
        preview:
          description: Preview video stream
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        rounds:
          type: number
        roundBreakDuration:
          type: number
        exerciseBreakDuration:
          type: number
        exerciseConfig:
          $ref: '#/components/schemas/SingleExerciseConfig'
      required:
        - id
        - createdAt
        - updatedAt
        - trainer
        - name
        - kind
        - rounds
        - roundBreakDuration
        - exerciseBreakDuration
        - exerciseConfig
    GroupListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/GroupListItem'
        explanation:
          type: string
          description: Explanation for how this list was filtered or sorted
      required:
        - links
        - data
    Group:
      type: object
      properties:
        id:
          type: string
        createdAt:
          format: date-time
          type: string
        updatedAt:
          format: date-time
          type: string
        trainer:
          $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
        kind:
          type: string
          enum:
            - circuit
            - sets
        preview:
          description: Preview video stream
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        rounds:
          type: number
        roundBreakDuration:
          type: number
        exerciseBreakDuration:
          type: number
        exerciseConfig:
          $ref: '#/components/schemas/SingleExerciseConfig'
        organization:
          $ref: '#/components/schemas/Organization'
      required:
        - id
        - createdAt
        - updatedAt
        - trainer
        - name
        - kind
        - rounds
        - roundBreakDuration
        - exerciseBreakDuration
        - exerciseConfig
    GroupResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/Group'
      required:
        - data
    GroupExerciseInstanceDto:
      type: object
      properties:
        id:
          type: string
        createdAt:
          format: date-time
          type: string
        trainer:
          description: Creator reference for the workspace member who owns this asset in Hyperhuman Teams. The JSON field name remains `trainer` for API compatibility.
          allOf:
            - $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
        kind:
          type: string
          enum:
            - single-exercise
            - multi-exercise
            - class
            - promo
            - educational
          description: Video kind. See the VIDEO TYPE GUIDE on the list operation for product names and audio behavior.
        muscleGroups:
          type: array
          items:
            $ref: '#/components/schemas/MuscleGroup'
        equipment:
          type: array
          items:
            $ref: '#/components/schemas/Equipment'
        preview:
          description: Preview video stream
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        collectionName:
          type: string
        coach:
          type: string
          enum:
            - male
            - female
        tags:
          type: array
          items:
            type: string
        skillLevel:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
        categories:
          type: array
          items:
            type: string
            enum:
              - strength
              - cardio
              - mobility
              - balance
              - endurance
              - flexibility
              - plyometrics
              - recovery
              - running
        executionSide:
          type: string
          enum:
            - both
            - left
            - right
            - alternating
        showcasedReps:
          type: number
        bundle:
          description: Asensei movement bundle for this exercise
          allOf:
            - $ref: '#/components/schemas/ExerciseBundleRefDto'
        playsInLoop:
          type: boolean
          description: When true, preview playback is intended to loop (for example smart clips aligned with reps or duration).
        organization:
          nullable: true
          description: Workspace (organization) this exercise belongs to. `null` when the workspace cannot be resolved.
          allOf:
            - $ref: '#/components/schemas/Organization'
        audioInstructions:
          description: 'Locale-specific instruction audio tracks. Emitted only for `kind: single-exercise` (the smart-clip product type that strips original audio in favor of multilingual instructions). When `?locale=` is supplied, narrowed to matching locales via the standard locale chain (English fallback); when omitted, returns all available locales so catalog UIs can render a "languages available" indicator. Empty array for `single-exercise` rows that have not yet been narrated. Always empty for the other kinds (`multi-exercise`, `educational`, `promo`, `class`) which keep their original audio baked into the video. Currently populated by `GET /v1/orgs/{organizationId}/video-assets`; other endpoints that share this list-item shape do not yet emit this field.'
          type: array
          items:
            $ref: '#/components/schemas/AudioDto'
        duration:
          type: number
          description: Duration of this exercise in seconds.
          example: 30
        reps:
          type: number
          description: Target reps for reps-based exercises. Null for time-based.
          example: 12
        pace:
          type: string
          enum:
            - slow
            - medium
            - fast
          nullable: true
          description: Recommended pace/tempo.
          example: medium
        weightLevel:
          type: string
          enum:
            - light
            - medium
            - heavy
          nullable: true
          description: Recommended weight level for reps-based exercises.
          example: medium
        rpe:
          type: number
          description: Rate of Perceived Exertion (0-10). Target intensity level.
          minimum: 0
          maximum: 10
          example: 8
        amrap:
          type: boolean
          description: As Many Reps As Possible mode. Only applicable for time-based exercises.
          example: false
        weight:
          type: number
          description: Prescribed/target weight (0-1000). Unit in weightUnit.
          minimum: 0
          maximum: 1000
        weightUnit:
          type: string
          enum:
            - metric
            - imperial
          nullable: true
          description: 'Unit for weight: metric (kg) or imperial (lbs).'
      required:
        - id
        - createdAt
        - trainer
        - name
        - kind
        - muscleGroups
        - equipment
        - playsInLoop
        - organization
        - duration
    GroupExercisesListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/GroupExerciseInstanceDto'
      required:
        - links
        - data
    Goal:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the goal.
          example: goal-strength-gain
        name:
          type: string
          description: Display name of the goal. Localized based on locale query parameter.
          example: Strength Gain
        nameTranslations:
          type: object
          additionalProperties:
            type: string
          description: Localized goal names for different locales
          example:
            en-US: Weight Loss
            de-DE: Gewichtsverlust
            fr-FR: Perte de Poids
      required:
        - id
        - name
    PlanListItem:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier (UUID) for the workout plan.
          example: 12ab3efd45c67c1234566cd1
        createdAt:
          format: date-time
          type: string
          description: Timestamp when the plan was created.
          example: '2023-10-26T10:00:00.000Z'
        updatedAt:
          format: date-time
          type: string
          description: Timestamp when the plan was last updated.
          example: '2023-10-27T11:30:00.000Z'
        trainer:
          description: Reference to the trainer associated with the plan. Can be null.
          allOf:
            - $ref: '#/components/schemas/TrainerRef'
        name:
          type: string
          description: Display name of the workout plan. Localized based on locale query parameter.
          example: 4-Week Strength Builder
        description:
          type: string
          description: Detailed description of the plan, including its purpose and target audience. Localized based on locale query parameter.
          example: A structured 4-week program designed to increase overall strength using compound lifts.
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Overall difficulty level of the plan.
          example: intermediate
        visibility:
          type: string
          enum:
            - private
            - public
            - end-user-ai-generated
          description: Visibility level of the plan.
          example: public
        durationInWeeks:
          type: number
          description: 'Program duration in weeks (1-24). Use for filtering: ?durationInWeeks=8. Total workouts = durationInWeeks × workoutsPerWeek'
          example: 8
          minimum: 1
          maximum: 24
        workoutsPerWeek:
          type: number
          description: Weekly workout frequency (1-7). Total workouts = durationInWeeks × workoutsPerWeek
          example: 3
          minimum: 1
          maximum: 7
        adaptationReasoning:
          type: string
          description: AI adaptation reasoning explanation (only present for AI-adapted programs)
          example: Program adapted to reduce intensity based on low sleep scores. Replaced 3 high-intensity workouts with recovery-focused alternatives.
        originalProgramId:
          type: string
          description: Original program ID if this program was adapted from another (only present for AI-adapted programs)
          example: 507f1f77bcf86cd799439016
        preview:
          description: Links to a preview video for the plan (if available).
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
        goals:
          description: List of primary goals this plan is designed for (e.g., Strength, Endurance, Weight Loss).
          type: array
          items:
            $ref: '#/components/schemas/Goal'
      required:
        - id
        - createdAt
        - updatedAt
        - name
        - description
        - difficulty
        - visibility
        - goals
    PlanListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          description: The array of plan list items for the current page.
          type: array
          items:
            $ref: '#/components/schemas/PlanListItem'
        explanation:
          type: string
          description: Explanation for how this list was filtered or sorted
      required:
        - links
        - data
    PlanRecommendationRequestDto:
      type: object
      properties:
        endUserProfileDetails:
          description: Detailed user profile information for personalized recommendations
          allOf:
            - $ref: '#/components/schemas/EndUserProfileDetailsDto'
        goalIds:
          description: Optional goal IDs at the root of the body (mobile clients). Merged with endUserProfileDetails.goalIds for library matching.
          example:
            - 63c92926f920a9005c4e61a0
          type: array
          items:
            type: string
        locale:
          type: string
          description: Preferred BCP-47 locale for recommendation text when the stack supports it.
          example: en-US
    RecommendedPlanDto:
      type: object
      properties:
        id:
          type: string
          description: Plan ID
        name:
          type: string
          description: Plan name
        description:
          type: string
          description: Plan description
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
        thumbnailUrl:
          type: object
          description: URL to plan thumbnail image
          nullable: true
        recommendation:
          type: string
          description: Reasoning for this recommendation
        goals:
          description: Plan goals
          items:
            type: array
          type: array
        preview:
          description: Preview video (playable URL when available). url is empty when only a thumbnail image exists.
          allOf:
            - $ref: '#/components/schemas/VideoLinks'
      required:
        - id
        - name
        - description
        - difficulty
        - thumbnailUrl
        - recommendation
        - goals
    PlanRecommendationResponseDto:
      type: object
      properties:
        plans:
          description: List of recommended plans (max 12)
          type: array
          items:
            $ref: '#/components/schemas/RecommendedPlanDto'
        reasoning:
          type: string
          description: Overall explanation for the recommendation strategy used
      required:
        - plans
        - reasoning
    DurationOptionsDto:
      type: object
      properties:
        minWeeks:
          type: number
          description: Minimum program duration in weeks
          minimum: 1
          maximum: 24
          example: 4
        maxWeeks:
          type: number
          description: Maximum program duration in weeks
          minimum: 1
          maximum: 24
          example: 8
    PlanGenerationRequestDto:
      type: object
      properties:
        goalIds:
          description: Array of goal IDs for the program
          example:
            - 507f1f77bcf86cd799439011
            - 507f1f77bcf86cd799439012
          type: array
          items:
            type: string
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Difficulty level for the program
          example: intermediate
        workoutsPerWeek:
          type: number
          description: Number of workouts per week
          minimum: 1
          maximum: 7
          example: 3
        durationOptions:
          description: Duration preferences for the program
          allOf:
            - $ref: '#/components/schemas/DurationOptionsDto'
        endUserProfileDetails:
          description: Detailed user profile information for personalized program generation
          allOf:
            - $ref: '#/components/schemas/EndUserProfileDetailsDto'
        workoutCollectionSources:
          type: array
          description: Sources of workout collections to use for plan generation. Defaults to both team and template if not specified.
          example:
            - team
            - template
          items:
            type: string
            enum:
              - team
              - template
        userRequirements:
          type: string
          description: High-level context, definitions, and guidelines for program generation. Provides customer-specific grounding for training methodologies, progression schemes, and program structure.
          example: Progressive overload with 3-week cycles. Include deload weeks every 4th week. Focus on unilateral movements for balance.
          maxLength: 2000
    ApiWorkoutDto:
      type: object
      properties:
        id:
          type: string
          description: Workout ID
          example: 507f1f77bcf86cd799439017
        name:
          type: string
          description: Workout name
          example: Upper Body Strength
        duration:
          type: number
          description: Workout duration in seconds
          example: 2700
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Workout difficulty level
          example: intermediate
        description:
          type: string
          description: Workout description
      required:
        - id
        - name
        - duration
        - difficulty
    PlanGenerationResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Generated program ID (if persisted)
          example: 507f1f77bcf86cd799439017
        name:
          type: string
          description: Generated plan name
          example: 8-Week Strength Building Program
        description:
          type: string
          description: Generated plan description
          example: A comprehensive 8-week program designed to build strength and muscle mass.
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Plan difficulty level
          example: intermediate
        goalIds:
          description: Array of goal IDs the plan addresses
          example:
            - 507f1f77bcf86cd799439011
            - 507f1f77bcf86cd799439012
          type: array
          items:
            type: string
        workouts:
          description: Array of workouts in the plan
          type: array
          items:
            $ref: '#/components/schemas/ApiWorkoutDto'
        durationInWeeks:
          type: number
          description: Total number of weeks in the program
          example: 8
        workoutsPerWeek:
          type: number
          description: Number of workouts per week
          example: 3
      required:
        - name
        - description
        - difficulty
        - goalIds
        - workouts
        - durationInWeeks
        - workoutsPerWeek
    PlanAdaptationRequestDto:
      type: object
      properties:
        endUserProfileId:
          type: string
          description: End user profile ID for fetching 60-day wearable data, workout feedback, and completed sessions
          example: 64e3bca9d1b7e600141a9712
        endUserProfileDetails:
          description: User profile information for program adaptation
          allOf:
            - $ref: '#/components/schemas/AdaptationEndUserProfileDetailsDto'
        workoutSources:
          type: array
          description: Workout sources for additions/replacements
          example:
            - template
            - team
          items:
            type: string
            enum:
              - template
              - team
        userGuidance:
          type: string
          description: User free text for guidance/feedback/context/injury/environment/constraints
          example: I have a slight knee injury, avoid high-impact exercises. Reduce program intensity for recovery.
          maxLength: 2000
      required:
        - endUserProfileDetails
        - workoutSources
    ApiAdaptedWorkoutDto:
      type: object
      properties:
        id:
          type: string
          description: Workout ID
          example: 507f1f77bcf86cd799439017
        name:
          type: string
          description: Workout name
          example: Upper Body Strength
        duration:
          type: number
          description: Workout duration in seconds
          example: 2700
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Workout difficulty
        description:
          type: string
          description: Workout description
        position:
          type: number
          description: Position in program (0-based)
        action:
          type: string
          description: Action taken
          enum:
            - kept
            - replaced
            - added
      required:
        - id
        - name
    PlanAdaptationResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Adapted program ID
          example: 507f1f77bcf86cd799439017
        name:
          type: string
          description: Adapted program name
          example: 'Adapted: 8-Week Strength Program'
        description:
          type: string
          description: Program description
        workouts:
          description: Workouts in adapted program
          type: array
          items:
            $ref: '#/components/schemas/ApiAdaptedWorkoutDto'
        totalWorkouts:
          type: number
          description: Total number of workouts
        durationInWeeks:
          type: number
          description: Program duration in weeks
        workoutsPerWeek:
          type: number
          description: Workouts per week
        difficulty:
          type: string
          enum:
            - beginner
            - intermediate
            - advanced
          description: Program difficulty
        adaptationReasoning:
          type: string
          description: Explanation of adaptations made
        wasDuplicated:
          type: boolean
          description: True if program was duplicated from team program
        originalProgramId:
          type: string
          description: Original program ID if duplicated
      required:
        - id
        - name
        - workouts
        - totalWorkouts
        - durationInWeeks
        - workoutsPerWeek
        - adaptationReasoning
    OrganizationMetadataResponse:
      type: object
      properties:
        id:
          type: string
          description: The unique identifier of the organization
          example: 12ab3efd45c67c1234566cd1
        name:
          type: string
          description: The name of the organization
          example: Hyperhuman LLC
        handle:
          type: object
          description: The organization handle (typically used in URLs)
          example: hyperhuman
        logoUrl:
          type: object
          description: URL to the organization logo
          example: https://assets.example.com/logos/hyperhuman-logo.png
        watermarkUrl:
          type: object
          description: URL to the brand watermark used in workout video exports and the embedded player. Square PNG with transparent background recommended.
          example: https://assets.example.com/logos/hyperhuman-watermark.png
        description:
          type: object
          description: The description of the organization
          example: A company dedicated to fitness and wellness solutions
        website:
          type: object
          description: The website URL of the organization
          example: https://hyperhuman.cc
        brandMainColor:
          type: object
          description: The primary brand color (hex format)
          example: '#11CC88'
        brandSecondaryColor:
          type: object
          description: The secondary brand color (hex format)
          example: '#F3F8F8'
        brandTextColor:
          type: object
          description: The text color that goes with the brand colors (hex format)
          example: '#FFFFFF'
        clientsJoinSetting:
          type: string
          description: Setting that controls how clients can join the organization
          enum:
            - OPEN
            - INVITE_ONLY
            - SUBSCRIPTION_REQUIRED
          example: OPEN
          default: OPEN
        hasAssenseiModuleActive:
          type: boolean
          description: Whether the organization has the Asensei Assessment module active (AI form analysis)
          example: false
        hasWearableModuleActive:
          type: boolean
          description: Whether the organization has the ROOK Wearables module active (health data sync)
          example: false
        hasWhiteLabelAppActive:
          type: boolean
          description: Whether the organization has a White-Label App active (custom branded consumer app)
          example: false
      required:
        - id
        - name
        - clientsJoinSetting
        - hasAssenseiModuleActive
        - hasWearableModuleActive
        - hasWhiteLabelAppActive
    TeamClientsJoinSetting:
      type: string
      enum:
        - OPEN
        - INVITE_ONLY
        - SUBSCRIPTION_REQUIRED
    FreeJoinOptionDto:
      type: object
      properties:
        id:
          type: string
          description: Product unique identifier
          example: 507f1f77bcf86cd799439011
        name:
          type: string
          description: Product name/title
          example: Club Free Plan
        description:
          type: string
          description: Product description
          example: Free access with basic features
        hasAutoJoin:
          type: boolean
          description: Whether this product includes auto-join capability
          example: true
        stripeProductId:
          type: string
          description: Stripe product ID for payment processing
          example: prod_SMcyPrDHt0ROlQ
      required:
        - id
        - name
        - description
        - hasAutoJoin
        - stripeProductId
    OrganizationJoinOptionsResponse:
      type: object
      properties:
        clientsJoinSetting:
          description: High-level team join setting that controls client access
          example: OPEN
          $ref: '#/components/schemas/TeamClientsJoinSetting'
        canJoinDirectly:
          type: boolean
          description: Whether users can join directly without any requirements (OPEN setting)
          example: true
        requiresSubscription:
          type: boolean
          description: Whether the team requires a subscription to join (SUBSCRIPTION_REQUIRED setting)
          example: false
        inviteOnlyMode:
          type: boolean
          description: Whether the team only allows invited users to join (INVITE_ONLY setting)
          example: false
        hasFreePlanWithAutoJoin:
          type: boolean
          description: Whether the team offers any free plans with auto-join capability
          example: true
        freeJoinOptions:
          description: Available free products that include auto-join capability
          type: array
          items:
            $ref: '#/components/schemas/FreeJoinOptionDto'
        totalProductsAvailable:
          type: number
          description: Total number of subscription products available (including paid)
          example: 3
      required:
        - clientsJoinSetting
        - canJoinDirectly
        - requiresSubscription
        - inviteOnlyMode
        - hasFreePlanWithAutoJoin
        - freeJoinOptions
    PlanProgressResponseDto:
      type: object
      properties:
        data:
          type: object
          nullable: true
          description: A map where keys are position indices (as strings) and values contain completion status, latest completion date, and workout details. Returns `null` when the user has no active plan.
          additionalProperties:
            type: object
            properties:
              completed:
                type: boolean
              latestCompletionDate:
                type: string
                format: date-time
              workoutName:
                type: string
              difficulty:
                type: string
              duration:
                type: number
              categories:
                type: array
                items:
                  type: string
              workoutId:
                type: string
              positionInPlan:
                type: number
          example:
            '0':
              completed: true
              latestCompletionDate: '2023-07-22T15:30:45.123Z'
              workoutName: Full Body HIIT
              difficulty: intermediate
              duration: 1800000
              categories:
                - Strength
                - HIIT
                - Full Body
              workoutId: 60f1b3b3b3b3b3b3b3b3b3b3
              positionInPlan: 0
            '1':
              completed: false
              latestCompletionDate: null
              workoutName: Lower Body Strength
              difficulty: advanced
              duration: 2400000
              categories:
                - Strength
                - Lower Body
              workoutId: 60f1b3b3b3b3b3b3b3b3b3b4
              positionInPlan: 1
            '2':
              completed: false
              latestCompletionDate: null
              workoutName: Full Body HIIT
              difficulty: intermediate
              duration: 1800000
              categories:
                - Strength
                - HIIT
                - Full Body
              workoutId: 60f1b3b3b3b3b3b3b3b3b3b3
              positionInPlan: 2
      required:
        - data
    ActivePlanResponseDto:
      type: object
      properties:
        data:
          type: object
          description: The active workout collection access object or null if no active plan
          nullable: true
      required:
        - data
    StartPlanBody:
      type: object
      properties:
        planId:
          type: string
          description: The plan ID to start as the active plan.
          example: 60f1b3b3b3b3b3b3b3b3b3b3
      required:
        - planId
    PlanResponseDto:
      type: object
      properties:
        data:
          type: object
          description: The workout collection access object
      required:
        - data
    EndUserProfileDto:
      type: object
      properties:
        email:
          type: string
          description: User email address
        firstName:
          type: string
          description: User first name
        lastName:
          type: string
          description: User last name
        externalUUID:
          type: string
          description: External unique identifier provided by the API client
        joinedDate:
          format: date-time
          type: string
          description: When the user joined the team
        status:
          type: string
          description: User membership status
          enum:
            - active
            - suspended
        endUserId:
          type: string
          description: Internal user ID. Present only when the API key is for this organization and the end user has an active (non-suspended) team membership. Use in enduser-scoped endpoints (e.g. plans, insights).
          example: 507f1f77bcf86cd799439011
      required:
        - email
        - joinedDate
        - status
    EndUserProfileListResponse:
      type: object
      properties:
        links:
          description: Pagination envelope. Use `links.next` to fetch the next page; `links.total` is the count across all pages and is omitted on endpoints where it is too expensive to compute.
          allOf:
            - $ref: '#/components/schemas/PageLinks'
        data:
          type: array
          items:
            $ref: '#/components/schemas/EndUserProfileDto'
        total:
          type: number
          deprecated: true
          description: Deprecated. Use `links.total` instead. Kept for one minor version for backwards compatibility.
      required:
        - links
        - data
        - total
    EndUserInviteItem:
      type: object
      properties:
        email:
          type: string
          description: Email address of the user to invite
        externalUUID:
          type: string
          description: External unique identifier for this user
        firstName:
          type: string
          description: First name of the user
        lastName:
          type: string
          description: Last name of the user
      required:
        - email
    InviteEndUsersDto:
      type: object
      properties:
        users:
          description: List of users to invite
          type: array
          items:
            $ref: '#/components/schemas/EndUserInviteItem'
      required:
        - users
    UserIdentifierDto:
      type: object
      properties:
        email:
          type: string
          description: Email address of the user
        externalUUID:
          type: string
          description: External UUID of the user
    InsightPillarDto:
      type: object
      properties:
        type:
          type: string
          description: The type of insight pillar.
          enum:
            - health_pulse
            - training
            - recovery
            - movement
            - nutrition
            - body
          example: health_pulse
        status:
          type: string
          description: Status indicator for this pillar.
          enum:
            - green
            - yellow
            - red
          example: green
        headline:
          type: string
          description: Headline summarizing the pillar insight (1-2 lines). Does not include pillar type prefix.
          example: '82 (+5 vs 7-day). Driver: Sleep.'
        action:
          type: string
          description: Recommended action for this pillar.
          example: Maintain your sleep routine
        confidence:
          type: number
          description: Confidence score for this pillar (0-1).
          example: 0.85
        score:
          type: number
          description: Score value if applicable (0-100).
          example: 82
        delta:
          type: number
          description: Change from baseline/average.
          example: 5
        deltaDirection:
          type: string
          description: Direction of change.
          enum:
            - up
            - down
            - stable
          example: up
        driver:
          type: string
          description: Primary driver for health pulse pillar.
          enum:
            - sleep
            - exercise
            - body
            - nutrition
            - adherence
          example: sleep
        weeklyCompletions:
          type: number
          description: Number of workouts completed this week.
          example: 4
        streak:
          type: number
          description: Current workout streak in days.
          example: 5
        formScore:
          type: number
          description: Average form score from AI assessments.
          example: 78
        formTrend:
          type: string
          description: Form score trend.
          enum:
            - improving
            - declining
            - stable
            - insufficient-data
          example: improving
        recentCoachingFocus:
          type: string
          description: Most common coaching feedback.
          example: Keep your knees aligned with your toes
        isFallback:
          type: boolean
          description: Indicates if this pillar used fallback data.
          example: false
        nutritionScore:
          type: number
          description: Nutrition score (0-100) for nutrition pillar.
          example: 72
        caloriesConsumedKcal:
          type: number
          description: Calories consumed (kcal) for nutrition pillar.
          example: 1850
        personalBests:
          type: array
          description: Personal best metrics for this pillar (90-day window).
          items:
            type: object
            properties:
              metric:
                type: string
              value:
                type: number
              label:
                type: string
        streaks:
          type: array
          description: Streaks for this pillar (90-day window).
          items:
            type: object
            properties:
              type:
                type: string
              value:
                type: number
              label:
                type: string
        milestones:
          type: array
          description: Milestones for this pillar (90-day window).
          items:
            type: object
            properties:
              type:
                type: string
              value:
                type: number
              label:
                type: string
      required:
        - type
        - status
        - headline
        - action
        - confidence
    UserDigestResponse:
      type: object
      properties:
        userId:
          type: string
          description: User ID the digest is for.
          example: 63415bf67a9c7000126616c1
        organizationId:
          type: string
          description: Organization ID.
          example: 63415bf67a9c7000126616c1
        date:
          format: date-time
          type: string
          description: Date the digest is for.
          example: '2026-01-10T00:00:00.000Z'
        pillars:
          description: Array of insight pillars (3-5 items).
          type: array
          items:
            $ref: '#/components/schemas/InsightPillarDto'
        todaysFocus:
          type: string
          description: The single most important action for today.
          example: 'Complete: Full Body Strength Workout'
        dataCompleteness:
          type: number
          description: Data completeness score (0-1). Higher means more data sources available.
          example: 0.75
        generatedAt:
          format: date-time
          type: string
          description: Timestamp when the digest was generated.
          example: '2026-01-10T08:30:00.000Z'
      required:
        - userId
        - organizationId
        - date
        - pillars
        - todaysFocus
        - dataCompleteness
        - generatedAt
    PillarDetailResponse:
      type: object
      properties:
        type:
          type: string
          description: The type of insight pillar.
          enum:
            - health_pulse
            - training
            - recovery
            - movement
            - nutrition
            - body
          example: health_pulse
        status:
          type: string
          description: Status indicator for this pillar.
          enum:
            - green
            - yellow
            - red
          example: green
        headline:
          type: string
          description: Headline summarizing the pillar insight (1-2 lines). Does not include pillar type prefix.
          example: '82 (+5 vs 7-day). Driver: Sleep.'
        action:
          type: string
          description: Recommended action for this pillar.
          example: Maintain your sleep routine
        confidence:
          type: number
          description: Confidence score for this pillar (0-1).
          example: 0.85
        score:
          type: number
          description: Score value if applicable (0-100).
          example: 82
        delta:
          type: number
          description: Change from baseline/average.
          example: 5
        deltaDirection:
          type: string
          description: Direction of change.
          enum:
            - up
            - down
            - stable
          example: up
        driver:
          type: string
          description: Primary driver for health pulse pillar.
          enum:
            - sleep
            - exercise
            - body
            - nutrition
            - adherence
          example: sleep
        weeklyCompletions:
          type: number
          description: Number of workouts completed this week.
          example: 4
        streak:
          type: number
          description: Current workout streak in days.
          example: 5
        formScore:
          type: number
          description: Average form score from AI assessments.
          example: 78
        formTrend:
          type: string
          description: Form score trend.
          enum:
            - improving
            - declining
            - stable
            - insufficient-data
          example: improving
        recentCoachingFocus:
          type: string
          description: Most common coaching feedback.
          example: Keep your knees aligned with your toes
        isFallback:
          type: boolean
          description: Indicates if this pillar used fallback data.
          example: false
        nutritionScore:
          type: number
          description: Nutrition score (0-100) for nutrition pillar.
          example: 72
        caloriesConsumedKcal:
          type: number
          description: Calories consumed (kcal) for nutrition pillar.
          example: 1850
        personalBests:
          type: array
          description: Personal best metrics for this pillar (90-day window).
          items:
            type: object
            properties:
              metric:
                type: string
              value:
                type: number
              label:
                type: string
        streaks:
          type: array
          description: Streaks for this pillar (90-day window).
          items:
            type: object
            properties:
              type:
                type: string
              value:
                type: number
              label:
                type: string
        milestones:
          type: array
          description: Milestones for this pillar (90-day window).
          items:
            type: object
            properties:
              type:
                type: string
              value:
                type: number
              label:
                type: string
        lastWorkout:
          type: object
          description: Last workout information for training pillar.
        nextSession:
          type: object
          description: Next scheduled session for training pillar.
        bestLever:
          type: string
          description: Best training lever for training pillar.
          enum:
            - strength
            - cardio
            - mobility
        sleepScore:
          type: number
          description: Sleep score for recovery pillar.
          example: 75
        mainIssue:
          type: string
          description: Main issue identified for recovery pillar.
          example: Sleep efficiency
        yesterdayIntensity:
          type: string
          description: Yesterday's workout intensity for recovery pillar.
          enum:
            - low
            - moderate
            - high
        activityLevel:
          type: string
          description: Activity level for movement pillar.
          enum:
            - low
            - moderate
            - high
        suggestedMinutes:
          type: number
          description: Suggested movement minutes for movement pillar.
          example: 20
        cardioTrend:
          type: string
          description: Cardio trend for movement pillar.
          enum:
            - improving
            - declining
            - stable
            - insufficient-data
        bodyScore:
          type: number
          description: Body score for body pillar.
          example: 72
        weeklyTrend:
          type: string
          description: Weekly trend for body pillar.
          enum:
            - improving
            - declining
            - stable
            - insufficient-data
        streakDays:
          type: number
          description: Streak days for body/momentum pillar.
          example: 7
        biggestLever:
          type: string
          description: Biggest lever for improvement.
          enum:
            - sleep
            - nutrition
            - movement
        proteinG:
          type: number
          description: Protein (g) for nutrition pillar.
          example: 120
        carbsG:
          type: number
          description: Carbohydrates (g) for nutrition pillar.
          example: 200
        fatG:
          type: number
          description: Fat (g) for nutrition pillar.
          example: 65
        mealsLoggedToday:
          type: number
          description: Number of meals/entries logged today for nutrition pillar.
          example: 6
        nutritionMeals:
          type: array
          description: Per-entry nutrition breakdown for the day (up to 20 entries).
          items:
            type: object
            properties:
              at:
                type: string
                format: date-time
              caloriesKcal:
                type: number
              proteinG:
                type: number
              carbsG:
                type: number
              fatG:
                type: number
        nutritionWin:
          type: string
          description: Positive nutrition behavior identified for nutrition pillar.
          example: Good protein intake (195g)
        nutritionWatch:
          type: string
          description: Area to improve for nutrition pillar.
          example: High calorie day – confirm aligned with goal
        readinessBand:
          type: string
          description: Readiness band indicating training capacity for today.
          enum:
            - push
            - maintain
            - recover
          example: maintain
        readinessMessage:
          type: string
          description: Short message explaining the readiness recommendation.
          example: Sleep down vs baseline - keep intensity moderate.
        recommendedIntensity:
          type: string
          description: Recommended workout intensity based on readiness.
          enum:
            - light
            - moderate
            - high
          example: moderate
        hrvBand:
          type: string
          description: HRV status relative to personal baseline.
          enum:
            - low
            - normal
            - high
          example: normal
        riskLevel:
          type: string
          description: Risk level for burnout/overreaching.
          enum:
            - low
            - moderate
            - high
          example: moderate
        riskTriggers:
          description: Factors that triggered the risk flag (max 3).
          example:
            - Sleep trend declining
            - RPE consistently high
          type: array
          items:
            type: string
        formCue:
          type: string
          description: Primary form cue to focus on today.
          example: Keep knees tracking over toes
        formSuggestion:
          type: string
          description: Suggested adjustment if form is declining.
          example: Slow tempo + lighter load today
        repAccuracy:
          type: number
          description: Average rep accuracy from AI assessments.
          example: 82
        pacingStatus:
          type: string
          description: Program pacing status for the current week.
          enum:
            - on_track
            - behind
            - ahead
          example: on_track
        pacingMessage:
          type: string
          description: Short message about program pacing.
          example: 3/4 workouts this week. On pace.
        workoutsPlannedThisWeek:
          type: number
          description: Planned workouts per week based on user profile.
          example: 4
        workoutsCompletedThisWeek:
          type: number
          description: Workouts completed this week.
          example: 3
        currentWeek:
          type: number
          description: Current week number in the program (1-based).
          example: 2
        totalWeeks:
          type: number
          description: Total weeks in the program.
          example: 8
        why:
          description: Reasons explaining the recommendation (max 3).
          example:
            - HRV below baseline
            - Sleep score declining
            - High intensity yesterday
          type: array
          items:
            type: string
        alternativeActions:
          description: Safe alternative actions (max 2).
          example:
            - Do planned workout at moderate intensity
            - Swap to Mobility + Zone 2
          type: array
          items:
            type: string
      required:
        - type
        - status
        - headline
        - action
        - confidence
    CurrentApiStatsDto:
      type: object
      properties:
        currentHour:
          type: string
          description: Current hour timestamp (ISO 8601 format)
          example: '2023-11-06T14:00:00Z'
        currentHourRequests:
          type: number
          description: Number of requests made in the current hour
          example: 45
        totalDayRequests:
          type: number
          description: Total number of requests made today
          example: 234
        currentDate:
          type: string
          description: Current date (YYYY-MM-DD format)
          example: '2023-11-06'
      required:
        - currentHour
        - currentHourRequests
        - totalDayRequests
        - currentDate
    RateLimitsDto:
      type: object
      properties:
        hourly:
          type: object
          description: Hourly rate limit from subscription entitlement
          example: 1000
          nullable: true
        daily:
          type: object
          description: Daily rate limit from subscription entitlement
          example: 15000
          nullable: true
    OrganizationStatsResponse:
      type: object
      properties:
        organizationId:
          type: string
          description: The unique identifier of the organization
          example: 63415bf67a9c7000126616c1
        organizationName:
          type: string
          description: The name of the organization
          example: My Fitness Company
        currentStats:
          description: Current API usage statistics
          allOf:
            - $ref: '#/components/schemas/CurrentApiStatsDto'
        rateLimits:
          description: Rate limits from subscription entitlement
          allOf:
            - $ref: '#/components/schemas/RateLimitsDto'
        timestamp:
          type: string
          description: Response timestamp (ISO 8601 format)
          example: '2023-11-06T14:30:00Z'
      required:
        - organizationId
        - organizationName
        - currentStats
        - rateLimits
        - timestamp
    StartConversationBody:
      type: object
      properties:
        organizationId:
          type: string
          description: Organization ID - use "default" to use the user's default organization
          example: default
        initialMessage:
          type: string
          description: Initial message to start the conversation
          example: What exercises should I do for chest?
          minLength: 1
          maxLength: 2000
        userEmail:
          type: string
          description: User email address to identify the end user
          example: user@example.com
        userExternalUUID:
          type: string
          description: External unique identifier for the end user
          example: user-12345
      required:
        - organizationId
        - initialMessage
    ChatConversationDto:
      type: object
      properties:
        id:
          type: string
          description: Conversation ID
        title:
          type: string
          description: Conversation title
        messageCount:
          type: number
          description: Number of messages in conversation
        lastMessageAt:
          format: date-time
          type: string
          description: Last message timestamp
        createdAt:
          format: date-time
          type: string
          description: Conversation creation timestamp
      required:
        - id
        - messageCount
        - createdAt
    ChatMessageDto:
      type: object
      properties:
        id:
          type: string
          description: Message ID
        role:
          type: string
          description: Message role
          enum:
            - user
            - assistant
        content:
          type: string
          description: Message content
        createdAt:
          format: date-time
          type: string
          description: Message creation timestamp
        metadata:
          type: object
          description: Message metadata (reasoning, topics, nutritionLogged, contentPreview, pendingAction, confirmedResult)
        status:
          type: string
          description: Message delivery status
          enum:
            - pending
            - delivered
            - failed
      required:
        - id
        - role
        - content
        - createdAt
        - status
    ChatConversationResponse:
      type: object
      properties:
        conversation:
          $ref: '#/components/schemas/ChatConversationDto'
        response:
          $ref: '#/components/schemas/ChatMessageDto'
      required:
        - conversation
        - response
    PaginationDto:
      type: object
      properties:
        page:
          type: number
          description: Current page number
        limit:
          type: number
          description: Items per page
        total:
          type: number
          description: Total number of items
        totalPages:
          type: number
          description: Total number of pages
      required:
        - page
        - limit
        - total
        - totalPages
    ChatConversationsResponse:
      type: object
      properties:
        conversations:
          type: array
          items:
            $ref: '#/components/schemas/ChatConversationDto'
        pagination:
          $ref: '#/components/schemas/PaginationDto'
      required:
        - conversations
        - pagination
    ChatMessagesResponse:
      type: object
      properties:
        messages:
          type: array
          items:
            $ref: '#/components/schemas/ChatMessageDto'
        pagination:
          $ref: '#/components/schemas/PaginationDto'
      required:
        - messages
        - pagination
    SendMessageBody:
      type: object
      properties:
        organizationId:
          type: string
          description: Organization ID - use "default" to use the user's default organization
          example: default
        content:
          type: string
          description: Message content
          example: What exercises should I do for chest?
          minLength: 1
          maxLength: 2000
        userEmail:
          type: string
          description: User email address to identify the end user
          example: user@example.com
        userExternalUUID:
          type: string
          description: External unique identifier for the end user
          example: user-12345
      required:
        - organizationId
        - content
    SendMessageResponse:
      type: object
      properties:
        userMessage:
          description: The user message that was sent
          allOf:
            - $ref: '#/components/schemas/ChatMessageDto'
        assistantMessage:
          description: The AI assistant response
          allOf:
            - $ref: '#/components/schemas/ChatMessageDto'
        conversation:
          description: Updated conversation information
          allOf:
            - $ref: '#/components/schemas/ChatConversationDto'
      required:
        - userMessage
        - assistantMessage
        - conversation
    ConfirmActionBody:
      type: object
      properties:
        pendingActionId:
          type: string
          description: Pending action ID from assistantMessage.metadata.pendingAction.id
          example: 507f1f77bcf86cd799439011
        organizationId:
          type: string
          description: Organization ID - use "default" to use the user's default organization
          example: default
        userEmail:
          type: string
          description: User email address to identify the end user
          example: user@example.com
        userExternalUUID:
          type: string
          description: External unique identifier for the end user
          example: user-12345
      required:
        - pendingActionId
        - organizationId
    NutritionOverviewLoggedDto:
      type: object
      properties:
        caloriesKcal:
          type: number
        proteinG:
          type: number
        carbsG:
          type: number
        fatG:
          type: number
      required:
        - caloriesKcal
        - proteinG
        - carbsG
        - fatG
    NutritionOverviewDayTotalsDto:
      type: object
      properties:
        caloriesConsumedKcal:
          type: number
        proteinG:
          type: number
        carbsG:
          type: number
        fatG:
          type: number
      required:
        - caloriesConsumedKcal
        - proteinG
        - carbsG
        - fatG
    NutritionOverviewDto:
      type: object
      properties:
        logged:
          $ref: '#/components/schemas/NutritionOverviewLoggedDto'
        dayTotals:
          $ref: '#/components/schemas/NutritionOverviewDayTotalsDto'
        nutritionScore:
          type: object
          nullable: true
      required:
        - logged
        - dayTotals
        - nutritionScore
    ConfirmActionResponseDto:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
        error:
          type: string
        nutritionOverview:
          description: Present when action was log_nutrition and success is true
          allOf:
            - $ref: '#/components/schemas/NutritionOverviewDto'
        instructionForReply:
          type: string
          description: Instruction for displaying the nutrition reply (log_nutrition only)
        adaptedWorkout:
          description: On-the-fly adapted workout (adapt_workout). Render and store locally.
          allOf:
            - $ref: '#/components/schemas/WorkoutAdaptationResponseDto'
        generatedWorkout:
          description: On-the-fly generated workout (generate_workout). Render and store locally.
          allOf:
            - $ref: '#/components/schemas/WorkoutGenerationResponseDto'
        adaptedProgram:
          description: On-the-fly adapted program (adapt_program). Render and store locally.
          allOf:
            - $ref: '#/components/schemas/PlanAdaptationResponseDto'
        generatedProgram:
          description: On-the-fly generated program (generate_program). Same shape as POST /v1/orgs/{orgId}/plans/generate. Render and store locally.
          allOf:
            - $ref: '#/components/schemas/PlanGenerationResponseDto'
      required:
        - success
