{
  "openapi": "3.1.0",
  "info": {
    "title": "Munsit API",
    "description": "Munsit - First True Arabic Voice AI that speaks Dialects From Abu Dhabi to Rabat with Voice Cloning & On-prem support",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.munsit.com/api/v1",
      "description": "Global production server"
    },
    {
      "url": "https://ae.api.faseeh.ai/api/v1",
      "description": "UAE regional server"
    }
  ],
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/models": {
      "get": {
        "summary": "Get Models",
        "description": "Retrieve a list of all available voice synthesis models",
        "operationId": "getModels",
        "tags": [
          "Models"
        ],
        "responses": {
          "200": {
            "description": "List of available models",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Model"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests - Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/voices": {
      "get": {
        "summary": "Get Voices",
        "description": "Retrieve a list of all available voices for text-to-speech synthesis",
        "operationId": "getVoices",
        "tags": [
          "Voices"
        ],
        "responses": {
          "200": {
            "description": "List of available voices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Voice"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests - Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/text-to-speech/{model_id}": {
      "post": {
        "summary": "Generate Text-to-Speech",
        "description": "Generate speech from Arabic text using a specific model. Supports both streaming and non-streaming responses.",
        "operationId": "generateTextToSpeech",
        "tags": [
          "Text-to-Speech"
        ],
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "description": "The model identifier to use for generation",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TextToSpeechRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Audio response (streaming or complete file)",
            "content": {
              "audio/raw": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "PCM16 audio stream (when streaming=true)"
                }
              },
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "WAV audio file (when streaming=false)"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required - Insufficient wallet balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not Found - Model not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests - Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/websocket/text-to-speech": {
      "get": {
        "summary": "WebSocket Text-to-Speech",
        "description": "WebSocket endpoint for streaming text-to-speech generation...",
        "x-badge": {
          "text": "WSS",
          "variant": "success"
        },
        "operationId": "websocketTextToSpeech"
      }
    },
    "/denoise": {
      "post": {
        "summary": "Submit Denoise Job",
        "description": "Queue an audio or video file for voice isolation. The original is uploaded and a background job is enqueued; the response returns identifiers used to track progress via the SSE endpoint.",
        "operationId": "denoiseAudio",
        "tags": [
          "Voice Isolation"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "audio"
                ],
                "properties": {
                  "audio": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio or video file to denoise (max 200 MB, max 15 minutes duration). Video containers (mp4, mov, mkv, webm, avi, m4v) have their audio track extracted automatically."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Denoising job queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "jobId",
                    "denoiseId"
                  ],
                  "properties": {
                    "jobId": {
                      "type": "string",
                      "description": "Background job identifier (mirrors denoiseId)."
                    },
                    "denoiseId": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Unique identifier of the denoising record. Use this with /denoise/{denoiseId}/progress and as the record id in /denoise."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - File size exceeds 200 MB or duration exceeds 15 minutes",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required - Insufficient wallet balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests - Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List Denoise History",
        "description": "Return the authenticated user's denoising records ordered by most recently created first. Use this to retrieve the final URL of completed jobs or paginate through history.",
        "operationId": "listDenoiseJobs",
        "tags": [
          "Voice Isolation"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of records to skip from the start of the result set."
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Maximum number of records to return. Omit to return all records."
          }
        ],
        "responses": {
          "200": {
            "description": "List of denoising records",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DenoiseRecord"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - invalid offset or limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/denoise/{denoiseId}/progress": {
      "get": {
        "summary": "Stream Denoise Progress",
        "description": "Subscribe to live progress events for a denoising job over Server-Sent Events (SSE). Emits processing updates and terminates with either a done event (carrying the final audio URL) or an error event. If the job is already complete the cached terminal event is replayed immediately.",
        "operationId": "denoiseProgress",
        "tags": [
          "Voice Isolation"
        ],
        "x-badge": {
          "text": "SSE",
          "variant": "success"
        },
        "parameters": [
          {
            "in": "path",
            "name": "denoiseId",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The denoiseId returned by POST /denoise."
          }
        ],
        "responses": {
          "200": {
            "description": "SSE stream of denoising events. Each message is a `data: <json>` line where the JSON conforms to DenoiseProgressEvent.",
            "content": {
              "text/event-stream": {
                "schema": {
                  "$ref": "#/components/schemas/DenoiseProgressEvent"
                }
              }
            }
          },
          "404": {
            "description": "Denoising job not found. NOTE: this endpoint returns {message} rather than the standard {errorCode, errorMessage} error envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Denoising job not found"
                    }
                  },
                  "required": [
                    "message"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/voices/preview": {
      "post": {
        "summary": "Voice Preview",
        "description": "Generate a preview of a voice you want to clone. This API allows you to test how a voice will sound before creating it as a permanent voice.",
        "operationId": "voicePreview",
        "tags": [
          "Voice Cloning"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "text",
                  "similarity",
                  "model_id",
                  "file"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Text to generate preview with (minimum 3 words, 10 characters)"
                  },
                  "similarity": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Voice similarity to source (0.0 to 1.0). Higher values produce more similar voice"
                  },
                  "model_id": {
                    "type": "string",
                    "description": "The model identifier to use for generation"
                  },
                  "speed": {
                    "type": "number",
                    "minimum": 0.7,
                    "maximum": 1.2,
                    "default": 1.0,
                    "description": "Speech speed (0.7 to 1.2, default 1.0)"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file containing the voice to preview"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Streaming PCM16 audio preview",
            "content": {
              "audio/raw": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "PCM16 audio stream (24000 Hz, Mono, 16-bit)"
                }
              }
            },
            "headers": {
              "Content-Type": {
                "schema": {
                  "type": "string",
                  "example": "audio/raw;codec=pcm16;rate=24000;channels=1"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required - Insufficient wallet balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - Failed to generate voice preview",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/voices/clone": {
      "post": {
        "summary": "Voice Clone",
        "description": "Create a cloned voice from an audio file. This endpoint allows you to create a new voice by providing a voice sample and reference audio.",
        "operationId": "cloneVoice",
        "tags": [
          "Voice Cloning"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "voice_file",
                  "reference_audio_file",
                  "text",
                  "stability",
                  "name",
                  "model"
                ],
                "properties": {
                  "voice_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The generated preview audio file from the preview API"
                  },
                  "reference_audio_file": {
                    "type": "string",
                    "format": "binary",
                    "description": "The original audio file used for the preview"
                  },
                  "text": {
                    "type": "string",
                    "description": "The text used in preview generation"
                  },
                  "stability": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Voice stability (0.0 to 1.0). Higher values produce more consistent output"
                  },
                  "name": {
                    "type": "string",
                    "description": "Name for the cloned voice"
                  },
                  "model": {
                    "type": "string",
                    "description": "Model identifier to use for voice cloning"
                  },
                  "description": {
                    "type": "string",
                    "description": "Description of the voice"
                  },
                  "gender": {
                    "type": "string",
                    "description": "Gender of the voice (e.g., 'male', 'female')"
                  },
                  "age": {
                    "type": "string",
                    "description": "Age category of the voice (e.g., 'middle', 'elderly')"
                  },
                  "languages": {
                    "type": "string",
                    "description": "Comma-separated list of language codes (e.g., 'ar,en')"
                  },
                  "dialects": {
                    "type": "string",
                    "description": "Comma-separated list of dialects (e.g., 'najdi,hijazi')"
                  },
                  "avatar_url": {
                    "type": "string",
                    "description": "URL to an avatar image for the voice (you can put your image URL here)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Voice created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClonedVoice"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - Failed to create voice",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/audio/transcribe": {
      "post": {
        "summary": "Transcribe Audio",
        "description": "Upload a pre-recorded audio file and receive Arabic transcription with timestamps.",
        "operationId": "transcribeAudio",
        "tags": [
          "Speech-to-Text"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file to transcribe"
                  },
                  "model": {
                    "type": "string",
                    "enum": [
                      "munsit",
                      "munsit-en-ar"
                    ],
                    "default": "munsit",
                    "description": "ASR model to use. Defaults to munsit."
                  },
                  "hotwords": {
                    "type": "string",
                    "description": "Comma-separated custom vocabulary (multi-word phrases allowed). Biases recognition toward rare terms; best with 5-30 genuinely rare entries. Not supported with model munsit-en-ar."
                  },
                  "return_confidence": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, each timestamps entry includes a confidence score (0-1). The response shape is otherwise unchanged."
                  },
                  "return_turns": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, adds a turns array with a per-turn breakdown (each turn is one VAD segment), tagged with smart-turn is_complete and turn_probability."
                  },
                  "return_gender": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, adds per-turn speaker gender (audio-based) to turns plus a whole-file gender rollup under analysis."
                  },
                  "return_sentiment": {
                    "type": "boolean",
                    "default": false,
                    "description": "When true, adds per-turn sentiment (fast text-based classification per utterance) to turns plus a whole-file sentiment rollup under analysis."
                  },
                  "return_timestamps": {
                    "type": "boolean",
                    "description": "Defaults to true on munsit (false returns an empty timestamps array). On munsit-en-ar timestamps are off unless set to true."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Transcription created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "transcriptionId": {
                          "type": "string",
                          "format": "uuid",
                          "description": "Transcription identifier (UUID). Path parameter for sentiment analysis and keyword extraction."
                        },
                        "transcription": {
                          "type": "string"
                        },
                        "summary": {
                          "type": "string",
                          "description": "Always present. Empty string on plain transcription."
                        },
                        "duration": {
                          "type": "number",
                          "description": "Audio duration in seconds"
                        },
                        "timestamps": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "word": {
                                "type": "string"
                              },
                              "start": {
                                "type": "number"
                              },
                              "end": {
                                "type": "number"
                              },
                              "confidence": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1,
                                "description": "Present only when return_confidence=true"
                              }
                            },
                            "required": [
                              "word",
                              "start",
                              "end"
                            ]
                          }
                        },
                        "turns": {
                          "type": "array",
                          "description": "Per-turn breakdown. Present when any of return_turns, return_gender or return_sentiment is true — the gender and sentiment flags imply it. Short single-speaker recordings typically yield a single turn.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "turn_id": {
                                "type": "number"
                              },
                              "start": {
                                "type": "number"
                              },
                              "end": {
                                "type": "number"
                              },
                              "text": {
                                "type": "string"
                              },
                              "is_complete": {
                                "type": "boolean",
                                "description": "Smart-turn detector verdict. Present only when return_turns=true."
                              },
                              "turn_probability": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1,
                                "description": "Smart-turn confidence 0-1. Present only when return_turns=true."
                              },
                              "gender": {
                                "type": "object",
                                "description": "Present only when return_gender=true.",
                                "properties": {
                                  "label": {
                                    "type": "string"
                                  },
                                  "score": {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 1
                                  }
                                }
                              },
                              "sentiment": {
                                "type": "object",
                                "description": "Present only when return_sentiment=true.",
                                "properties": {
                                  "label": {
                                    "type": "string"
                                  },
                                  "score": {
                                    "type": "number",
                                    "minimum": 0,
                                    "maximum": 1
                                  }
                                }
                              }
                            },
                            "required": [
                              "turn_id",
                              "start",
                              "end",
                              "text"
                            ]
                          }
                        },
                        "analysis": {
                          "type": "object",
                          "description": "Whole-file rollup. Present only when return_gender or return_sentiment is true — return_turns alone does not produce it.",
                          "properties": {
                            "turns": {
                              "type": "integer",
                              "description": "Total number of turns."
                            },
                            "gender": {
                              "type": "object",
                              "description": "Whole-file rollup. Present only when return_gender=true.",
                              "properties": {
                                "dominant": {
                                  "type": "string"
                                },
                                "by_duration_s": {
                                  "type": "object",
                                  "additionalProperties": {
                                    "type": "number"
                                  },
                                  "description": "Total speaking duration in seconds, keyed by gender label."
                                }
                              }
                            },
                            "sentiment": {
                              "type": "object",
                              "description": "Whole-file rollup. Present only when return_sentiment=true.",
                              "properties": {
                                "dominant": {
                                  "type": "string"
                                },
                                "counts": {
                                  "type": "object",
                                  "additionalProperties": {
                                    "type": "integer"
                                  },
                                  "description": "Turn count, keyed by sentiment label."
                                }
                              }
                            }
                          }
                        },
                        "attributes": {
                          "type": "object",
                          "description": "Internal metadata blob persisted with the transcription; repeats timestamps and mirrors turns/analysis under other names. Unstable — prefer the named fields."
                        },
                        "audioUrl": {
                          "type": "string",
                          "description": "URL of the stored copy of the uploaded audio. Its exact form is not part of the API contract and may change; do not hard-code or parse it."
                        },
                        "stats": {
                          "$ref": "#/components/schemas/SttStats"
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request — validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized — invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/minutes-of-meeting/transcribe": {
      "post": {
        "summary": "Transcribe Minutes of Meeting",
        "description": "Upload meeting audio and receive structured transcription output.",
        "operationId": "transcribeMinutesOfMeeting",
        "tags": [
          "Speech-to-Text"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Meeting audio file"
                  },
                  "model": {
                    "type": "string",
                    "enum": [
                      "munsit",
                      "munsit-en-ar"
                    ],
                    "default": "munsit",
                    "description": "ASR model to use. Defaults to munsit."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Meeting transcription created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "statusCode",
                    "data",
                    "message"
                  ],
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "transcriptionId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "transcription": {
                          "type": "string",
                          "description": "Meeting summary text."
                        },
                        "originalTranscript": {
                          "type": "string",
                          "description": "Raw verbatim transcript."
                        },
                        "summary": {
                          "type": "string"
                        },
                        "attributes": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "duration": {
                          "type": "number",
                          "description": "Audio duration in seconds"
                        },
                        "timestamps": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "word": {
                                "type": "string"
                              },
                              "start": {
                                "type": "number"
                              },
                              "end": {
                                "type": "number"
                              },
                              "confidence": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1,
                                "description": "Present only when return_confidence=true"
                              }
                            },
                            "required": [
                              "word",
                              "start",
                              "end"
                            ]
                          },
                          "description": "Word-level timestamps. Omitted when the minutes engine returns none."
                        },
                        "audioUrl": {
                          "type": "string"
                        },
                        "stats": {
                          "$ref": "#/components/schemas/SttStats"
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/audio/diarization/transcribe": {
      "post": {
        "summary": "Transcribe with Diarization",
        "description": "Upload audio and receive diarization segments merged with transcription.",
        "operationId": "transcribeWithDiarization",
        "tags": [
          "Speech-to-Text"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "Audio file for diarization + transcription"
                  },
                  "model": {
                    "type": "string",
                    "enum": [
                      "munsit",
                      "munsit-en-ar"
                    ],
                    "default": "munsit",
                    "description": "ASR model to use. Defaults to munsit."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diarization transcription created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "statusCode",
                    "data",
                    "message"
                  ],
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "transcriptionId": {
                          "type": "string",
                          "format": "uuid"
                        },
                        "transcription": {
                          "type": "string"
                        },
                        "originalTranscript": {
                          "type": "string"
                        },
                        "attributes": {
                          "type": [
                            "object",
                            "null"
                          ]
                        },
                        "diarization": {
                          "type": "object",
                          "description": "Raw speaker-diarization output from the model."
                        },
                        "merged": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "speaker": {
                                "type": "string"
                              },
                              "start": {
                                "type": "number"
                              },
                              "end": {
                                "type": "number"
                              },
                              "text": {
                                "type": "string"
                              }
                            }
                          },
                          "description": "Transcript segments merged with speaker labels."
                        },
                        "duration": {
                          "type": "number"
                        },
                        "audioUrl": {
                          "type": "string"
                        },
                        "stats": {
                          "$ref": "#/components/schemas/SttStats"
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/audio/{transcriptionId}/sentiment-analysis": {
      "post": {
        "summary": "Sentiment Analysis (Audio)",
        "description": "Generate sentiment analysis from an audio transcription ID.",
        "operationId": "audioSentimentAnalysis",
        "tags": [
          "Speech-to-Text"
        ],
        "parameters": [
          {
            "name": "transcriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Transcription ID"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "analysis_depth": {
                    "type": "string",
                    "enum": [
                      "light",
                      "standard",
                      "deep"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sentiment analysis generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "statusCode",
                    "data",
                    "message"
                  ],
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Structured analysis result. Shape varies with the requested depth; empty object when the model returns nothing."
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/minutes-of-meeting/{transcriptionId}/keyword-extraction": {
      "post": {
        "summary": "Keyword Extraction",
        "description": "Extract keywords and topic insights from a meeting transcription.",
        "operationId": "keywordExtraction",
        "tags": [
          "Speech-to-Text"
        ],
        "parameters": [
          {
            "name": "transcriptionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Meeting transcription ID"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "extraction_depth": {
                    "type": "string",
                    "enum": [
                      "basic",
                      "standard",
                      "comprehensive"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Keyword extraction generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "statusCode",
                    "data",
                    "message"
                  ],
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Structured analysis result. Shape varies with the requested depth; empty object when the model returns nothing."
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/diarization/{diarizationId}/sentiment-analysis": {
      "post": {
        "summary": "Sentiment Analysis (Diarization)",
        "description": "Generate sentiment analysis from a diarization record ID.",
        "operationId": "diarizationSentimentAnalysis",
        "tags": [
          "Speech-to-Text"
        ],
        "parameters": [
          {
            "name": "diarizationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Diarization record ID"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "analysis_depth": {
                    "type": "string",
                    "enum": [
                      "light",
                      "standard",
                      "deep"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diarization sentiment analysis generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "statusCode",
                    "data",
                    "message"
                  ],
                  "properties": {
                    "statusCode": {
                      "type": "integer",
                      "example": 200
                    },
                    "data": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Structured analysis result. Shape varies with the requested depth; empty object when the model returns nothing."
                    },
                    "message": {
                      "type": "string",
                      "example": "Success"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/translation/stream": {
      "post": {
        "summary": "Translation Stream",
        "description": "Translate text with Server-Sent Events (SSE) streaming response.",
        "operationId": "translationStream",
        "tags": [
          "Translation"
        ],
        "x-badge": {
          "text": "SSE",
          "variant": "success"
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text",
                  "target_language"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "target_language": {
                    "type": "string"
                  },
                  "source_language": {
                    "type": "string"
                  },
                  "model_name": {
                    "type": "string"
                  },
                  "prompt_name": {
                    "type": "string"
                  },
                  "prompt_version": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SSE stream started",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/tashkil/diacritize": {
      "post": {
        "summary": "Diacritize Arabic Text",
        "description": "Add Arabic diacritics (tashkil) to text. The model performs best on Fusha and formal Arabic content.",
        "operationId": "diacritizeArabicText",
        "tags": [
          "Tashkil"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TashkilRequest"
              },
              "example": {
                "text": "ذهب الطالب الى المدرسة"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Text diacritized successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TashkilResponse"
                },
                "example": {
                  "statusCode": 200,
                  "data": {
                    "original_text": "ذهب الطالب الى المدرسة",
                    "diacritized_text": "ذَهَبَ الطَّالِبُ إِلَى المَدْرَسَةِ"
                  },
                  "message": "Success"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid request body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "validationError": {
                    "summary": "Invalid text field",
                    "value": {
                      "errorCode": 40001,
                      "errorMessage": "text: Expected string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid or missing API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "missingApiKey": {
                    "summary": "Missing API key",
                    "value": {
                      "errorCode": 40101,
                      "errorMessage": "API key required"
                    }
                  },
                  "invalidApiKey": {
                    "summary": "Invalid API key",
                    "value": {
                      "errorCode": 40101,
                      "errorMessage": "Invalid API key"
                    }
                  },
                  "expiredApiKey": {
                    "summary": "Expired API key",
                    "value": {
                      "errorCode": 40101,
                      "errorMessage": "API key has expired"
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large - Request body exceeds the maximum size limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "errorCode": 41301,
                  "errorMessage": "Request body exceeds the maximum size limit of 600MB. Please reduce the file size or contact support for assistance."
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - Internal error or upstream Tashkil service failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "errorCode": 50001,
                  "errorMessage": "Internal server error"
                }
              }
            }
          }
        }
      }
    },
    "/listen": {
      "get": {
        "summary": "WebSocket Speech-to-Text (Live streaming)",
        "description": "Real-time Arabic transcription over WebSocket: interim and final results with word timestamps and confidence, turn detection, and per-turn sentiment and speaker gender. Audio is sent as binary frames; controls and events are JSON text frames. The full message contract is in asyncapi.json (channel \"listen\"). Supersedes the deprecated WS /websocket/speech-to-text.",
        "operationId": "websocketListen",
        "tags": [
          "Speech-to-Text"
        ],
        "x-badge": {
          "text": "WSS",
          "variant": "success"
        },
        "parameters": [
          {
            "name": "api_key",
            "in": "query",
            "required": false,
            "description": "API key, for browser clients that cannot set headers. Takes precedence if several auth methods are supplied.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-api-key",
            "in": "query",
            "required": false,
            "description": "API key as a query parameter. Also accepted as a header (see security).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "encoding",
            "in": "query",
            "required": false,
            "description": "Encoding of the binary audio frames.",
            "schema": {
              "type": "string",
              "default": "linear16",
              "enum": [
                "linear16",
                "mulaw",
                "alaw"
              ]
            }
          },
          {
            "name": "sample_rate",
            "in": "query",
            "required": false,
            "description": "Sample rate of the audio you send.",
            "schema": {
              "type": "integer",
              "default": 8000,
              "enum": [
                8000,
                16000
              ]
            }
          },
          {
            "name": "channels",
            "in": "query",
            "required": false,
            "description": "1 (mono) or 2 (stereo, interleaved). With 2, each channel is transcribed independently.",
            "schema": {
              "type": "integer",
              "default": 1,
              "enum": [
                1,
                2
              ]
            }
          },
          {
            "name": "language",
            "in": "query",
            "required": false,
            "description": "Transcription language. \"ar\" is the only supported value in v1.",
            "schema": {
              "type": "string",
              "default": "ar",
              "enum": [
                "ar"
              ]
            }
          },
          {
            "name": "interim_results",
            "in": "query",
            "required": false,
            "description": "Emit interim (partial) results while a turn is in progress.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "endpointing",
            "in": "query",
            "required": false,
            "description": "Milliseconds of silence that end a turn. Retunable mid-session with the Configure message.",
            "schema": {
              "type": "integer",
              "default": 800,
              "minimum": 100,
              "maximum": 5000
            }
          },
          {
            "name": "smart_turn",
            "in": "query",
            "required": false,
            "description": "Gate end-of-turn on a semantic turn-completion model in addition to silence. A turn always ends after 2x the endpointing silence regardless.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          },
          {
            "name": "hotwords",
            "in": "query",
            "required": false,
            "description": "Comma-separated custom vocabulary, URL-encoded; multi-word phrases allowed. Up to 200 entries of 40 characters each. Entries that cannot be applied are reported in Metadata.dropped_hotwords.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "correlation_id",
            "in": "query",
            "required": false,
            "description": "Your identifier for this session, echoed in the opening Metadata event.",
            "schema": {
              "type": "string",
              "maxLength": 128
            }
          },
          {
            "name": "metadata",
            "in": "query",
            "required": false,
            "description": "Base64-encoded JSON object (up to 2 KB) attached to the session.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/websocket/speech-to-text": {
      "get": {
        "summary": "WebSocket Speech-to-Text (Legacy — deprecated)",
        "description": "DEPRECATED: superseded by WS /api/v1/listen (see Speech-to-Text Streaming). WebSocket endpoint for real-time speech-to-text transcription.",
        "operationId": "websocketSpeechToText",
        "tags": [
          "Speech-to-Text"
        ],
        "x-badge": {
          "text": "WSS",
          "variant": "success"
        },
        "deprecated": true,
        "parameters": [
          {
            "name": "x-api-key",
            "in": "query",
            "required": false,
            "description": "API key as a query parameter. Also accepted as a header (see security).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "token",
            "in": "query",
            "required": false,
            "description": "API key fallback for browser clients that cannot set headers.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "model",
            "in": "query",
            "required": false,
            "description": "ASR model to use.",
            "schema": {
              "type": "string",
              "default": "munsit",
              "enum": [
                "munsit",
                "munsit-en-ar"
              ]
            }
          },
          {
            "name": "min_buffer_seconds",
            "in": "query",
            "required": false,
            "description": "Seconds of audio that must accumulate before an interim transcription is emitted.",
            "schema": {
              "type": "number",
              "default": 0.5,
              "minimum": 0.1,
              "maximum": 5.0
            }
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Model": {
        "type": "object",
        "properties": {
          "model_id": {
            "type": "string",
            "description": "Model identifier used in API calls"
          },
          "model_name": {
            "type": "string",
            "description": "Human-readable model name"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Detailed description of the model"
          }
        },
        "required": [
          "model_id",
          "model_name"
        ]
      },
      "Voice": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "description": "Unique identifier for the voice (used in text-to-speech requests)"
          },
          "name": {
            "type": "string",
            "description": "Human-readable name of the voice"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Detailed description of the voice characteristics"
          },
          "gender": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "male",
              "female"
            ],
            "description": "Gender of the voice"
          },
          "age": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "middle",
              "elderly"
            ],
            "description": "Age category of the voice"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of language codes supported by the voice (e.g., [\"ar\", \"en\"])"
          },
          "dialect": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of dialects supported by the voice (e.g., [\"fusha\", \"emirati\", \"najdi\"])"
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "neural"
            ],
            "description": "Voice type"
          },
          "sample_url": {
            "type": "string",
            "format": "uri",
            "description": "URL to an audio sample of the voice"
          }
        },
        "required": [
          "voice_id",
          "name",
          "languages",
          "dialect",
          "sample_url"
        ]
      },
      "ClonedVoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Unique identifier for the voice record"
          },
          "voice_id": {
            "type": "string",
            "description": "Voice identifier used in API calls"
          },
          "name": {
            "type": "string",
            "description": "Name of the cloned voice"
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Description of the voice"
          },
          "gender": {
            "type": [
              "string",
              "null"
            ],
            "description": "Gender of the voice"
          },
          "age": {
            "type": [
              "string",
              "null"
            ],
            "description": "Age category of the voice"
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of language codes supported by the voice"
          },
          "dialect": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of dialects supported by the voice"
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Voice type"
          },
          "sample_url": {
            "type": "string",
            "format": "uri",
            "description": "URL to the sample audio file"
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "URL to the avatar image"
          },
          "stability": {
            "type": "number",
            "description": "Voice stability value"
          }
        },
        "required": [
          "id",
          "voice_id",
          "name",
          "languages",
          "dialect",
          "sample_url",
          "stability"
        ]
      },
      "TextToSpeechRequest": {
        "type": "object",
        "required": [
          "voice_id",
          "text",
          "stability",
          "streaming"
        ],
        "properties": {
          "voice_id": {
            "type": "string",
            "description": "The voice ID to use for synthesis"
          },
          "text": {
            "type": "string",
            "description": "The Arabic text to convert to speech"
          },
          "stability": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Voice stability (0.0 to 1.0). Higher values produce more consistent output"
          },
          "speed": {
            "type": "number",
            "minimum": 0.7,
            "maximum": 1.2,
            "default": 1.0,
            "description": "Speech speed multiplier (0.7 to 1.2). Values below 1.0 slow down speech, values above 1.0 speed it up"
          },
          "streaming": {
            "type": "boolean",
            "description": "If true, returns streaming PCM16 audio. If false, returns complete WAV file"
          },
          "sample_rate": {
            "type": "number",
            "minimum": 8000,
            "maximum": 48000,
            "default": 24000,
            "description": "Output sample rate in Hz. Use 48000 for WebRTC-native audio with no client resampling."
          },
          "dialect": {
            "type": "string",
            "enum": [
              "auto",
              "emirati",
              "fusha"
            ],
            "default": "auto",
            "description": "Dialect hint for synthesis."
          }
        }
      },
      "TashkilRequest": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "text": {
            "type": "string",
            "minLength": 1,
            "description": "Arabic text to diacritize. Fusha and formal Arabic text are recommended for best results."
          }
        }
      },
      "TashkilResponse": {
        "type": "object",
        "required": [
          "statusCode",
          "data",
          "message"
        ],
        "properties": {
          "statusCode": {
            "type": "integer",
            "example": 200
          },
          "data": {
            "type": "object",
            "required": [
              "original_text",
              "diacritized_text"
            ],
            "properties": {
              "original_text": {
                "type": "string",
                "description": "Original input text."
              },
              "diacritized_text": {
                "type": "string",
                "description": "Text with Arabic diacritics."
              }
            }
          },
          "message": {
            "type": "string",
            "example": "Success"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "errorCode",
          "errorMessage"
        ],
        "properties": {
          "errorCode": {
            "type": "integer",
            "example": 40001,
            "description": "Numeric error code for programmatic handling. Returned unquoted."
          },
          "errorMessage": {
            "type": "string",
            "description": "Human-readable error message"
          }
        }
      },
      "DenoiseRecord": {
        "type": "object",
        "required": [
          "id",
          "user_id",
          "original_audio_url",
          "file_name",
          "audio_duration",
          "audio_size",
          "audio_format",
          "source_type",
          "status",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Denoising record id (same value as denoiseId returned by POST /denoise)."
          },
          "user_id": {
            "type": "string",
            "description": "Owner of the record."
          },
          "transaction_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Wallet transaction id associated with billing for this job, if any."
          },
          "audio_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL of the denoised audio. Null until the job reaches success."
          },
          "original_audio_url": {
            "type": "string",
            "description": "URL of the originally uploaded file."
          },
          "file_name": {
            "type": "string",
            "description": "Original file name as submitted by the client."
          },
          "audio_duration": {
            "type": "number",
            "description": "Duration of the source audio in seconds."
          },
          "audio_size": {
            "type": "number",
            "description": "Size of the source file in bytes."
          },
          "audio_format": {
            "type": "string",
            "description": "Lower-cased file extension of the source file."
          },
          "source_type": {
            "type": "string",
            "enum": [
              "audio",
              "video"
            ],
            "description": "Whether the upload was an audio file or a video container."
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed"
            ],
            "description": "Current job status."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Error message if status is failed."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DenoiseProgressEvent": {
        "description": "An SSE event payload for a denoising job. The stage field discriminates between processing, done, and error.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "stage",
              "pct"
            ],
            "properties": {
              "stage": {
                "type": "string",
                "enum": [
                  "processing"
                ]
              },
              "pct": {
                "type": "number",
                "minimum": 0,
                "maximum": 100,
                "description": "Completion percentage."
              },
              "message": {
                "type": "string",
                "description": "Optional human-readable progress message."
              }
            }
          },
          {
            "type": "object",
            "required": [
              "stage",
              "url",
              "denoiseId"
            ],
            "properties": {
              "stage": {
                "type": "string",
                "enum": [
                  "done"
                ]
              },
              "url": {
                "type": "string",
                "description": "URL of the denoised audio file."
              },
              "denoiseId": {
                "type": "string",
                "format": "uuid"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "stage",
              "message"
            ],
            "properties": {
              "stage": {
                "type": "string",
                "enum": [
                  "error"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable error message."
              }
            }
          }
        ]
      },
      "SttStats": {
        "type": "object",
        "properties": {
          "fileName": {
            "type": "string"
          },
          "fileSize": {
            "type": "string",
            "description": "Human-readable size, e.g. \"1.42 MB\""
          },
          "mimeType": {
            "type": "string"
          },
          "creditsConsumed": {
            "type": "number",
            "description": "Credits billed for this request"
          }
        }
      }
    },
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "API key for authentication"
      }
    }
  }
}
