{
  "openapi": "3.1.0",
  "info": {
    "title": "Vocametrix API",
    "version": "1.0.0",
    "description": "Voice analysis, speech therapy, and acoustic measurement API for speech-language pathologists, voice researchers, and developers building healthcare and education applications. Full reference: https://www.vocametrix.com/api-docs",
    "contact": {
      "url": "https://www.vocametrix.com"
    },
    "license": {
      "name": "Commercial",
      "url": "https://www.vocametrix.com/pricing"
    }
  },
  "externalDocs": {
    "description": "Full API reference",
    "url": "https://www.vocametrix.com/api-docs"
  },
  "servers": [
    {
      "url": "https://platform.vocametrix.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Core Speech Analysis",
      "description": "Pronunciation assessment (30+ locales, phoneme-level), async speech-to-text with SSE progress, and neural text-to-speech with per-character timing."
    },
    {
      "name": "Voice Quality Metrics",
      "description": "Clinically validated voice quality indices: AVQI (Maryn/Barsties), DSI, Cepstral Peak Prominence (CPP), and multi-band HNR with age/gender norms."
    },
    {
      "name": "Advanced Voice Analysis",
      "description": "Spectral measures, formants F1-F4, S/Z ratio, GNE, H1*-H2*, voice range profile, jitter/shimmer (Teixeira & Gonçalves 2014), ABI, voice dynamics, and prosody similarity."
    },
    {
      "name": "Audio Measures",
      "description": "Sound level (dB SPL) over a time window and openSMILE eGeMAPSv02 88-feature acoustic extraction."
    },
    {
      "name": "Phoneme & Classification",
      "description": "Live phoneme detection (French/Estonian), async stuttering classification, and Estonian vowel classification."
    },
    {
      "name": "Therapy Planning",
      "description": "Multi-step async LangGraph workflow for generating, reviewing, and approving clinical therapy plans with human-in-the-loop approval."
    },
    {
      "name": "AI Agents",
      "description": "LLM-backed agents for speech exercises, vocabulary tutoring, pronunciation coaching, syntax checking, and clinical voice metric interpretation."
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key for all endpoints except /api/transcription-progress/:transcriptionId"
      },
      "apiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "apiKey",
        "description": "API key as query string — required ONLY on GET /api/transcription-progress/:transcriptionId because the browser EventSource API cannot send custom headers"
      }
    }
  },
  "paths": {
    "/api/get-blob-url": {
      "post": {
        "operationId": "postGetBlobUrl",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Get a secure URL for uploading audio files to Azure Blob Storage",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uploadURL": {
                      "type": "string",
                      "description": "Secure URL for uploading the audio file (1 hour validity)"
                    },
                    "blobURL": {
                      "type": "string",
                      "description": "Secure URL for accessing the uploaded file (1 hour validity)"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/pronunciation-assessment": {
      "post": {
        "operationId": "postPronunciationAssessment",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Perform pronunciation assessment on uploaded audio",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blobURL": {
                    "type": "string",
                    "description": "The secure URL received from get-blob-url endpoint"
                  },
                  "referenceText": {
                    "type": "string",
                    "description": "The text to compare against the audio"
                  },
                  "locale": {
                    "type": "string",
                    "description": "The language locale (e.g., en-US, fr-FR)"
                  }
                },
                "required": [
                  "blobURL",
                  "referenceText",
                  "locale"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "accuracyScore": {
                      "type": "number",
                      "description": "Phoneme-level pronunciation accuracy score (0-100)"
                    },
                    "fluencyScore": {
                      "type": "number",
                      "description": "Natural speech flow and timing score (0-100)"
                    },
                    "completenessScore": {
                      "type": "number",
                      "description": "Coverage of reference text score (0-100)"
                    },
                    "prosodyScore": {
                      "type": "number",
                      "description": "Speech qualities assessment score (0-100)"
                    },
                    "pronScore": {
                      "type": "number",
                      "description": "Overall weighted pronunciation score"
                    },
                    "error": {
                      "type": "string",
                      "description": "Error details with specific rejection reasons if applicable"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/pronunciation-assessment-with-pitch": {
      "post": {
        "operationId": "postPronunciationAssessmentWithPitch",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Pronunciation assessment enriched with per-word pitch contours. Same audio upload + Azure pronunciation evaluation as…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blobURL": {
                    "type": "string",
                    "description": "The secure URL received from /api/get-blob-url"
                  },
                  "referenceText": {
                    "type": "string",
                    "description": "The text to compare against the audio"
                  },
                  "locale": {
                    "type": "string",
                    "description": "The language locale (e.g., en-US, fr-FR)"
                  }
                },
                "required": [
                  "blobURL",
                  "referenceText",
                  "locale"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "RecognitionStatus": {
                      "type": "string",
                      "description": "Azure recognition status (e.g., \"Success\")"
                    },
                    "Offset": {
                      "type": "string",
                      "description": "Recognition start offset in 100-nanosecond units"
                    },
                    "Duration": {
                      "type": "string",
                      "description": "Recognition duration in 100-nanosecond units"
                    },
                    "DisplayText": {
                      "type": "string",
                      "description": "The recognized text with proper formatting"
                    },
                    "NBest": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Array of N-best recognition hypotheses. Each NBest[i] contains the standard Azure pronunciation fields (Confidence, Lexical, ITN, MaskedITN, Display, PronunciationAssessment, Words[]) — and each NBest[i].Words[j] is augmented with an additional `Pitch` array containing F0 samples (Hz) measured over the word's timespan via parselmouth. Words[j] also carry the standard Azure fields: Word, Offset, Duration, PronunciationAssessment {AccuracyScore, ErrorType}, Phonemes[], Syllables[]."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/offline-speech-to-text": {
      "post": {
        "operationId": "postOfflineSpeechToText",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Submit an uploaded audio file for asynchronous transcription. Returns immediately with a transcription job ID — the a…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blobURL": {
                    "type": "string",
                    "description": "The secure URL received from get-blob-url endpoint"
                  },
                  "locale": {
                    "type": "string",
                    "description": "The language locale (e.g., en-US, fr-FR)"
                  }
                },
                "required": [
                  "blobURL",
                  "locale"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean indicating the job was accepted"
                    },
                    "transcriptionId": {
                      "type": "string",
                      "description": "Job identifier — pass this to /api/transcription-progress/:transcriptionId to subscribe to progress and final result"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message confirming the job was queued"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/transcription-progress/{transcriptionId}": {
      "get": {
        "operationId": "getTranscriptionProgressByTranscriptionId",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Server-Sent Events (SSE) stream delivering transcription progress events and the final transcript. The terminal event…",
        "security": [
          {
            "apiKeyQuery": []
          }
        ],
        "parameters": [
          {
            "name": "transcriptionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — job identifier returned by /api/offline-speech-to-text.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "apiKey",
            "in": "query",
            "required": true,
            "description": "REQUIRED query string parameter (e.g. ?apiKey=YOUR_KEY). The X-API-Key header is ignored on this endpoint due to EventSource limitations.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "Newline-delimited JSON events (data: <json>\\n\\n). Each event has a status field; terminal events have status \"Succeeded\" or \"failed\"."
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/text-to-speech": {
      "post": {
        "operationId": "postTextToSpeech",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Convert text to high-quality speech using neural voice synthesis",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The text to convert to speech (max 1000 characters)"
                  },
                  "voice": {
                    "type": "string",
                    "description": "Voice name (optional, default: en-US-AriaNeural)"
                  },
                  "style": {
                    "type": "string",
                    "description": "Speaking style (optional, default: friendly)"
                  },
                  "rate": {
                    "type": "string",
                    "description": "Speaking rate (optional, default: 1.0)"
                  },
                  "language": {
                    "type": "string",
                    "description": "Language locale (optional, default: en-US)"
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean indicating if synthesis was successful"
                    },
                    "audio": {
                      "type": "string",
                      "format": "byte",
                      "description": "Base64 encoded audio data"
                    },
                    "format": {
                      "type": "string",
                      "description": "Audio format (wav)"
                    },
                    "voice": {
                      "type": "string",
                      "description": "Voice used for synthesis"
                    },
                    "style": {
                      "type": "string",
                      "description": "Speaking style applied"
                    },
                    "textLength": {
                      "type": "string",
                      "description": "Length of input text processed"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/text-to-speech/generate-with-timing": {
      "post": {
        "operationId": "postTextToSpeechGenerateWithTiming",
        "tags": [
          "Core Speech Analysis"
        ],
        "summary": "Synthesize speech via ElevenLabs (model: eleven_multilingual_v2) and return per-character timing alongside the audio.…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Text to synthesize (1–2500 characters). REQUIRED."
                  },
                  "isSSML": {
                    "type": "boolean",
                    "description": "Boolean (optional, default false). Currently accepted but not applied to the request body — flag is reserved for future SSML support."
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean — true on a successful synthesis"
                    },
                    "audio_base64": {
                      "type": "string",
                      "format": "byte",
                      "description": "Base64-encoded MP3 audio (ElevenLabs default format)"
                    },
                    "alignment": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object with arrays of equal length: `{ characters: string[], character_start_times_seconds: number[], character_end_times_seconds: number[] }`. Each i-th entry gives the start/end time in seconds of the i-th character of the synthesized audio."
                    },
                    "normalized_alignment": {
                      "type": "string",
                      "description": "Same shape as `alignment`, but computed against the post-text-normalization sequence (numbers expanded, abbreviations expanded, etc.) — use this when your highlighter must follow what was actually pronounced, not the literal input text."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-avqi": {
      "get": {
        "operationId": "getCalculateAvqi",
        "tags": [
          "Voice Quality Metrics"
        ],
        "summary": "Calculate AVQI metrics from connected speech and sustained vowel audio recordings",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "csFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the connected speech audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "AVQI algorithm version: \"v02.03\" or \"v03.01\" - REQUIRED"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "AVQI": {
                      "type": "number",
                      "description": "Acoustic Voice Quality Index - final composite score (0-10 scale, dimensionless). Values above language-specific threshold indicate potential voice pathology"
                    },
                    "CPPS": {
                      "type": "string",
                      "description": "Smoothed Cepstral Peak Prominence measuring harmonic structure (dB). Higher values indicate better periodicity and voice quality"
                    },
                    "HNR": {
                      "type": "string",
                      "description": "Mean Harmonics-to-Noise Ratio across concatenated CS+SV signal (dB). Higher values indicate less noise relative to harmonic content"
                    },
                    "Shimmer": {
                      "type": "number",
                      "description": "Period-to-period amplitude variation expressed as percentage (%). Lower values indicate more stable amplitude control"
                    },
                    "Shimmer_dB": {
                      "type": "string",
                      "description": "Period-to-period amplitude variation in logarithmic scale (dB). Lower values indicate better amplitude stability"
                    },
                    "LTAS_slope": {
                      "type": "number",
                      "description": "Spectral slope between 0-1kHz and 1-10kHz frequency ranges (dB/octave). More negative values indicate steeper spectral roll-off"
                    },
                    "LTAS_tilt": {
                      "type": "string",
                      "description": "Spectral tilt of trend line through long-term average spectrum 1-10kHz (dB/octave). Indicates overall spectral balance and voice quality"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/assignFileId": {
      "post": {
        "operationId": "postAssignFileId",
        "tags": [
          "Voice Quality Metrics"
        ],
        "summary": "Upload audio files for AVQI analysis",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "audio": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file for analysis (WAV format preferred) - REQUIRED"
                  },
                  "email": {
                    "type": "string",
                    "description": "Email associated with the user account - REQUIRED"
                  }
                },
                "required": [
                  "audio",
                  "email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "fileId": {
                      "type": "string",
                      "description": "ID of the uploaded file for use with the calculate-avqi endpoint"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-dsi": {
      "get": {
        "operationId": "getCalculateDsi",
        "tags": [
          "Voice Quality Metrics"
        ],
        "summary": "Calculate DSI from a previously uploaded sustained vowel (SV) recording and required voice-range parameters. All para…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (returned by /api/assignFileId) - REQUIRED"
          },
          {
            "name": "mpt",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "description": "Maximum Phonation Time in seconds (MPT). Must be a positive number > 0 - REQUIRED"
          },
          {
            "name": "maximumF0",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "description": "Highest fundamental frequency in Hz (F0-High). Must be a positive number > 0 - REQUIRED"
          },
          {
            "name": "minimumIntensity",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "description": "Softest intensity level in dB SPL (I_low). Numeric value - REQUIRED"
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Patient age in years (1-120). Used for clinical interpretation - REQUIRED"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Patient gender code: 1=Male, 2=Female, 3=Other/Unknown. Used for F0 validation/context - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional DSI algorithm version (example: \"v02.01\") - OPTIONAL"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "DSI": {
                      "type": "number",
                      "description": "number - Dysphonia Severity Index score (approx range -5 to +5). Example: 1.85"
                    },
                    "JITTER": {
                      "type": "number",
                      "description": "number - Period Perturbation Quotient (PPQ5) as a percentage or fraction (parsed as number). Example: 0.45"
                    },
                    "MPT": {
                      "type": "number",
                      "description": "number - Maximum Phonation Time in seconds (echoes input MPT or measured). Example: 15.2"
                    },
                    "MINLEVEL": {
                      "type": "number",
                      "description": "number - Minimum intensity level in dB SPL. Example: 45.5"
                    },
                    "MAXF0": {
                      "type": "number",
                      "description": "number - Maximum fundamental frequency in Hz. Example: 440.0"
                    },
                    "PATIENT_AGE": {
                      "type": "number",
                      "description": "number - Patient age (integer). Example: 35"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "string - Human-readable gender label (e.g. \"Female\")"
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "string - Age group label used for interpretation (e.g. \"Young adult / Middle-aged\")"
                    },
                    "PRESBYLARYNGIS_RISK": {
                      "type": "number",
                      "description": "number - Age-related voice change risk flag (0 or 1). Example: 0"
                    },
                    "EXPECTED_F0_RANGE": {
                      "type": "number",
                      "description": "string - Gender-specific expected F0 range. Example: \"150-350 Hz\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-cpp": {
      "get": {
        "operationId": "getCalculateCpp",
        "tags": [
          "Voice Quality Metrics"
        ],
        "summary": "Calculate CPP and complementary voice measures from sustained vowel recording",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "CPP algorithm version (default: \"v01\") - OPTIONAL"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "CPP": {
                      "type": "number",
                      "description": "Cepstral Peak Prominence value in dB. Example: 12.45"
                    },
                    "VOICE_QUALITY": {
                      "type": "string",
                      "description": "Clinical voice quality assessment. Example: \"Good voice quality\""
                    },
                    "SEVERITY": {
                      "type": "string",
                      "description": "Dysphonia severity classification. Example: \"Normal\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-hnr-multiband": {
      "get": {
        "operationId": "getCalculateHnrMultiband",
        "tags": [
          "Voice Quality Metrics"
        ],
        "summary": "Calculate multi-band HNR with age and gender-specific clinical interpretation",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            },
            "description": "Patient age in years (integer) - REQUIRED for age-specific analysis"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                2,
                3
              ]
            },
            "description": "Patient gender: 1=Male, 2=Female, 3=Other/Unknown (integer) - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "HNR algorithm version (default: \"v01\") - OPTIONAL"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "HNR_FULL": {
                      "type": "number",
                      "description": "Full-spectrum HNR (80-8000 Hz) in dB. Example: 15.4"
                    },
                    "HNR_LOW": {
                      "type": "number",
                      "description": "Low-frequency HNR (80-500 Hz) in dB. Example: 18.2"
                    },
                    "HNR_MID": {
                      "type": "number",
                      "description": "Mid-frequency HNR (500-1500 Hz) in dB. Example: 16.8"
                    },
                    "HNR_HIGH": {
                      "type": "number",
                      "description": "High-frequency HNR (1500-3500 Hz) in dB. Example: 12.3"
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz. Example: 195.4"
                    },
                    "F0_STD": {
                      "type": "string",
                      "description": "Standard deviation of F0. Example: 8.5"
                    },
                    "GENDER": {
                      "type": "string",
                      "description": "Gender classification result. Example: \"Female\""
                    },
                    "NOISE_RATIO_LOW": {
                      "type": "number",
                      "description": "Low-frequency noise percentage. Example: 12.5"
                    },
                    "NOISE_RATIO_MID": {
                      "type": "number",
                      "description": "Mid-frequency noise percentage. Example: 18.2"
                    },
                    "NOISE_RATIO_HIGH": {
                      "type": "number",
                      "description": "High-frequency noise percentage. Example: 25.7"
                    },
                    "HNR_SLOPE": {
                      "type": "number",
                      "description": "Spectral tilt across frequency bands. Example: -0.68"
                    },
                    "OVERALL_QUALITY": {
                      "type": "string",
                      "description": "Clinical voice quality assessment. Example: \"Good voice quality\""
                    },
                    "SEVERITY": {
                      "type": "string",
                      "description": "Voice quality severity classification. Example: \"Normal\""
                    },
                    "NOISE_PATTERN": {
                      "type": "number",
                      "description": "Dominant noise pattern classification. Example: \"Low-frequency emphasis\""
                    },
                    "BREATHINESS": {
                      "type": "string",
                      "description": "Breathiness assessment. Example: \"Minimal breathiness\""
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Patient age used in analysis. Example: 35"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "Patient gender classification. Example: \"Female\""
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Age group classification. Example: \"Young Adult\""
                    },
                    "AGE_NOTE": {
                      "type": "string",
                      "description": "Age-related clinical note. Example: \"Age within normal vocal range\""
                    },
                    "F0_NOTE": {
                      "type": "string",
                      "description": "F0 validation note. Example: \"F0 within expected range for gender/age\""
                    },
                    "GENDER_NOTE": {
                      "type": "string",
                      "description": "Gender-specific note. Example: \"Female vocal characteristics confirmed\""
                    },
                    "EXPECTED_F0_MIN": {
                      "type": "string",
                      "description": "Expected minimum F0 for age/gender. Example: 165.4"
                    },
                    "EXPECTED_F0_MAX": {
                      "type": "string",
                      "description": "Expected maximum F0 for age/gender. Example: 294.3"
                    },
                    "HNR_ADJUSTMENT": {
                      "type": "string",
                      "description": "Age-based threshold adjustment applied. Example: 0.8"
                    },
                    "ADJUSTED_HNR_FULL": {
                      "type": "string",
                      "description": "Age-adjusted full-spectrum HNR. Example: 16.2"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-spectral-advanced": {
      "get": {
        "operationId": "getCalculateSpectralAdvanced",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate advanced spectral measures with age and gender-specific clinical interpretation",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            },
            "description": "Patient age in years (integer) - REQUIRED for age-specific adjustments"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                2,
                3
              ]
            },
            "description": "Patient gender: 1=Male, 2=Female, 3=Other/Unknown (integer) - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Spectral analysis algorithm version (default: \"v01\") - OPTIONAL"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "SPECTRAL_MEAN": {
                      "type": "number",
                      "description": "Weighted average frequency (center of gravity) in Hz. Example: 1847.3"
                    },
                    "SPECTRAL_SD": {
                      "type": "number",
                      "description": "Standard deviation of spectral distribution in Hz. Example: 623.8"
                    },
                    "SPECTRAL_SKEWNESS": {
                      "type": "string",
                      "description": "Third moment indicating spectral asymmetry. Example: 0.85"
                    },
                    "SPECTRAL_KURTOSIS": {
                      "type": "string",
                      "description": "Fourth moment indicating spectral peakedness. Example: 2.34"
                    },
                    "ALPHA_RATIO": {
                      "type": "number",
                      "description": "Energy ratio below/above 1 kHz in dB. Example: 4.2"
                    },
                    "L1_L0": {
                      "type": "number",
                      "description": "First formant to fundamental energy difference in dB. Example: -8.5"
                    },
                    "H1_H2": {
                      "type": "number",
                      "description": "First to second harmonic amplitude difference in dB. Example: 3.8"
                    },
                    "H1_A1": {
                      "type": "number",
                      "description": "First harmonic to first formant amplitude difference in dB. Example: -5.2"
                    },
                    "H1_A3": {
                      "type": "number",
                      "description": "First harmonic to third formant amplitude difference in dB. Example: -15.7"
                    },
                    "SPECTRAL_FLUX": {
                      "type": "number",
                      "description": "Rate of spectral change in Hz. Example: 234.6"
                    },
                    "LTAS_SLOPE": {
                      "type": "number",
                      "description": "Spectral slope 0-1 kHz vs 1-4 kHz in dB/octave. Example: -12.4"
                    },
                    "LTAS_TILT": {
                      "type": "number",
                      "description": "Trend line slope across 1-4 kHz in dB/octave. Example: -8.9"
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz. Example: 195.8"
                    },
                    "F1_MEAN": {
                      "type": "number",
                      "description": "Mean first formant frequency in Hz. Example: 685.4"
                    },
                    "F2_MEAN": {
                      "type": "number",
                      "description": "Mean second formant frequency in Hz. Example: 1247.8"
                    },
                    "F3_MEAN": {
                      "type": "number",
                      "description": "Mean third formant frequency in Hz. Example: 2856.1"
                    },
                    "GENDER": {
                      "type": "string",
                      "description": "Gender classification result. Example: \"Female\""
                    },
                    "VOICE_PATTERN": {
                      "type": "string",
                      "description": "Clinical classification. Example: \"Balanced voice pattern\""
                    },
                    "BREATHINESS_LEVEL": {
                      "type": "string",
                      "description": "Breathiness assessment. Example: \"Minimal breathiness\""
                    },
                    "VOICE_STABILITY": {
                      "type": "string",
                      "description": "Stability classification. Example: \"Good stability\""
                    },
                    "SPECTRAL_HEALTH": {
                      "type": "string",
                      "description": "Overall spectral assessment. Example: \"Healthy spectral characteristics\""
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Patient age used in analysis. Example: 35"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "Patient gender classification. Example: \"Female\""
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Age group classification. Example: \"Young Adult\""
                    },
                    "AGE_NOTE": {
                      "type": "string",
                      "description": "Age-related clinical note. Example: \"Age within normal vocal range\""
                    },
                    "F0_NOTE": {
                      "type": "string",
                      "description": "F0 validation note. Example: \"F0 within expected range\""
                    },
                    "F0_VALIDITY": {
                      "type": "string",
                      "description": "F0 validation status. Example: \"Valid\""
                    },
                    "GENDER_SPECTRAL_NOTE": {
                      "type": "string",
                      "description": "Gender-specific spectral note. Example: \"Female spectral characteristics confirmed\""
                    },
                    "EXPECTED_F0_MIN": {
                      "type": "string",
                      "description": "Expected minimum F0 for age/gender. Example: 165.4"
                    },
                    "EXPECTED_F0_MAX": {
                      "type": "string",
                      "description": "Expected maximum F0 for age/gender. Example: 294.3"
                    },
                    "SPECTRAL_MEAN_EXPECTED": {
                      "type": "string",
                      "description": "Expected spectral mean for demographics. Example: 1923.5"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-formant-statistics": {
      "get": {
        "operationId": "getCalculateFormantStatistics",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate comprehensive formant statistics with gender-specific validation and clinical interpretation",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            },
            "description": "Patient age in years (integer) - REQUIRED for clinical context"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                2,
                3
              ]
            },
            "description": "Patient gender: 1=Male, 2=Female, 3=Other/Unknown (integer) - REQUIRED"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Formant analysis algorithm version (default: \"v01\") - OPTIONAL"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "F1_MEAN": {
                      "type": "number",
                      "description": "Mean first formant frequency in Hz. Example: 685.4"
                    },
                    "F1_STD": {
                      "type": "number",
                      "description": "F1 standard deviation in Hz. Example: 45.2"
                    },
                    "F1_CV": {
                      "type": "string",
                      "description": "F1 coefficient of variation in %. Example: 6.6"
                    },
                    "F1_MEDIAN": {
                      "type": "number",
                      "description": "F1 median frequency in Hz. Example: 682.1"
                    },
                    "F1_IQR": {
                      "type": "number",
                      "description": "F1 interquartile range in Hz. Example: 38.7"
                    },
                    "F1_RANGE": {
                      "type": "number",
                      "description": "F1 frequency range in Hz. Example: 142.5"
                    },
                    "F2_MEAN": {
                      "type": "number",
                      "description": "Mean second formant frequency in Hz. Example: 1247.8"
                    },
                    "F2_STD": {
                      "type": "number",
                      "description": "F2 standard deviation in Hz. Example: 78.3"
                    },
                    "F2_CV": {
                      "type": "string",
                      "description": "F2 coefficient of variation in %. Example: 6.3"
                    },
                    "F2_MEDIAN": {
                      "type": "number",
                      "description": "F2 median frequency in Hz. Example: 1245.6"
                    },
                    "F2_IQR": {
                      "type": "number",
                      "description": "F2 interquartile range in Hz. Example: 65.1"
                    },
                    "F2_RANGE": {
                      "type": "number",
                      "description": "F2 frequency range in Hz. Example: 234.8"
                    },
                    "F3_MEAN": {
                      "type": "number",
                      "description": "Mean third formant frequency in Hz. Example: 2856.1"
                    },
                    "F3_STD": {
                      "type": "number",
                      "description": "F3 standard deviation in Hz. Example: 112.4"
                    },
                    "F3_CV": {
                      "type": "string",
                      "description": "F3 coefficient of variation in %. Example: 3.9"
                    },
                    "F3_MEDIAN": {
                      "type": "number",
                      "description": "F3 median frequency in Hz. Example: 2851.7"
                    },
                    "F3_IQR": {
                      "type": "number",
                      "description": "F3 interquartile range in Hz. Example: 89.3"
                    },
                    "F3_RANGE": {
                      "type": "number",
                      "description": "F3 frequency range in Hz. Example: 387.2"
                    },
                    "F4_MEAN": {
                      "type": "number",
                      "description": "Mean fourth formant frequency in Hz. Example: 3847.5"
                    },
                    "F4_STD": {
                      "type": "number",
                      "description": "F4 standard deviation in Hz. Example: 145.7"
                    },
                    "F4_CV": {
                      "type": "string",
                      "description": "F4 coefficient of variation in %. Example: 3.8"
                    },
                    "F4_MEDIAN": {
                      "type": "number",
                      "description": "F4 median frequency in Hz. Example: 3842.9"
                    },
                    "F4_IQR": {
                      "type": "number",
                      "description": "F4 interquartile range in Hz. Example: 123.8"
                    },
                    "F4_RANGE": {
                      "type": "number",
                      "description": "F4 frequency range in Hz. Example: 512.6"
                    },
                    "F2_F1_DIFF": {
                      "type": "number",
                      "description": "F2-F1 frequency difference in Hz. Example: 562.4"
                    },
                    "F3_F2_DIFF": {
                      "type": "number",
                      "description": "F3-F2 frequency difference in Hz. Example: 1608.3"
                    },
                    "F4_F3_DIFF": {
                      "type": "number",
                      "description": "F4-F3 frequency difference in Hz. Example: 991.4"
                    },
                    "VOWEL_SPACE_DISTANCE": {
                      "type": "number",
                      "description": "Distance from neutral vowel in Hz. Example: 234.6"
                    },
                    "FORMANT_STABILITY_INDEX": {
                      "type": "number",
                      "description": "Articulatory consistency (0-100). Example: 87.3"
                    },
                    "ARTICULATORY_PRECISION": {
                      "type": "string",
                      "description": "Clinical precision level. Example: \"Good articulatory precision\""
                    },
                    "PRECISION_LEVEL": {
                      "type": "string",
                      "description": "Severity classification. Example: \"Normal precision\""
                    },
                    "VOWEL_QUALITY": {
                      "type": "string",
                      "description": "Gender-specific assessment. Example: \"Normal female vowel production\""
                    },
                    "HYPERNASALITY_RISK": {
                      "type": "string",
                      "description": "Hypernasality screening. Example: \"Low risk\""
                    },
                    "GENDER": {
                      "type": "string",
                      "description": "Gender classification. Example: \"Female\""
                    },
                    "VOICE_PATTERN": {
                      "type": "string",
                      "description": "Clinical pattern assessment. Example: \"Normal formant pattern\""
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Patient age in years. Example: 35"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "Patient gender classification. Example: \"Female\""
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Age-based grouping. Example: \"Young Adult\""
                    },
                    "AGE_NOTE": {
                      "type": "string",
                      "description": "Age-related clinical note. Example: \"Age within normal vocal range\""
                    },
                    "GENDER_FORMANT_NOTE": {
                      "type": "string",
                      "description": "Gender-specific formant note. Example: \"Formant frequencies consistent with female anatomy\""
                    },
                    "EXPECTED_F1_RANGE": {
                      "type": "number",
                      "description": "Expected F1 range for demographics. Example: \"650-720 Hz\""
                    },
                    "EXPECTED_F2_RANGE": {
                      "type": "number",
                      "description": "Expected F2 range for demographics. Example: \"1200-1300 Hz\""
                    },
                    "EXPECTED_F3_RANGE": {
                      "type": "number",
                      "description": "Expected F3 range for demographics. Example: \"2800-2900 Hz\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-sz-ratio": {
      "get": {
        "operationId": "getCalculateSzRatio",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate S/Z ratio with age-specific interpretation and quality assessment",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the /s/ sound audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "zFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the /z/ sound audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "patientAge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "description": "Patient age in years (for presbylaryngis assessment) - REQUIRED"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Patient gender (\"male\" or \"female\") - REQUIRED"
          },
          {
            "name": "clinicalContext",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Clinical context (\"screening\", \"therapy\", \"neurological\", \"post-surgical\") - default: \"screening\""
          },
          {
            "name": "silenceThreshold",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Silence detection threshold in dB - default: -30"
          },
          {
            "name": "minVoicedDuration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Minimum voiced segment duration in seconds - default: 0.1"
          },
          {
            "name": "minVoicelessDuration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Minimum voiceless segment duration in seconds - default: 0.1"
          },
          {
            "name": "edgePadding",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Edge padding to avoid artifacts in seconds - default: 0.05"
          },
          {
            "name": "maxRecordingDuration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Maximum recording duration in seconds - default: 30"
          },
          {
            "name": "chunkDuration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Analysis chunk duration in seconds - default: 10"
          },
          {
            "name": "version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "S/Z analysis algorithm version - default: \"v01\""
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "S_PHONATION_TIME": {
                      "type": "number",
                      "description": "Total sustained /s/ phonation duration in seconds. Example: 18.7"
                    },
                    "Z_PHONATION_TIME": {
                      "type": "number",
                      "description": "Total sustained /z/ phonation duration in seconds. Example: 19.2"
                    },
                    "SZ_RATIO": {
                      "type": "string",
                      "description": "S/Z phonation time ratio (primary clinical measure). Example: 0.97"
                    },
                    "S_EFFICIENCY": {
                      "type": "number",
                      "description": "Percentage of /s/ recording with actual phonation. Example: 85.4"
                    },
                    "Z_EFFICIENCY": {
                      "type": "number",
                      "description": "Percentage of /z/ recording with actual phonation. Example: 87.2"
                    },
                    "S_PHONATION_SEGMENTS": {
                      "type": "number",
                      "description": "Number of continuous /s/ phonation segments. Example: 3"
                    },
                    "Z_PHONATION_SEGMENTS": {
                      "type": "number",
                      "description": "Number of continuous /z/ phonation segments. Example: 2"
                    },
                    "S_LONGEST_SEGMENT": {
                      "type": "number",
                      "description": "/s/ longest continuous segment duration in seconds. Example: 12.5"
                    },
                    "Z_LONGEST_SEGMENT": {
                      "type": "number",
                      "description": "/z/ longest continuous segment duration in seconds. Example: 15.8"
                    },
                    "MEAN_F0_Z": {
                      "type": "number",
                      "description": "Mean fundamental frequency during /z/ phonation in Hz. Example: 195.8"
                    },
                    "F0_STD_Z": {
                      "type": "number",
                      "description": "Standard deviation of F0 during /z/ phonation in Hz. Example: 8.3"
                    },
                    "F0_CV_Z": {
                      "type": "string",
                      "description": "Coefficient of variation of F0 during /z/ in %. Example: 4.2"
                    },
                    "RELIABILITY_SCORE": {
                      "type": "number",
                      "description": "Composite reliability score (0-4). Example: 3.8"
                    },
                    "PRESBYLARYNGIS_RISK": {
                      "type": "string",
                      "description": "Age-related voice changes risk (0/1). Example: 0"
                    },
                    "SZ_INTERPRETATION": {
                      "type": "string",
                      "description": "Clinical classification with age adjustment. Example: \"Normal S/Z ratio\""
                    },
                    "CLINICAL_SIGNIFICANCE": {
                      "type": "string",
                      "description": "Pathophysiology interpretation. Example: \"No evidence of vocal fold mass lesions\""
                    },
                    "RISK_LEVEL": {
                      "type": "string",
                      "description": "Stratified risk assessment. Example: \"Low\""
                    },
                    "RELIABILITY": {
                      "type": "string",
                      "description": "Test reliability classification. Example: \"High reliability\""
                    },
                    "AGE_ADJUSTMENT": {
                      "type": "string",
                      "description": "Age-specific interpretation note. Example: \"No age-related adjustments needed\""
                    },
                    "GENDER": {
                      "type": "string",
                      "description": "Gender classification. Example: \"Female\""
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Patient age in years. Example: 35"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "Patient gender classification. Example: \"Female\""
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Age-based clinical grouping. Example: \"Young Adult\""
                    },
                    "AGE_NOTE": {
                      "type": "string",
                      "description": "Age-related clinical note. Example: \"Age within normal vocal range\""
                    },
                    "GENDER_NOTE": {
                      "type": "string",
                      "description": "Gender-specific clinical note. Example: \"Female-typical phonation patterns\""
                    },
                    "EXPECTED_SZ_RANGE": {
                      "type": "string",
                      "description": "Expected S/Z ratio range for demographics. Example: \"0.85-1.15\""
                    },
                    "PHONATION_QUALITY": {
                      "type": "string",
                      "description": "Overall phonation quality assessment. Example: \"Good phonatory control\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-gne": {
      "get": {
        "operationId": "getCalculateGne",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate GNE using the validated Michaelis algorithm implemented in Praat",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "GNE_VALUE": {
                      "type": "number",
                      "description": "Glottal-to-Noise Excitation Ratio on 0-1 scale. Example: 0.425"
                    },
                    "GNE_DB": {
                      "type": "string",
                      "description": "GNE expressed in decibel scale for clinical interpretation. Example: -7.4"
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Average fundamental frequency in Hz. Example: 185.3"
                    },
                    "F0_STD": {
                      "type": "number",
                      "description": "F0 standard deviation indicating pitch stability in Hz. Example: 8.3"
                    },
                    "HNR": {
                      "type": "number",
                      "description": "Harmonics-to-noise ratio in dB (for comparison with GNE). Example: 12.8"
                    },
                    "GENDER": {
                      "type": "string",
                      "description": "Gender classification based on F0 range. Example: \"Female\""
                    },
                    "VOICE_QUALITY": {
                      "type": "string",
                      "description": "Qualitative assessment of voice quality. Example: \"Borderline normal\""
                    },
                    "CLINICAL_RECOMMENDATION": {
                      "type": "string",
                      "description": "Contextual clinical guidance based on GNE value. Example: \"Monitor voice quality. Consider vocal hygiene if symptoms persist.\""
                    },
                    "METHOD": {
                      "type": "string",
                      "description": "Calculation method identifier. Example: \"Native_Praat_GNE\""
                    },
                    "ANALYSIS_TYPE": {
                      "type": "string",
                      "description": "Analysis type descriptor. Example: \"Native_Praat_GNE\""
                    },
                    "FREQUENCY_RANGE": {
                      "type": "number",
                      "description": "Frequency range analyzed. Example: \"500-4500 Hz\""
                    },
                    "BANDWIDTH": {
                      "type": "number",
                      "description": "Bandwidth used in analysis. Example: \"1000 Hz\""
                    },
                    "STEP_SIZE": {
                      "type": "number",
                      "description": "Step size for frequency analysis. Example: \"80 Hz\""
                    },
                    "ALGORITHM": {
                      "type": "string",
                      "description": "Algorithm reference. Example: \"Michaelis_et_al_1997\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-h1-h2": {
      "get": {
        "operationId": "getCalculateH1H2",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate formant-corrected H1*-H2* voice source measure",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Speaker gender for optimal formant analysis: \"male\"/\"1\", \"female\"/\"2\", or \"other\"/\"3\" - REQUIRED. Determines formant ceiling: Female=5500Hz, Male=5000Hz, Other=F0-adaptive"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "H1_H2": {
                      "type": "number",
                      "description": "Raw (uncorrected) H1-H2 in dB. Amplitude difference between first and second harmonics without formant correction. Use for comparison with corrected value. Example: 5.88"
                    },
                    "H1_H2_CORRECTED": {
                      "type": "number",
                      "description": "Formant-corrected H1*-H2* in dB. Primary measure accounting for vocal tract resonance effects using Iseli & Alwan (2004) algorithm. Higher values may indicate breathier voice quality. Example: 10.93"
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz. Averaged across all valid frames in the stable vowel portion. Example: 134.76"
                    },
                    "F1_MEAN": {
                      "type": "number",
                      "description": "Mean first formant frequency in Hz. Extracted using Praat Burg algorithm. Vowel height correlate. Example: 473.00"
                    },
                    "F2_MEAN": {
                      "type": "number",
                      "description": "Mean second formant frequency in Hz. Extracted using Praat Burg algorithm. Vowel frontness/backness correlate. Example: 1183.97"
                    },
                    "B1_MEAN": {
                      "type": "number",
                      "description": "Estimated first formant bandwidth in Hz. Calculated using Hawk & Miller (1995) formula: B1 = 50 + (F1/10). Used for formant correction. Example: 97.30"
                    },
                    "B2_MEAN": {
                      "type": "number",
                      "description": "Estimated second formant bandwidth in Hz. Calculated using Hawk & Miller (1995) formula: B2 = 70 + (F2/50). Used for formant correction. Example: 93.68"
                    },
                    "FRAMES_ANALYZED": {
                      "type": "number",
                      "description": "Number of valid frames analyzed. Frame shift = 1ms, window = 3 pitch periods. Higher counts indicate longer recordings or more stable voicing. Example: 2977"
                    },
                    "GENDER": {
                      "type": "number",
                      "description": "Gender classification used for formant analysis. Determines formant ceiling frequency. Example: \"Male\" or \"Female (F0-based)\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-ambitus": {
      "get": {
        "operationId": "getCalculateAmbitus",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Analyzes voice range profile from sustained vowel glissando recording",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "binary"
            },
            "description": "File ID of the uploaded glissando recording (sustained vowel from low to high pitch)"
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            },
            "description": "Representative age from age group (Child: 8, Adolescent: 15, Adult: 30). Affects pitch tracking parameters and range expectations"
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                2,
                3
              ]
            },
            "description": "Patient gender (1=Male, 2=Female). Influences expected range and analysis settings"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "AMBITUS_SEMITONES": {
                      "type": "string",
                      "description": "Voice range in semitones (12 × log₂(F0_max/F0_min))"
                    },
                    "AMBITUS_OCTAVES": {
                      "type": "string",
                      "description": "Voice range in octaves (semitones ÷ 12)"
                    },
                    "FREQUENCY_RATIO": {
                      "type": "number",
                      "description": "Ratio of highest to lowest frequency (F0_max/F0_min)"
                    },
                    "RANGE_CLASSIFICATION": {
                      "type": "string",
                      "description": "Age-appropriate range assessment (Excellent/Normal/Reduced/Severely reduced)"
                    },
                    "F0_MIN": {
                      "type": "number",
                      "description": "Minimum fundamental frequency in Hz"
                    },
                    "F0_MAX": {
                      "type": "number",
                      "description": "Maximum fundamental frequency in Hz"
                    },
                    "F0_MEAN": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz"
                    },
                    "F0_MEDIAN": {
                      "type": "number",
                      "description": "Median fundamental frequency in Hz"
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Patient age used in analysis"
                    },
                    "PATIENT_GENDER": {
                      "type": "string",
                      "description": "Patient gender (Male/Female)"
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Age category (Child/Adolescent/Adult)"
                    },
                    "PITCH_FLOOR": {
                      "type": "number",
                      "description": "Lower limit for pitch tracking in Hz"
                    },
                    "PITCH_CEILING": {
                      "type": "number",
                      "description": "Upper limit for pitch tracking in Hz"
                    },
                    "ANALYSIS_METHOD": {
                      "type": "string",
                      "description": "Analysis technique used (Voice Range Profile)"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/jitter-shimmer": {
      "get": {
        "operationId": "getJitterShimmer",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate jitter, shimmer, and recording quality metrics with clinical interpretation",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number"
            },
            "description": "ID of the sustained vowel audio file (previously uploaded) - REQUIRED. Minimum 1 second, recommended 3+ seconds for reliability"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "RECORDING_QUALITY": {
                      "type": "string",
                      "description": "Quality assessment: \"Good\" (-25 to -10 dBFS), \"Suboptimal\" (-30 to -25 or -10 to -6 dBFS), \"Poor\" (<-30 or >-6 dBFS). Example: \"Good\""
                    },
                    "RECORDING_QUALITY_WARNING": {
                      "type": "string",
                      "description": "Detailed warning message if quality is suboptimal or poor. Empty string if good. Example: \"CAUTION: Recording level is low (<-25 dBFS). Consider re-recording with slightly higher volume for more reliable results.\""
                    },
                    "MEAN_INTENSITY_DBFS": {
                      "type": "string",
                      "description": "Mean recording intensity in dBFS (decibels relative to full scale). Target range: -25 to -10 dBFS. Example: -18.3"
                    },
                    "RMS_AMPLITUDE": {
                      "type": "number",
                      "description": "Root-mean-square amplitude (0-1 scale). Used to calculate dBFS. Example: 0.122"
                    },
                    "JITTER_LOCAL_PERCENT": {
                      "type": "string",
                      "description": "Local jitter (period-to-period variation) in percent. Primary jitter measure. Normal: ≤1.04%. Example: 0.85"
                    },
                    "JITTER_PPQ5_PERCENT": {
                      "type": "string",
                      "description": "5-period perturbation quotient in percent. Smoothed jitter over 5 periods. Example: 0.78"
                    },
                    "JITTER_RAP_PERCENT": {
                      "type": "string",
                      "description": "Relative average perturbation in percent. Average over 3 consecutive periods. Example: 0.82"
                    },
                    "JITTER_DDP_PERCENT": {
                      "type": "string",
                      "description": "Difference of differences of periods in percent. Sensitive to small perturbations. Example: 1.23"
                    },
                    "SHIMMER_LOCAL_PERCENT": {
                      "type": "string",
                      "description": "Local shimmer (peak-to-peak amplitude variation) in percent. Primary shimmer measure. Normal: ≤3.81%. Example: 2.45"
                    },
                    "SHIMMER_LOCAL_DB": {
                      "type": "string",
                      "description": "Local shimmer in decibels. Logarithmic amplitude perturbation. Example: 0.215"
                    },
                    "SHIMMER_APQ3_PERCENT": {
                      "type": "string",
                      "description": "3-period amplitude perturbation quotient in percent. Short-term shimmer. Example: 2.31"
                    },
                    "SHIMMER_APQ5_PERCENT": {
                      "type": "string",
                      "description": "5-period amplitude perturbation quotient in percent. Medium-term shimmer. Example: 2.38"
                    },
                    "SHIMMER_APQ11_PERCENT": {
                      "type": "string",
                      "description": "11-period amplitude perturbation quotient in percent. Long-term shimmer trends. Example: 2.52"
                    },
                    "SHIMMER_DDA_PERCENT": {
                      "type": "string",
                      "description": "Difference of differences of amplitudes in percent. Sensitive to amplitude changes. Example: 3.47"
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz. Averaged across voiced segments. Example: 185.7"
                    },
                    "F0_STD": {
                      "type": "number",
                      "description": "Standard deviation of F0 in Hz. Pitch variability indicator. Example: 7.2"
                    },
                    "F0_CV": {
                      "type": "string",
                      "description": "Coefficient of variation of F0 in percent. (F0_STD / MEAN_F0) × 100. Pitch stability metric. Example: 3.88"
                    },
                    "VOICELESS_PERCENT": {
                      "type": "number",
                      "description": "Percentage of voiceless (unvoiced) frames. Indicates phonation breaks. Example: 5.2"
                    },
                    "NUMBER_OF_PERIODS": {
                      "type": "number",
                      "description": "Number of vocal fold vibration periods analyzed. Minimum 20 required, 100+ optimal. Example: 245"
                    },
                    "INSUFFICIENT_PERIODS": {
                      "type": "string",
                      "description": "Flag indicating insufficient periods: 1 if <100 periods (reduced reliability), 0 if ≥100 periods. Example: 0"
                    },
                    "JITTER_SEVERITY": {
                      "type": "string",
                      "description": "Jitter classification: \"Normal\" (≤1.04%) or \"Elevated\" (>1.04%). Example: \"Normal\""
                    },
                    "SHIMMER_SEVERITY": {
                      "type": "string",
                      "description": "Shimmer classification: \"Normal\" (≤3.81%) or \"Elevated\" (>3.81%). Example: \"Normal\""
                    },
                    "JITTER_INTERPRETATION": {
                      "type": "string",
                      "description": "Clinical interpretation text for jitter results. Example: \"Within normal limits (≤1.04%)\""
                    },
                    "SHIMMER_INTERPRETATION": {
                      "type": "string",
                      "description": "Clinical interpretation text for shimmer results. Example: \"Within normal limits (≤3.81%)\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-abi": {
      "get": {
        "operationId": "getCalculateAbi",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Calculate the Acoustic Breathiness Index (ABI) from a connected speech recording and a sustained vowel recording. The…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "csFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId of the CONNECTED SPEECH recording (e.g., reading a passage)."
          },
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId of the SUSTAINED VOWEL /a/ recording (≥ 5 s)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ABI_SCORE": {
                      "type": "number",
                      "description": "Acoustic Breathiness Index — composite multi-component score (number)."
                    },
                    "CPPS": {
                      "type": "number",
                      "description": "Cepstral Peak Prominence (Smoothed) in dB — harmonic-to-aperiodic structure indicator."
                    },
                    "JITTER_PERCENT": {
                      "type": "number",
                      "description": "Local jitter as a percentage — period perturbation."
                    },
                    "GNE_APPROXIMATION": {
                      "type": "string",
                      "description": "Approximate Glottal-to-Noise Excitation ratio."
                    },
                    "HNR_6KHZ": {
                      "type": "string",
                      "description": "Harmonics-to-Noise Ratio computed in the 0–6 kHz band (dB)."
                    },
                    "HNR_DEJONCKERE": {
                      "type": "string",
                      "description": "HNR computed using De Jonckere's method (dB)."
                    },
                    "H1_H2_DIFF": {
                      "type": "number",
                      "description": "Difference between the first two harmonic amplitudes (H1 − H2) in dB — voice source quality indicator."
                    },
                    "SHIMMER_DB": {
                      "type": "string",
                      "description": "Shimmer in logarithmic scale (dB)."
                    },
                    "SHIMMER_PERCENT": {
                      "type": "number",
                      "description": "Shimmer as a percentage."
                    },
                    "PERIOD_STD": {
                      "type": "string",
                      "description": "Standard deviation of glottal period (period stability)."
                    },
                    "CS_DURATION": {
                      "type": "number",
                      "description": "Connected speech recording duration in seconds."
                    },
                    "SV_DURATION": {
                      "type": "number",
                      "description": "Sustained vowel recording duration in seconds."
                    },
                    "CS_DURATION_USED": {
                      "type": "string",
                      "description": "Portion of CS actually analyzed (after silence trimming)."
                    },
                    "SV_DURATION_USED": {
                      "type": "string",
                      "description": "Portion of SV actually analyzed."
                    },
                    "TOTAL_ANALYSIS_DURATION": {
                      "type": "string",
                      "description": "Sum of CS_DURATION_USED + SV_DURATION_USED."
                    },
                    "ABI_REFERENCE": {
                      "type": "string",
                      "description": "Clinical reference text emitted by the analysis script (interpretive guidance)."
                    },
                    "ANALYSIS_VERSION": {
                      "type": "string",
                      "description": "Algorithm version, e.g. \"ABI_v01\"."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-voice-dynamics": {
      "get": {
        "operationId": "getCalculateVoiceDynamics",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Compute intensity dynamics, pitch-intensity correlation, and projection/stability/effort/control/monotonicity scores …",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "svFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId of the sustained vowel recording."
          },
          {
            "name": "age",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 120
            },
            "description": "REQUIRED. Patient age in years (1–120)."
          },
          {
            "name": "gender",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. \"male\" | \"female\" | \"other\" (or numeric \"1\" | \"2\" | \"3\")."
          },
          {
            "name": "timeStep",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 0.01 (must be 0 < x ≤ 0.1). Praat analysis frame step in seconds."
          },
          {
            "name": "minPitch",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 75. Lower limit of pitch tracking in Hz (range 50–200)."
          },
          {
            "name": "subtractMean",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional, default 1. 0 or 1 — whether to subtract DC offset before analysis."
          },
          {
            "name": "windowLength",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 0.03 (must be 0 < x ≤ 1). Analysis window in seconds."
          },
          {
            "name": "fatigueThreshold",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 1.0. Threshold for severe fatigue indicator (positive number)."
          },
          {
            "name": "mildFatigueThreshold",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional, default 0.5. Threshold for mild fatigue indicator."
          },
          {
            "name": "monotonicityCV",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional, default 5.0. Coefficient-of-variation threshold below which voice is flagged monotonous."
          },
          {
            "name": "monotonicityRange",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional, default 10.0. Pitch range threshold (semitones) below which voice is flagged monotonous."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "INTENSITY_MEAN": {
                      "type": "number",
                      "description": "Mean intensity in dB."
                    },
                    "INTENSITY_STD": {
                      "type": "number",
                      "description": "Intensity standard deviation in dB."
                    },
                    "INTENSITY_CV": {
                      "type": "string",
                      "description": "Intensity coefficient of variation (%)."
                    },
                    "INTENSITY_MIN": {
                      "type": "number",
                      "description": "Minimum intensity in dB."
                    },
                    "INTENSITY_MAX": {
                      "type": "number",
                      "description": "Maximum intensity in dB."
                    },
                    "INTENSITY_RANGE": {
                      "type": "number",
                      "description": "Intensity range (max − min) in dB."
                    },
                    "INTENSITY_MEDIAN": {
                      "type": "number",
                      "description": "Median intensity in dB."
                    },
                    "INTENSITY_Q25": {
                      "type": "number",
                      "description": "25th percentile of intensity in dB."
                    },
                    "INTENSITY_Q75": {
                      "type": "number",
                      "description": "75th percentile of intensity in dB."
                    },
                    "INTENSITY_IQR": {
                      "type": "number",
                      "description": "Inter-quartile range of intensity in dB."
                    },
                    "INTENSITY_SLOPE": {
                      "type": "string",
                      "description": "Slope of intensity over time (dB/sec) — fatigue indicator if strongly negative."
                    },
                    "PITCH_SLOPE": {
                      "type": "string",
                      "description": "Slope of pitch over time (Hz/sec)."
                    },
                    "PITCH_INTENSITY_CORRELATION": {
                      "type": "string",
                      "description": "Correlation between pitch and intensity contours."
                    },
                    "MEAN_F0": {
                      "type": "number",
                      "description": "Mean fundamental frequency in Hz."
                    },
                    "F0_STD": {
                      "type": "number",
                      "description": "F0 standard deviation in Hz."
                    },
                    "ANALYSIS_DURATION": {
                      "type": "number",
                      "description": "Analyzed duration in seconds."
                    },
                    "N_FRAMES": {
                      "type": "number",
                      "description": "Number of frames analyzed."
                    },
                    "TIME_STEP": {
                      "type": "string",
                      "description": "Echo of the timeStep parameter used."
                    },
                    "WINDOW_LENGTH": {
                      "type": "string",
                      "description": "Echo of the windowLength parameter used."
                    },
                    "FATIGUE_THRESHOLD": {
                      "type": "string",
                      "description": "Echo of the fatigueThreshold parameter used."
                    },
                    "MILD_FATIGUE_THRESHOLD": {
                      "type": "string",
                      "description": "Echo of the mildFatigueThreshold parameter used."
                    },
                    "MONOTONICITY_CV_THRESHOLD": {
                      "type": "string",
                      "description": "Echo of monotonicityCV."
                    },
                    "MONOTONICITY_RANGE_THRESHOLD": {
                      "type": "string",
                      "description": "Echo of monotonicityRange."
                    },
                    "PROJECTION_SCORE": {
                      "type": "integer",
                      "description": "Integer score (0–N) — vocal projection capability."
                    },
                    "STABILITY_SCORE": {
                      "type": "integer",
                      "description": "Integer score — intensity stability."
                    },
                    "EFFORT_SCORE": {
                      "type": "integer",
                      "description": "Integer score — vocal effort level."
                    },
                    "CONTROL_SCORE": {
                      "type": "integer",
                      "description": "Integer score — pitch/intensity coordination."
                    },
                    "MONOTONICITY_SCORE": {
                      "type": "integer",
                      "description": "Integer score — monotonicity (lower is better)."
                    },
                    "RELIABILITY_FLAG": {
                      "type": "integer",
                      "description": "Integer flag indicating whether the analysis is reliable."
                    },
                    "RELATIVE_MAX_THRESHOLD_HIGH": {
                      "type": "string",
                      "description": "Computed reference threshold (high)."
                    },
                    "RELATIVE_MAX_THRESHOLD_MODERATE": {
                      "type": "string",
                      "description": "Computed reference threshold (moderate)."
                    },
                    "GENDER_DETECTED": {
                      "type": "string",
                      "description": "Gender inferred from F0 statistics."
                    },
                    "GENDER_PROVIDED": {
                      "type": "string",
                      "description": "Echo of the gender parameter as supplied."
                    },
                    "PROJECTION_CAPABILITY": {
                      "type": "string",
                      "description": "Categorical: e.g. \"Strong\", \"Adequate\", \"Reduced\"."
                    },
                    "INTENSITY_STABILITY": {
                      "type": "string",
                      "description": "Categorical clinical label for intensity stability."
                    },
                    "VOCAL_EFFORT": {
                      "type": "string",
                      "description": "Categorical: e.g. \"Normal\", \"Increased\", \"Reduced\"."
                    },
                    "COORDINATION": {
                      "type": "string",
                      "description": "Categorical: how well pitch and intensity co-vary."
                    },
                    "FATIGUE_INDICATOR": {
                      "type": "string",
                      "description": "Categorical: \"None\" | \"Mild\" | \"Severe\"."
                    },
                    "FATIGUE_RISK": {
                      "type": "string",
                      "description": "Categorical risk level."
                    },
                    "MONOTONICITY": {
                      "type": "string",
                      "description": "Categorical: \"Monotonous\" | \"Normal variation\" | etc."
                    },
                    "MONOTONICITY_LEVEL": {
                      "type": "string",
                      "description": "Categorical severity of monotonicity."
                    },
                    "MONOTONICITY_CONFIDENCE": {
                      "type": "string",
                      "description": "Categorical confidence: \"High\" | \"Moderate\" | \"Low\"."
                    },
                    "INTENSITY_CONTROL": {
                      "type": "string",
                      "description": "Categorical assessment of intensity control."
                    },
                    "CLINICAL_INTERPRETATION": {
                      "type": "string",
                      "description": "Free-form clinical text summary."
                    },
                    "CLINICAL_RECOMMENDATION": {
                      "type": "string",
                      "description": "Free-form clinical recommendation text."
                    },
                    "PROFESSIONAL_VOICE": {
                      "type": "string",
                      "description": "Categorical: assessment of professional-voice readiness."
                    },
                    "CALIBRATION_NOTE": {
                      "type": "number",
                      "description": "Note about absolute dB calibration (recordings are typically uncalibrated)."
                    },
                    "VISUALIZATION_NOTE": {
                      "type": "string",
                      "description": "Hint for downstream visualizers."
                    },
                    "PATIENT_AGE": {
                      "type": "string",
                      "description": "Echo of the input age."
                    },
                    "AGE_GROUP": {
                      "type": "string",
                      "description": "Categorical age group (Child / Adolescent / Adult / Older Adult)."
                    },
                    "PRESBYLARYNGIS_RISK": {
                      "type": "string",
                      "description": "Categorical: presbylaryngis (age-related laryngeal change) risk."
                    },
                    "PRESBYLARYNGIS_AGE_THRESHOLD": {
                      "type": "string",
                      "description": "Threshold age above which presbylaryngis is suspected."
                    },
                    "EXPECTED_INTENSITY_RANGE": {
                      "type": "string",
                      "description": "Expected intensity range string for this demographic."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/calculate-prosody-similarity": {
      "get": {
        "operationId": "getCalculateProsodySimilarity",
        "tags": [
          "Advanced Voice Analysis"
        ],
        "summary": "Compare two recordings (a reference \"model\" and a learner \"user\") on prosodic dimensions. Returns per-dimension score…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "modelFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId of the REFERENCE recording (the model the learner is trying to imitate)."
          },
          {
            "name": "userFileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId of the LEARNER recording."
          },
          {
            "name": "modelStartTime",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 0. Seconds into the model file from which to start aligning."
          },
          {
            "name": "userStartTime",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "Optional, default 0. Seconds into the user file from which to start aligning."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "OVERALL_SCORE": {
                      "type": "number",
                      "description": "Composite similarity score on a 0–100 scale."
                    },
                    "PITCH_SCORE": {
                      "type": "number",
                      "description": "Pitch-similarity sub-score (0–100)."
                    },
                    "RHYTHM_SCORE": {
                      "type": "number",
                      "description": "Rhythm-similarity sub-score (0–100)."
                    },
                    "INTENSITY_SCORE": {
                      "type": "number",
                      "description": "Intensity-similarity sub-score (0–100)."
                    },
                    "PERFORMANCE_LEVEL": {
                      "type": "string",
                      "description": "Categorical label (e.g. \"Excellent\", \"Good\", \"Needs work\")."
                    },
                    "OVERALL_FEEDBACK": {
                      "type": "string",
                      "description": "Free-form coaching text (English)."
                    },
                    "BEST_MATCH": {
                      "type": "string",
                      "description": "Free-form description of the best-matching dimension."
                    },
                    "NEEDS_WORK": {
                      "type": "string",
                      "description": "Free-form description of the dimension that needs the most work."
                    },
                    "SPEECH_RATE_SIMILARITY": {
                      "type": "number",
                      "description": "Speech-rate similarity (0–1 or 0–100 depending on metric)."
                    },
                    "DURATION_SIMILARITY": {
                      "type": "string",
                      "description": "Total-duration similarity."
                    },
                    "PITCH_CONTOUR_SIMILARITY": {
                      "type": "string",
                      "description": "Pitch-contour shape similarity."
                    },
                    "INTENSITY_CONTOUR_SIMILARITY": {
                      "type": "string",
                      "description": "Intensity-contour shape similarity."
                    },
                    "DYNAMIC_RANGE_SIMILARITY": {
                      "type": "string",
                      "description": "Dynamic-range similarity."
                    },
                    "MODEL_F0_MEAN": {
                      "type": "string",
                      "description": "Mean F0 of the model recording (Hz)."
                    },
                    "USER_F0_MEAN": {
                      "type": "string",
                      "description": "Mean F0 of the learner recording (Hz)."
                    },
                    "MODEL_SPEECH_RATE": {
                      "type": "string",
                      "description": "Speech rate of the model (e.g., syllables/sec)."
                    },
                    "USER_SPEECH_RATE": {
                      "type": "string",
                      "description": "Speech rate of the learner."
                    },
                    "MODEL_DURATION": {
                      "type": "string",
                      "description": "Duration of the model recording (sec)."
                    },
                    "USER_DURATION": {
                      "type": "string",
                      "description": "Duration of the learner recording (sec)."
                    },
                    "CURVE_DATA": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Visualization-ready curves: `{ pitch: [{time, model, user}, …], intensity: [...], rhythm: [...] }`. Each array is sampled at common time points and includes both signals so the UI can overlay them directly."
                    },
                    "VISUALIZATION_METADATA": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: `{ model_duration, user_duration, total_samples, pitch_range: { model_median, user_median } }`."
                    },
                    "ANALYSIS_TYPE": {
                      "type": "string",
                      "description": "String — currently \"Prosody_Similarity_Game\"."
                    },
                    "ALGORITHM_VERSION": {
                      "type": "string",
                      "description": "String — currently \"v01_with_curves\"."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/soundLevel": {
      "post": {
        "operationId": "postSoundLevel",
        "tags": [
          "Audio Measures"
        ],
        "summary": "Measure the sound level (dB SPL) of an audio recording over a specified time window. Useful for environmental noise c…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blobUrl": {
                    "type": "string",
                    "description": "REQUIRED. URL of the audio file (typically obtained via /api/get-blob-url + upload)."
                  },
                  "start_sec": {
                    "type": "number",
                    "description": "REQUIRED. Start of the analysis window in seconds. CAVEAT: The server uses a falsy check (`!start_sec`), so the literal value 0 is rejected — pass a tiny positive value like 0.001 if you mean 'from the beginning'."
                  },
                  "stop_sec": {
                    "type": "number",
                    "description": "REQUIRED. End of the analysis window in seconds. Must be > start_sec."
                  }
                },
                "required": [
                  "blobUrl",
                  "start_sec",
                  "stop_sec"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "soundLevel": {
                      "type": "number",
                      "description": "Number — dB value rounded to 2 decimals."
                    },
                    "unit": {
                      "type": "string",
                      "description": "String — currently \"dB SPL\"."
                    },
                    "frequencyRange": {
                      "type": "number",
                      "description": "String — currently \"20-8000 Hz\"."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/gemaps-extract": {
      "get": {
        "operationId": "getGemapsExtract",
        "tags": [
          "Audio Measures"
        ],
        "summary": "Extract the full openSMILE eGeMAPSv02 feature set (88 features) from a previously uploaded audio file. Files longer t…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "fileId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "REQUIRED. fileId from a prior /api/assignFileId upload."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "<eGeMAPSv02 features>": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "The full eGeMAPSv02 feature object (88 features) as emitted by openSMILE — feature names follow the openSMILE convention (e.g. F0semitoneFrom27.5Hz_sma3nz_amean, loudness_sma3_amean, jitterLocal_sma3nz_amean, shimmerLocaldB_sma3nz_amean, HNRdBACF_sma3nz_amean, F1frequency_sma3nz_amean, etc.). Refer to the openSMILE eGeMAPSv02 configuration for the canonical key list — this server is a transparent wrapper around it."
                    },
                    "chunk_info": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object describing chunking: `{ total_chunks: number, current_chunk: number, start_time: number, duration: number, is_chunked: boolean }`. For files ≤ 8 s, is_chunked is false and the whole file produces one result."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: `{ file_id: string, processing_duration_seconds: number, analysis_type: \"single_chunk\" | \"chunked\" }`."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/analyze-phonemes-live": {
      "post": {
        "operationId": "postAnalyzePhonemesLive",
        "tags": [
          "Phoneme & Classification"
        ],
        "summary": "Run a phoneme-recognition pass on a recording. Provide either a previously-uploaded fileId (preferred for performance…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileId": {
                    "type": "string",
                    "description": "Optional (use this OR blobUrl). fileId from a prior /api/assignFileId upload."
                  },
                  "blobUrl": {
                    "type": "string",
                    "description": "Optional (use this OR fileId). HTTPS URL of the audio file. Will be downloaded server-side. If the host is `vocametrixstorageaccount.blob.core.windows.net` and `keepBlob` is false, the blob is deleted after processing."
                  },
                  "referenceWord": {
                    "type": "string",
                    "description": "Optional. Currently accepted by the API but not used by the JavaScript layer (passed through to the Python script which may use it)."
                  },
                  "language": {
                    "type": "string",
                    "description": "Optional, default \"fr-FR\". Accepted: \"fr-FR\" | \"et-EE\"."
                  },
                  "model": {
                    "type": "string",
                    "description": "Optional. Alias for an alternative ASR model (must pass server-side `isKnownAlias`). Resolved to a model URL internally."
                  },
                  "keepBlob": {
                    "type": "string",
                    "description": "Optional, default false. If false and `blobUrl` was used, the source blob is deleted after success (only when hosted on the Vocametrix storage account)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "<python output>": {
                      "type": "string",
                      "description": "JSON shape produced by the underlying phoneme client. Typical fields: `phonemes: [{ label, start_ms, end_ms, confidence }, ...]`, `language`, `model_used`. Exact shape is not enumerated by the JS layer and is determined by the per-language Python client (see python/phonemes/french/phoneme_client.py and python/phonemes/estonian/phoneme_client.py)."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/classify-stuttering": {
      "post": {
        "operationId": "postClassifyStuttering",
        "tags": [
          "Phoneme & Classification"
        ],
        "summary": "Kick off an asynchronous stuttering classification job on a previously-uploaded recording. Returns a session_id immed…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileId": {
                    "type": "string",
                    "description": "REQUIRED. fileId from a prior /api/assignFileId upload."
                  },
                  "patientId": {
                    "type": "string",
                    "description": "Optional, default \"unknown\". Patient identifier — the literal value \"PT-UNKNOWN\" is explicitly rejected (use \"unknown\" or a real ID)."
                  },
                  "chunkOverlap": {
                    "type": "string",
                    "description": "Optional, default 0.25. Overlap fraction between analysis chunks."
                  },
                  "chunkSize": {
                    "type": "number",
                    "description": "Optional, default 4. Chunk size in seconds."
                  },
                  "locale": {
                    "type": "string",
                    "description": "Optional, default \"en-US\". Locale used by the Azure STT step within the classification pipeline."
                  }
                },
                "required": [
                  "fileId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean — true when the job has been queued."
                    },
                    "session_id": {
                      "type": "string",
                      "description": "String of the form \"cls-<uuid>\". Pass to /api/therapy-status/:sessionId and /api/therapy-result/:sessionId to poll and retrieve."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable confirmation, e.g. \"Classification started. Use session_id to poll for progress.\""
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/classify-estonian-vowel": {
      "post": {
        "operationId": "postClassifyEstonianVowel",
        "tags": [
          "Phoneme & Classification"
        ],
        "summary": "Synchronous Estonian vowel classifier. Submit a fileId, receive the predicted vowel and confidence in the response.",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileId": {
                    "type": "string",
                    "description": "REQUIRED. fileId from a prior /api/assignFileId upload."
                  }
                },
                "required": [
                  "fileId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "<python output>": {
                      "type": "string",
                      "description": "JSON shape produced by python/phonemes/estonian_vowels/estonian_vowel_client.py — typical fields: `success`, `predicted_vowel`, `confidence`, `probabilities: { <vowel>: <prob>, ... }`. The exact key set is determined by the Python client and is not enumerated by the JS layer."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/generate-therapy-plan": {
      "post": {
        "operationId": "postGenerateTherapyPlan",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "Kick off therapy plan generation from an uploaded audio recording. Returns immediately (202) with a therapy_session_i…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileId": {
                    "type": "string",
                    "description": "REQUIRED. fileId from a prior /api/assignFileId upload."
                  },
                  "patientId": {
                    "type": "string",
                    "description": "REQUIRED. Patient identifier matching ^[a-zA-Z0-9_-]{1,100}$. The literal \"PT-UNKNOWN\" is explicitly rejected."
                  },
                  "patientMetadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional. Object describing the patient. Max 10,000 bytes when JSON-serialized. Optional sub-fields: demographics.age (0–120), clinical_history.severity (\"Mild\"|\"Moderate\"|\"Severe\"|\"Very Severe\"), current_goals (max 20 entries), recent_progress_notes (max 50), previous_exercises (max 30)."
                  },
                  "maxIterations": {
                    "type": "integer",
                    "description": "Optional integer 1–5, default 2. Max critic-agent iterations within the workflow."
                  },
                  "therapyAgentTemperature": {
                    "type": "number",
                    "description": "Optional number, default 0.3. Generation temperature for the therapy-planner LLM."
                  },
                  "criticAgentTemperature": {
                    "type": "number",
                    "description": "Optional number, default 0. Generation temperature for the critic LLM."
                  },
                  "classificationSessionId": {
                    "type": "string",
                    "description": "Optional string. If present, links the new therapy session to a prior /api/classify-stuttering session so the workflow can use those classification results."
                  },
                  "useAzureML": {
                    "type": "boolean",
                    "description": "Optional boolean, default true. Whether to use Azure ML inside the workflow."
                  }
                },
                "required": [
                  "fileId",
                  "patientId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean — true when the job has been queued."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message."
                    },
                    "therapy_session_id": {
                      "type": "string",
                      "description": "Session ID of the form \"THERAPY-<patientId>-<uuid>\"."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"pending\" — the initial state."
                    },
                    "status_url": {
                      "type": "string",
                      "description": "Convenience URL to poll status (/api/therapy-status/<id>)."
                    },
                    "result_url": {
                      "type": "string",
                      "description": "Convenience URL to fetch result once complete (/api/therapy-result/<id>)."
                    },
                    "estimated_time_seconds": {
                      "type": "string",
                      "description": "Approximate wall-clock estimate (e.g., 120 s)."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-status/{sessionId}": {
      "get": {
        "operationId": "getTherapyStatusBySessionId",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "Poll the status of a therapy (or stuttering-classification) session. Returns 404 if the session is unknown or has exp…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — the session ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "session_id": {
                      "type": "string",
                      "description": "String — may be normalized from the input (the server does flexible lookup)."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"pending\" | \"processing\" | \"complete\" | \"pending_approval\" | \"failed\"."
                    },
                    "progress_percent": {
                      "type": "number",
                      "description": "Number 0–100."
                    },
                    "progress": {
                      "type": "number",
                      "description": "Number — alias for progress_percent (kept for back-compat)."
                    },
                    "status_message": {
                      "type": "string",
                      "description": "Free-form progress description."
                    },
                    "error_message": {
                      "type": "string",
                      "description": "String, or null."
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp."
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp."
                    },
                    "completed_at": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp, or null until complete."
                    },
                    "result_available": {
                      "type": "boolean",
                      "description": "Boolean — true when status is \"complete\" or \"pending_approval\"."
                    },
                    "approval_required": {
                      "type": "boolean",
                      "description": "Boolean — true when status is \"pending_approval\"."
                    },
                    "generated_prompts": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Array, or null. Workflow-internal prompts (mostly for debugging)."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 server time."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-result/{sessionId}": {
      "get": {
        "operationId": "getTherapyResultBySessionId",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "Fetch the final result of a therapy or classification session. Returns 400 \"Result not ready\" if status is not \"compl…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — the session ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "<therapy session>": {
                      "type": "string",
                      "description": "{ success, message, nodejs_session_id, ...result } — `result` is whatever the LangGraph workflow saved. Typical fields include `therapySession.sessionMetadata`, exercise plans, generated HTML paths (`html_clinician_final`, `output_file`), and free-form workflow output. The full keyset is determined by the Python workflow, not the JS layer."
                    },
                    "<classification session>": {
                      "type": "string",
                      "description": "{ success, session_id, patient_id, classification, classificationMetadata, overallClassification, timestamp } — see /api/classify-stuttering documentation."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-approve/{sessionId}": {
      "post": {
        "operationId": "postTherapyApproveBySessionId",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "Approve, modify, or reject a generated therapy plan. The action determines the next step: \"approve\" locks the plan as…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — the session ID. Status must be \"complete\" or \"pending_approval\".",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "action": {
                    "type": "string",
                    "description": "REQUIRED in body. \"approve\" | \"modify\" | \"reject\" (case-insensitive)."
                  },
                  "feedback": {
                    "type": "string",
                    "description": "REQUIRED when action=\"modify\". Free-form clinician notes describing what to change. Optional otherwise."
                  }
                },
                "required": [
                  "action"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "therapy_session_id": {
                      "type": "string",
                      "description": "Echo of the session ID."
                    },
                    "action": {
                      "type": "string",
                      "description": "Echo of the action."
                    },
                    "feedback": {
                      "type": "string",
                      "description": "Echo of the feedback (or null)."
                    },
                    "delivery_status": {
                      "type": "string",
                      "description": "On approve: \"approved_pending_delivery\". On reject: \"rejected\"."
                    },
                    "status": {
                      "type": "string",
                      "description": "On modify: \"processing\" — the workflow re-runs and the client must poll again."
                    },
                    "status_message": {
                      "type": "string",
                      "description": "Human-readable description."
                    },
                    "status_url": {
                      "type": "string",
                      "description": "(modify only) URL to poll the new run."
                    },
                    "result_url": {
                      "type": "string",
                      "description": "(modify only) URL to fetch the new result."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable confirmation."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-plan-html/{sessionId}": {
      "get": {
        "operationId": "getTherapyPlanHtmlBySessionId",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "Download the clinician-facing HTML version of the generated therapy plan. Returns text/html with Content-Disposition:…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — the session ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-revise/{sessionId}": {
      "post": {
        "operationId": "postTherapyReviseBySessionId",
        "tags": [
          "Therapy Planning"
        ],
        "summary": "DEPRECATED. Always returns 410 Gone. Migrate to POST /api/therapy-approve/:sessionId with action=\"modify\" + feedback.…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "deprecated": true,
        "parameters": [
          {
            "name": "sessionId",
            "in": "path",
            "required": true,
            "description": "Path parameter — the session ID.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "feedback": {
                    "type": "string",
                    "description": "Body — required for the deprecation handler to confirm intent (returns 400 if missing)."
                  },
                  "maxIterations": {
                    "type": "integer",
                    "description": "Body, optional. Accepted but unused."
                  }
                },
                "required": [
                  "feedback"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Always false."
                    },
                    "error": {
                      "type": "string",
                      "description": "\"Endpoint deprecated\"."
                    },
                    "recommended_endpoint": {
                      "type": "string",
                      "description": "\"POST /api/therapy-approve/:sessionId\"."
                    },
                    "recommended_payload": {
                      "type": "string",
                      "description": "{ action: \"modify\", feedback }."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/speech-exercise-generator": {
      "post": {
        "operationId": "postSpeechExerciseGenerator",
        "tags": [
          "AI Agents"
        ],
        "summary": "Generate personalized speech therapy exercises. The agent returns a single conversational reply containing the exerci…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "REQUIRED. Instructions or context for the exercise generation (e.g., \"Generate 5 articulation exercises for /r/\")."
                  },
                  "ageLevel": {
                    "type": "string",
                    "description": "Patient age range (e.g., \"3-6 years\", \"7-12 years\", \"adults\")"
                  },
                  "speechChallenge": {
                    "type": "string",
                    "description": "The specific speech challenge to address (e.g., \"R sounds\", \"S sounds\")"
                  },
                  "language": {
                    "type": "string",
                    "description": "Target language for exercises (English, French, Spanish)"
                  }
                },
                "required": [
                  "message",
                  "ageLevel",
                  "speechChallenge",
                  "language"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "description": "The agent reply containing the generated exercises as structured text"
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Conversation thread ID — pass it back to continue the same session"
                    },
                    "agentName": {
                      "type": "string",
                      "description": "Identifier of the agent that produced the reply"
                    },
                    "runStatus": {
                      "type": "string",
                      "description": "Internal run state (e.g., \"completed\")"
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number of API credits remaining in your account"
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean — true if the call used an anonymous_<sessionId> key"
                    },
                    "parameters": {
                      "type": "string",
                      "description": "Echo of the parameters used to produce the reply (ageLevel, speechChallenge, language)"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/word-list-generator": {
      "post": {
        "operationId": "postWordListGenerator",
        "tags": [
          "AI Agents"
        ],
        "summary": "Generate word lists tailored to specific phonemes with helpful hints",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "language": {
                    "type": "string",
                    "description": "Target language for words (english, french, spanish, german)"
                  },
                  "age": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 120,
                    "description": "Patient age range (e.g., \"3-6 years\", \"7-12 years\", \"adults\")"
                  },
                  "selectedSound": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Object containing symbol (IPA phoneme) and position (beginning/middle/end/random)"
                  }
                },
                "required": [
                  "language",
                  "age",
                  "selectedSound"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "words": {
                      "type": "string",
                      "description": "String containing 20 words separated by semicolons"
                    },
                    "hints": {
                      "type": "string",
                      "description": "String containing 20 corresponding hints separated by semicolons"
                    },
                    "wordHintPairs": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Array of objects with word and hint properties"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/spell-agent": {
      "post": {
        "operationId": "postSpellAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Interpret raw speech-to-text transcriptions of spelling attempts and provide intelligent feedback",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The speech-to-text transcription of user's spoken spelling attempt"
                  },
                  "word": {
                    "type": "string",
                    "description": "The target word to compare against (with proper accents if applicable)"
                  },
                  "language": {
                    "type": "string",
                    "description": "Language code (e.g., \"en-US\", \"fr-FR\", \"es-ES\") for language-appropriate feedback"
                  }
                },
                "required": [
                  "text",
                  "word",
                  "language"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "string",
                      "description": "Spelled word in uppercase with any recognized accents"
                    },
                    "match": {
                      "type": "boolean",
                      "description": "Boolean indicating whether the spelling matches the target word"
                    },
                    "explanation": {
                      "type": "string",
                      "description": "Detailed explanation in the target language providing educational feedback"
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number of remaining API credits"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/speech-therapist-assistant": {
      "post": {
        "operationId": "postSpeechTherapistAssistant",
        "tags": [
          "AI Agents"
        ],
        "summary": "Expert speech therapy assistant providing role-based guidance for therapists, patients, and caregivers. Text-only — f…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "input": {
                    "type": "string",
                    "description": "The user's query or question about speech therapy"
                  },
                  "accountType": {
                    "type": "string",
                    "description": "User role: \"slt\" (therapist), \"patient\", or \"parent\" for role-based responses"
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Conversation thread ID for maintaining context between messages"
                  }
                },
                "required": [
                  "input",
                  "accountType",
                  "threadId"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "description": "The AI assistant's detailed answer with evidence-based recommendations and resources"
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Conversation thread ID for continuing the conversation"
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number of API credits remaining in your account"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/language-chat-vocabulary": {
      "post": {
        "operationId": "postLanguageChatVocabulary",
        "tags": [
          "AI Agents"
        ],
        "summary": "Interactive conversational AI that helps users practice language skills with real-time vocabulary enhancement",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "REQUIRED. The user's message in their target language"
                  },
                  "language": {
                    "type": "string",
                    "description": "REQUIRED. Target language the user is learning (en-US, fr-FR, es-ES, de-DE, etc.)"
                  },
                  "nativeLanguage": {
                    "type": "string",
                    "description": "REQUIRED. The user's native language code — used to localize vocabulary hints and corrections"
                  },
                  "ageLevel": {
                    "type": "string",
                    "description": "Age/level (child-beginner, teen-intermediate, adult-advanced, etc.)"
                  },
                  "topic": {
                    "type": "string",
                    "description": "Conversation topic (family, travel, food, work, hobbies, etc.)"
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional thread ID to continue previous conversation"
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional user email for tracking"
                  }
                },
                "required": [
                  "message",
                  "language",
                  "nativeLanguage",
                  "ageLevel",
                  "topic"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "description": "The AI assistant's conversational reply with vocabulary enhancements"
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Thread ID for continuing the conversation"
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number of API credits remaining in your account"
                    },
                    "configuration": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object containing the current language, age level, and topic"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/voice-metrics-interpreter": {
      "post": {
        "operationId": "postVoiceMetricsInterpreter",
        "tags": [
          "AI Agents"
        ],
        "summary": "Translate raw voice metrics (jitter, shimmer, HNR, CPPS, etc.) into a clinical-language interpretation with severity,…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "metrics": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "REQUIRED. Object of voice metrics — typical keys: jitter, shimmer, hnr, cpps, etc. (validated server-side)."
                  },
                  "age": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 120,
                    "description": "REQUIRED. Patient age in years (1–120)."
                  },
                  "gender": {
                    "type": "string",
                    "description": "REQUIRED. \"male\" | \"female\" | \"other\"."
                  },
                  "languageCode": {
                    "type": "string",
                    "description": "Optional. Output language code — server applies a default via validateLanguageCode if omitted."
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional. Azure AI Foundry thread ID for multi-turn continuity."
                  },
                  "praatResults": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional. Full Praat output object — when present, the server merges F0 / expected-range fields into the metrics for richer interpretation."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  }
                },
                "required": [
                  "metrics",
                  "age",
                  "gender"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "overallScore": {
                      "type": "number",
                      "description": "Number 0–100, or -1 if the agent's response could not be parsed."
                    },
                    "pathologyLevel": {
                      "type": "string",
                      "description": "Categorical string describing pathology severity."
                    },
                    "problematicMetrics": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Array of metric names flagged as problematic."
                    },
                    "interpretation": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { summary, overallAssessment, metrics: [...], additionalNotes: [...], recommendedActions: [{category, recommendation}], riskLevel, nextSteps }."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { languageCode, age, gender, metricsProcessed, threadId, agentName, processingTimeSeconds, timestamp, genderValidation: {detectedF0, expectedRange, f0Validity, note} | null }."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean — true if the call used an anonymous_<sessionId> key."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/syntax-checker-agent": {
      "post": {
        "operationId": "postSyntaxCheckerAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Linguistic syntax/grammar checker. Returns a structured analysis with overall score, per-issue breakdown by severity …",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "REQUIRED. Text to analyze (≤ 5000 characters)."
                  },
                  "locale": {
                    "type": "string",
                    "description": "REQUIRED. Language code (validated via validateLanguageCode)."
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional. Thread ID for multi-turn continuity."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  }
                },
                "required": [
                  "text",
                  "locale"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "analysis": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { overall_score, language_detected, text_length, analysis_timestamp, issues: [...], suggestions: [{category, type, description, examples}], statistics: {total_issues, by_severity: {high, medium, low}, by_type: {grammar, spelling, punctuation, style, clarity}}, corrected_text, readability: {grade_level, reading_ease, avg_sentence_length} }."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { locale, textLength, threadId, agentName, processingTimeSeconds, timestamp }."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/vocabulary-tutor-agent": {
      "post": {
        "operationId": "postVocabularyTutorAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Conversational language-tutor agent that adapts vocabulary to the learner's native language, target language, age gro…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "REQUIRED. The learner's message in the target language."
                  },
                  "nativeLanguage": {
                    "type": "string",
                    "description": "REQUIRED. The learner's native language code."
                  },
                  "targetLanguage": {
                    "type": "string",
                    "description": "REQUIRED. The language the learner is studying."
                  },
                  "ageGroup": {
                    "type": "string",
                    "description": "REQUIRED. Categorical age group label."
                  },
                  "topic": {
                    "type": "string",
                    "description": "REQUIRED. Conversation topic."
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional. Thread ID for multi-turn continuity."
                  }
                },
                "required": [
                  "message",
                  "nativeLanguage",
                  "targetLanguage",
                  "ageGroup",
                  "topic"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "response": {
                      "type": "string",
                      "description": "String — the agent's free-form text reply."
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Thread ID for the conversation (use to continue)."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { nativeLanguage, targetLanguage, ageGroup, topic, runId, runStatus }."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/adaptive-exercise-agent": {
      "post": {
        "operationId": "postAdaptiveExerciseAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Adapts a speech-therapy exercise to a learner profile (ADHD, dyslexia, dysgraphia, dyspraxia, Tourette syndrome, auti…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "exerciseText": {
                    "type": "string",
                    "description": "REQUIRED. The original exercise text."
                  },
                  "profile": {
                    "type": "string",
                    "description": "REQUIRED. One of \"adhd\" | \"dyslexia\" | \"dysgraphia\" | \"dyspraxia\" | \"tourette\" | \"autism\" (case-insensitive). Other values return 400 with a `validProfiles` field."
                  },
                  "includeTips": {
                    "type": "string",
                    "description": "Optional, default false. If true, the agent includes practitioner tips alongside the adapted exercise."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  }
                },
                "required": [
                  "exerciseText",
                  "profile"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "adaptedHTML": {
                      "type": "string",
                      "description": "String — HTML version of the exercise adapted for the chosen profile."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { profile, includeTips, threadId, agentName, processingTimeSeconds, timestamp }."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/french-to-ipa-agent": {
      "post": {
        "operationId": "postFrenchToIpaAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Convert French words to IPA (International Phonetic Alphabet) transcription. Accepts either a single word string or a…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "phoneticInput": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "REQUIRED. Either a single French word as a string, OR a JSON-stringified array of up to 20 strings. The server detects which by attempting JSON.parse."
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional. Thread ID for multi-turn continuity."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  }
                },
                "required": [
                  "phoneticInput"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "result": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object OR array of objects, mirroring the input shape. Each entry has the form { word, ipa: [...], ... }. The server checks `result.ipa.length` to count transcriptions; the rest of the shape is determined by the agent."
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Thread ID."
                    },
                    "agentName": {
                      "type": "string",
                      "description": "Agent identifier."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/therapy-planning-agent": {
      "post": {
        "operationId": "postTherapyPlanningAgent",
        "tags": [
          "AI Agents"
        ],
        "summary": "Single-shot Azure AI Foundry agent that generates a therapy recommendation from session metadata + wav2vec output. NO…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "session_metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "REQUIRED. Object — must include `patient_id` (string). May also include `session_id`, `timestamp`, `audio_file`."
                  },
                  "wav2vec_output": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "REQUIRED. Object — must include `summary_statistics` (typically `{disfluency_types_detected, overall_fluency_rate, total_segments, ...}`)."
                  },
                  "patient_anamnesis": {
                    "type": "string",
                    "description": "Optional. Patient context — `demographics: {age}`, `clinical_history: {diagnosis, severity}`, `therapy_information: {current_treatment_approach, total_sessions_completed}`, etc."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  }
                },
                "required": [
                  "session_metadata",
                  "wav2vec_output"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Azure AI Foundry thread ID (always a new thread for this endpoint)."
                    },
                    "runId": {
                      "type": "string",
                      "description": "Run ID."
                    },
                    "agentName": {
                      "type": "string",
                      "description": "Agent identifier."
                    },
                    "status": {
                      "type": "string",
                      "description": "Run status string."
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time",
                      "description": "ISO 8601 timestamp."
                    },
                    "recommendation": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object — preferred shape contains `primary_recommendation` and related structured fields when the agent's JSON parses successfully. Fallback shape on parse failure: { raw_response, structured_content: bool, analysis_summary }."
                    },
                    "allMessages": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Array — full thread message history."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object: { patient_id, session_id, processing_time_seconds, disfluency_types, fluency_rate, total_segments_analyzed, response_metadata: {responseLength, containsStructuredData, parseSuccess} }."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    },
    "/api/language-chat-pronunciation": {
      "post": {
        "operationId": "postLanguageChatPronunciation",
        "tags": [
          "AI Agents"
        ],
        "summary": "Conversational language-coach agent specialized in pronunciation feedback. Similar to /api/language-chat-vocabulary b…",
        "security": [
          {
            "apiKeyHeader": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "REQUIRED. The learner's message in the target language."
                  },
                  "language": {
                    "type": "string",
                    "description": "REQUIRED. Target language being learned."
                  },
                  "ageLevel": {
                    "type": "string",
                    "description": "REQUIRED. Categorical age/level label."
                  },
                  "topic": {
                    "type": "string",
                    "description": "REQUIRED. Conversation topic."
                  },
                  "nativeLanguage": {
                    "type": "string",
                    "description": "Optional. The learner's native language code."
                  },
                  "threadId": {
                    "type": "string",
                    "description": "Optional. Thread ID for multi-turn continuity."
                  },
                  "email": {
                    "type": "string",
                    "description": "Optional. Used by anonymous-key validation flow."
                  },
                  "assessmentHistory": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "Optional. Array or object of prior pronunciation-assessment results to feed into the coach for grounded feedback."
                  }
                },
                "required": [
                  "message",
                  "language",
                  "ageLevel",
                  "topic"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "description": "String — the coach's text reply."
                    },
                    "threadId": {
                      "type": "string",
                      "description": "Thread ID."
                    },
                    "runStatus": {
                      "type": "string",
                      "description": "Run status string."
                    },
                    "remaining_credits": {
                      "type": "number",
                      "description": "Number."
                    },
                    "isAnonymousSession": {
                      "type": "boolean",
                      "description": "Boolean."
                    },
                    "configuration": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Object — passthrough of resolved language, nativeLanguage, ageLevel, topic."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request — missing or invalid parameter"
          },
          "401": {
            "description": "Unauthorized — missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          },
          "500": {
            "description": "Server error"
          }
        }
      }
    }
  }
}