> ## Documentation Index
> Fetch the complete documentation index at: https://typecast.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 텍스트 음성 변환(TTS)

> 보이스를 설정하여 텍스트에서 음성을 생성합니다. 감정, 볼륨, 피치, 템포 맞춤 설정을 지원합니다.

먼저 GET /v2/voices 엔드포인트를 사용하여 사용 가능한 모든 보이스를 조회한 다음, 응답의 voice_id를 사용하여 이 엔드포인트로 음성을 생성합니다. 각 보이스에는 고유한 특성이 있습니다. 사용 가능한 보이스는 [보이스 목록 조회](/docs/ko/api-reference/voices/list-voices)를 참조하세요.

## OpenAPI

```json
{
  "openapi": "3.1.0",
  "info": {
    "title": "Typecast API",
    "version": "0.1.2",
    "x-logo": {
      "url": "https://typecast.ai/docs/logo/light.svg"
    }
  },
  "servers": [
    {
      "url": "https://api.typecast.ai",
      "description": "프로덕션 서버"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/text-to-speech": {
      "post": {
        "tags": [
          "Text-to-Speech"
        ],
        "summary": "텍스트 음성 변환(TTS)",
        "description": "보이스를 설정하여 텍스트에서 음성을 생성합니다. 감정, 볼륨, 피치, 템포 맞춤 설정을 지원합니다.\n\n먼저 GET /v2/voices 엔드포인트를 사용하여 사용 가능한 모든 보이스를 조회한 다음, 응답의 voice_id를 사용하여 이 엔드포인트로 음성을 생성합니다. 각 보이스에는 고유한 특성이 있습니다. 사용 가능한 보이스는 [보이스 목록 조회](/docs/ko/api-reference/voices/list-voices)를 참조하세요.",
        "operationId": "text_to_speech_v1_text_to_speech_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TTSRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Success - Returns audio file",
            "content": {
              "audio/wav": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "WAV 오디오 파일 바이너리 데이터(비압축 PCM, 16비트, 모노, 44.1kHz)"
                },
                "example": "[Binary audio data - WAV file content]"
              },
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary",
                  "description": "MP3 audio file binary data. Compressed MPEG Layer III audio with 320 kbps bitrate, 44100 Hz sample rate."
                },
                "example": "[Binary audio data - MP3 file content]"
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Invalid voice_id"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Authentication failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Invalid API key"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required - Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Insufficient credit"
                }
              }
            }
          },
          "404": {
            "description": "Not Found - Voice model not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Voice not found"
                }
              }
            }
          },
          "422": {
            "description": "유효성 검사 오류 - 요청이 올바르지 않거나 입력 텍스트를 합성할 수 없는 경우",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error_code": "TEXT_NOT_SYNTHESIZABLE",
                  "message": "The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text."
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests - Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "Too many requests"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error - Server processing failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "detail": "An unexpected error occurred"
                }
              }
            }
          }
        },
        "x-mint": {
          "href": "/ko/api-reference/text-to-speech/text-to-speech"
        },
        "x-codeSamples": [
          {
            "lang": "cURL",
            "label": "cURL (파일로 저장)",
            "source": "curl --request POST \\\n  --url https://api.typecast.ai/v1/text-to-speech \\\n  --header 'Content-Type: application/json' \\\n  --header 'X-API-KEY: <api-key>' \\\n  --output output.wav \\\n  --data @- <<EOF\n{\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n  \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n  \"model\": \"ssfm-v30\",\n  \"language\": \"eng\",\n  \"prompt\": {\n    \"emotion_type\": \"smart\",\n    \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n    \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n  },\n  \"output\": {\n    \"volume\": 100,\n    \"audio_pitch\": 0,\n    \"audio_tempo\": 1,\n    \"audio_format\": \"wav\"\n  },\n  \"seed\": 42\n}\nEOF\n"
          },
          {
            "lang": "Python",
            "label": "Python (requests)",
            "source": "import requests\n\nAPI_HOST = \"https://api.typecast.ai\"\nheaders = {\n    \"X-API-KEY\": \"<api-key>\",\n    \"Content-Type\": \"application/json\",\n}\npayload = {\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n    \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n    \"model\": \"ssfm-v30\",\n    \"language\": \"eng\",\n    \"prompt\": {\n        \"emotion_type\": \"smart\",\n        \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n        \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\",\n    },\n    \"output\": {\n        \"volume\": 100,\n        \"audio_pitch\": 0,\n        \"audio_tempo\": 1,\n        \"audio_format\": \"wav\",\n    },\n    \"seed\": 42,\n}\n\nresponse = requests.post(f\"{API_HOST}/v1/text-to-speech\", headers=headers, json=payload, timeout=60)\nresponse.raise_for_status()\n\nwith open(\"output.wav\", \"wb\") as f:\n    f.write(response.content)\nprint(f\"Saved {len(response.content)} bytes to output.wav\")\n"
          },
          {
            "lang": "C#",
            "label": "C# (HttpClient)",
            "source": "using System;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\n\nvar client = new HttpClient();\nclient.DefaultRequestHeaders.Add(\"X-API-KEY\", \"<api-key>\");\n\nvar requestBody = @\"{\n  \"\"voice_id\"\": \"\"tc_60e5426de8b95f1d3000d7b5\"\",\n  \"\"text\"\": \"\"Everything is so incredibly perfect that I feel like I'm dreaming.\"\",\n  \"\"model\"\": \"\"ssfm-v30\"\",\n  \"\"language\"\": \"\"eng\"\",\n  \"\"prompt\"\": {\n    \"\"emotion_type\"\": \"\"smart\"\",\n    \"\"previous_text\"\": \"\"I feel like I'm walking on air and I just want to scream with joy!\"\",\n    \"\"next_text\"\": \"\"I am literally bursting with happiness and I never want this feeling to end!\"\"\n  },\n  \"\"output\"\": {\n    \"\"volume\"\": 100,\n    \"\"audio_pitch\"\": 0,\n    \"\"audio_tempo\"\": 1,\n    \"\"audio_format\"\": \"\"wav\"\"\n  },\n  \"\"seed\"\": 42\n}\";\n\nvar content = new StringContent(requestBody, Encoding.UTF8, \"application/json\");\nvar response = await client.PostAsync(\"https://api.typecast.ai/v1/text-to-speech\", content);\n\nif (response.IsSuccessStatusCode)\n{\n    var audioBytes = await response.Content.ReadAsByteArrayAsync();\n    await File.WriteAllBytesAsync(\"output.wav\", audioBytes);\n    Console.WriteLine(\"Audio saved to output.wav\");\n}\n"
          },
          {
            "lang": "Kotlin",
            "label": "Kotlin (OkHttp)",
            "source": "import okhttp3.MediaType.Companion.toMediaType\nimport okhttp3.OkHttpClient\nimport okhttp3.Request\nimport okhttp3.RequestBody.Companion.toRequestBody\nimport java.io.File\n\nval client = OkHttpClient()\nval mediaType = \"application/json\".toMediaType()\n\nval requestBody = \"\"\"\n{\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n  \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n  \"model\": \"ssfm-v30\",\n  \"language\": \"eng\",\n  \"prompt\": {\n    \"emotion_type\": \"smart\",\n    \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n    \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n  },\n  \"output\": {\n    \"volume\": 100,\n    \"audio_pitch\": 0,\n    \"audio_tempo\": 1,\n    \"audio_format\": \"wav\"\n  },\n  \"seed\": 42\n}\n\"\"\".trimIndent()\n\nval request = Request.Builder()\n    .url(\"https://api.typecast.ai/v1/text-to-speech\")\n    .addHeader(\"X-API-KEY\", \"<api-key>\")\n    .addHeader(\"Content-Type\", \"application/json\")\n    .post(requestBody.toRequestBody(mediaType))\n    .build()\n\nclient.newCall(request).execute().use { response ->\n    if (response.isSuccessful) {\n        response.body?.bytes()?.let {\n            File(\"output.wav\").writeBytes(it)\n            println(\"Audio saved to output.wav\")\n        }\n    }\n}\n"
          },
          {
            "lang": "C++",
            "label": "C++ (libcurl)",
            "source": "#include <curl/curl.h>\n#include <fstream>\n#include <string>\n\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    ((std::string*)userp)->append((char*)contents, size * nmemb);\n    return size * nmemb;\n}\n\nint main() {\n    CURL* curl = curl_easy_init();\n    if(curl) {\n        std::string readBuffer;\n        struct curl_slist* headers = NULL;\n\n        headers = curl_slist_append(headers, \"Content-Type: application/json\");\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        std::string jsonData = R\"({\n          \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n          \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n          \"model\": \"ssfm-v30\",\n          \"language\": \"eng\",\n          \"prompt\": {\n            \"emotion_type\": \"smart\",\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n          },\n          \"output\": {\n            \"volume\": 100,\n            \"audio_pitch\": 0,\n            \"audio_tempo\": 1,\n            \"audio_format\": \"wav\"\n          },\n          \"seed\": 42\n        })\";\n\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech\");\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);\n\n        CURLcode res = curl_easy_perform(curl);\n        if(res == CURLE_OK) {\n            std::ofstream outFile(\"output.wav\", std::ios::binary);\n            outFile.write(readBuffer.c_str(), readBuffer.size());\n            outFile.close();\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n    }\n    return 0;\n}\n"
          },
          {
            "lang": "C",
            "label": "C (libcurl)",
            "source": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <curl/curl.h>\n\ntypedef struct {\n    char* data;\n    size_t size;\n} MemoryStruct;\n\nsize_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    size_t realsize = size * nmemb;\n    MemoryStruct* mem = (MemoryStruct*)userp;\n\n    char* ptr = realloc(mem->data, mem->size + realsize + 1);\n    if(!ptr) return 0;\n\n    mem->data = ptr;\n    memcpy(&(mem->data[mem->size]), contents, realsize);\n    mem->size += realsize;\n    mem->data[mem->size] = 0;\n\n    return realsize;\n}\n\nint main(void) {\n    CURL* curl;\n    CURLcode res;\n    MemoryStruct chunk = {NULL, 0};\n\n    curl_global_init(CURL_GLOBAL_ALL);\n    curl = curl_easy_init();\n\n    if(curl) {\n        struct curl_slist* headers = NULL;\n        headers = curl_slist_append(headers, \"Content-Type: application/json\");\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        const char* jsonData = \"{\"\n            \"\\\"voice_id\\\":\\\"tc_60e5426de8b95f1d3000d7b5\\\",\"\n            \"\\\"text\\\":\\\"Everything is so incredibly perfect that I feel like I'm dreaming.\\\",\"\n            \"\\\"model\\\":\\\"ssfm-v30\\\",\"\n            \"\\\"language\\\":\\\"eng\\\",\"\n            \"\\\"output\\\":{\\\"volume\\\":100,\\\"audio_pitch\\\":0,\\\"audio_tempo\\\":1,\\\"audio_format\\\":\\\"wav\\\"},\"\n            \"\\\"seed\\\":42\"\n            \"}\";\n\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech\");\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);\n\n        res = curl_easy_perform(curl);\n\n        if(res == CURLE_OK) {\n            FILE* fp = fopen(\"output.wav\", \"wb\");\n            fwrite(chunk.data, 1, chunk.size, fp);\n            fclose(fp);\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n        free(chunk.data);\n    }\n\n    curl_global_cleanup();\n    return 0;\n}\n"
          },
          {
            "lang": "Swift",
            "label": "Swift (URLSession)",
            "source": "import Foundation\n\nlet url = URL(string: \"https://api.typecast.ai/v1/text-to-speech\")!\nvar request = URLRequest(url: url)\nrequest.httpMethod = \"POST\"\nrequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\nrequest.setValue(\"<api-key>\", forHTTPHeaderField: \"X-API-KEY\")\n\nlet requestBody: [String: Any] = [\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n    \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n    \"model\": \"ssfm-v30\",\n    \"language\": \"eng\",\n    \"prompt\": [\n        \"emotion_type\": \"smart\",\n        \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n        \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n    ],\n    \"output\": [\n        \"volume\": 100,\n        \"audio_pitch\": 0,\n        \"audio_tempo\": 1,\n        \"audio_format\": \"wav\"\n    ],\n    \"seed\": 42\n]\n\nrequest.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)\n\nlet task = URLSession.shared.dataTask(with: request) { data, response, error in\n    if let data = data {\n        try? data.write(to: URL(fileURLWithPath: \"output.wav\"))\n        print(\"Audio saved to output.wav\")\n    }\n}\ntask.resume()\n"
          },
          {
            "lang": "Rust",
            "label": "Rust (reqwest)",
            "source": "use reqwest;\nuse serde_json::json;\nuse std::fs::File;\nuse std::io::Write;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = reqwest::Client::new();\n\n    let request_body = json!({\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n        \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n        \"model\": \"ssfm-v30\",\n        \"language\": \"eng\",\n        \"prompt\": {\n            \"emotion_type\": \"smart\",\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n        },\n        \"output\": {\n            \"volume\": 100,\n            \"audio_pitch\": 0,\n            \"audio_tempo\": 1,\n            \"audio_format\": \"wav\"\n        },\n        \"seed\": 42\n    });\n\n    let response = client\n        .post(\"https://api.typecast.ai/v1/text-to-speech\")\n        .header(\"X-API-KEY\", \"<api-key>\")\n        .header(\"Content-Type\", \"application/json\")\n        .json(&request_body)\n        .send()\n        .await?;\n\n    if response.status().is_success() {\n        let bytes = response.bytes().await?;\n        let mut file = File::create(\"output.wav\")?;\n        file.write_all(&bytes)?;\n        println!(\"Audio saved to output.wav\");\n    }\n\n    Ok(())\n}\n"
          },
          {
            "lang": "JavaScript",
            "label": "JavaScript (Node.js)",
            "source": "// Node 18+ (built-in fetch).\nimport { writeFile } from \"node:fs/promises\";\n\nconst response = await fetch(\"https://api.typecast.ai/v1/text-to-speech\", {\n    method: \"POST\",\n    headers: {\n        \"Content-Type\": \"application/json\",\n        \"X-API-KEY\": \"<api-key>\",\n    },\n    body: JSON.stringify({\n        voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\n        text: \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n        model: \"ssfm-v30\",\n        language: \"eng\",\n        prompt: {\n            emotion_type: \"smart\",\n            previous_text: \"I feel like I'm walking on air and I just want to scream with joy!\",\n            next_text: \"I am literally bursting with happiness and I never want this feeling to end!\",\n        },\n        output: { volume: 100, audio_pitch: 0, audio_tempo: 1, audio_format: \"wav\" },\n        seed: 42,\n    }),\n});\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\nconst buffer = Buffer.from(await response.arrayBuffer());\nawait writeFile(\"output.wav\", buffer);\nconsole.log(`Saved ${buffer.length} bytes to output.wav`);\n"
          },
          {
            "lang": "PHP",
            "label": "PHP (curl)",
            "source": "<?php\n$payload = json_encode([\n    \"voice_id\" => \"tc_60e5426de8b95f1d3000d7b5\",\n    \"text\" => \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n    \"model\" => \"ssfm-v30\",\n    \"language\" => \"eng\",\n    \"prompt\" => [\n        \"emotion_type\" => \"smart\",\n        \"previous_text\" => \"I feel like I'm walking on air and I just want to scream with joy!\",\n        \"next_text\" => \"I am literally bursting with happiness and I never want this feeling to end!\",\n    ],\n    \"output\" => [\"volume\" => 100, \"audio_pitch\" => 0, \"audio_tempo\" => 1, \"audio_format\" => \"wav\"],\n    \"seed\" => 42,\n]);\n\n$ch = curl_init(\"https://api.typecast.ai/v1/text-to-speech\");\ncurl_setopt_array($ch, [\n    CURLOPT_POST => true,\n    CURLOPT_RETURNTRANSFER => true,\n    CURLOPT_HTTPHEADER => [\n        \"Content-Type: application/json\",\n        \"X-API-KEY: <api-key>\",\n    ],\n    CURLOPT_POSTFIELDS => $payload,\n]);\n$audio = curl_exec($ch);\n$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);\nif ($status !== 200) {\n    fwrite(STDERR, \"HTTP $status\\n\");\n    exit(1);\n}\nfile_put_contents(\"output.wav\", $audio);\necho \"Saved \" . strlen($audio) . \" bytes to output.wav\\n\";\n"
          },
          {
            "lang": "Go",
            "label": "Go (net/http)",
            "source": "package main\n\nimport (\n    \"bytes\"\n    \"fmt\"\n    \"io\"\n    \"net/http\"\n    \"os\"\n)\n\nfunc main() {\n    body := []byte(`{\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n        \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n        \"model\": \"ssfm-v30\",\n        \"language\": \"eng\",\n        \"prompt\": {\n            \"emotion_type\": \"smart\",\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n        },\n        \"output\": {\"volume\": 100, \"audio_pitch\": 0, \"audio_tempo\": 1, \"audio_format\": \"wav\"},\n        \"seed\": 42\n    }`)\n\n    req, _ := http.NewRequest(\"POST\", \"https://api.typecast.ai/v1/text-to-speech\", bytes.NewReader(body))\n    req.Header.Set(\"Content-Type\", \"application/json\")\n    req.Header.Set(\"X-API-KEY\", \"<api-key>\")\n\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n\n    out, _ := os.Create(\"output.wav\")\n    defer out.Close()\n    n, _ := io.Copy(out, resp.Body)\n    fmt.Printf(\"Saved %d bytes to output.wav\\n\", n)\n}\n"
          },
          {
            "lang": "Java",
            "label": "Java (HttpClient)",
            "source": "// Java 11+ HttpClient + file body handler.\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.nio.file.Path;\n\npublic class TextToSpeech {\n    public static void main(String[] args) throws Exception {\n        String body = \"\"\"\n            {\n              \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n              \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n              \"model\": \"ssfm-v30\",\n              \"language\": \"eng\",\n              \"prompt\": {\n                \"emotion_type\": \"smart\",\n                \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\n                \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\n              },\n              \"output\": {\"volume\": 100, \"audio_pitch\": 0, \"audio_tempo\": 1, \"audio_format\": \"wav\"},\n              \"seed\": 42\n            }\n            \"\"\";\n\n        HttpRequest request = HttpRequest.newBuilder()\n                .uri(URI.create(\"https://api.typecast.ai/v1/text-to-speech\"))\n                .header(\"Content-Type\", \"application/json\")\n                .header(\"X-API-KEY\", \"<api-key>\")\n                .POST(HttpRequest.BodyPublishers.ofString(body))\n                .build();\n\n        HttpResponse<Path> response = HttpClient.newHttpClient()\n                .send(request, HttpResponse.BodyHandlers.ofFile(Path.of(\"output.wav\")));\n\n        System.out.println(\"Audio saved to \" + response.body());\n    }\n}\n"
          },
          {
            "lang": "Ruby",
            "label": "Ruby (net/http)",
            "source": "require \"net/http\"\nrequire \"uri\"\nrequire \"json\"\n\nuri = URI(\"https://api.typecast.ai/v1/text-to-speech\")\nhttp = Net::HTTP.new(uri.host, uri.port)\nhttp.use_ssl = true\n\nreq = Net::HTTP::Post.new(uri)\nreq[\"Content-Type\"] = \"application/json\"\nreq[\"X-API-KEY\"] = \"<api-key>\"\nreq.body = {\n  voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\n  text: \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\n  model: \"ssfm-v30\",\n  language: \"eng\",\n  prompt: {\n    emotion_type: \"smart\",\n    previous_text: \"I feel like I'm walking on air and I just want to scream with joy!\",\n    next_text: \"I am literally bursting with happiness and I never want this feeling to end!\",\n  },\n  output: { volume: 100, audio_pitch: 0, audio_tempo: 1, audio_format: \"wav\" },\n  seed: 42,\n}.to_json\n\nresp = http.request(req)\nraise \"HTTP #{resp.code}\" unless resp.code == \"200\"\n\nFile.binwrite(\"output.wav\", resp.body)\nputs \"Saved #{resp.body.bytesize} bytes to output.wav\"\n"
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AgeEnum": {
        "type": "string",
        "enum": [
          "child",
          "teenager",
          "young_adult",
          "middle_age",
          "elder"
        ],
        "title": "AgeEnum",
        "description": "연령대 분류 열거형 - 데이터베이스 값(한국어)을 API 값(영어)으로 변환합니다.\n\n사용 가능한 값:\n- **child**: 어린이 보이스(12세 미만)\n- **teenager**: 청소년 보이스(13-19세)\n- **young_adult**: 청년 보이스(20-35세)\n- **middle_age**: 중년 보이스(36-60세)\n- **elder**: 노년 보이스(60세 이상)\n"
      },
      "AlignmentSegmentCharacter": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "title": "Text",
            "description": "원본 transcript 의 텍스트 조각 (문장부호/공백 포함)."
          },
          "start": {
            "type": "number",
            "title": "Start",
            "description": "이 구간의 시작 시각(오디오 시작 기준 초)."
          },
          "end": {
            "type": "number",
            "title": "End",
            "description": "이 구간의 종료 시각(오디오 시작 기준 초)."
          }
        },
        "required": [
          "text",
          "start",
          "end"
        ],
        "title": "AlignmentSegmentCharacter",
        "description": "원본 transcript 와 생성된 오디오 사이의 문자 단위 정렬 구간."
      },
      "AlignmentSegmentWord": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "title": "Text",
            "description": "원본 transcript 의 텍스트 조각 (문장부호 포함)."
          },
          "start": {
            "type": "number",
            "title": "Start",
            "description": "이 구간의 시작 시각(오디오 시작 기준 초)."
          },
          "end": {
            "type": "number",
            "title": "End",
            "description": "이 구간의 종료 시각(오디오 시작 기준 초)."
          }
        },
        "required": [
          "text",
          "start",
          "end"
        ],
        "title": "AlignmentSegmentWord",
        "description": "원본 transcript 와 생성된 오디오 사이의 단어 단위 정렬 구간."
      },
      "Body_create_voice_clone_v1_voices_clone_post": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "title": "File",
            "description": "오디오 샘플. WAV 또는 MP3, 최대 25MB, 5초 이상 150초 이하.",
            "contentMediaType": "application/octet-stream",
            "format": "binary"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "보이스 이름 (1~30자).",
            "maxLength": 30,
            "minLength": 1
          },
          "model": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "클로닝할 엔진 모델 (`ssfm-v21` 또는 `ssfm-v30`).",
            "allOf": [
              {
                "$ref": "#/components/schemas/TTSModel"
              }
            ]
          }
        },
        "required": [
          "file",
          "name",
          "model"
        ],
        "title": "Body_create_voice_clone_v1_voices_clone_post",
        "description": "퀵 클로닝 요청을 위한 multipart 본문."
      },
      "ComposeRequest": {
        "type": "object",
        "properties": {
          "segments": {
            "type": "array",
            "items": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/TTSComposeSegment"
                },
                {
                  "$ref": "#/components/schemas/PauseComposeSegment"
                }
              ],
              "discriminator": {
                "propertyName": "type",
                "mapping": {
                  "pause": "#/components/schemas/PauseComposeSegment",
                  "tts": "#/components/schemas/TTSComposeSegment"
                }
              }
            },
            "title": "Segments",
            "description": "출력 순서대로 나열한 음성과 쉼 세그먼트입니다. 최소 1개, 최대 50개이며 `tts` 세그먼트가 적어도 하나 필요합니다.",
            "minItems": 1,
            "maxItems": 50
          }
        },
        "required": [
          "segments"
        ],
        "title": "ComposeRequest",
        "description": "음성과 쉼 세그먼트를 순서대로 합성하여 하나의 오디오 파일로 반환하는 요청입니다."
      },
      "Credits": {
        "type": "object",
        "properties": {
          "plan_credits": {
            "type": "integer",
            "title": "Plan Credits",
            "description": "플랜에서 기본으로 제공하는 총 크레딧"
          },
          "used_credits": {
            "type": "integer",
            "title": "Used Credits",
            "description": "사용된 크레딧 수"
          }
        },
        "required": [
          "plan_credits",
          "used_credits"
        ],
        "title": "Credits",
        "description": "크레딧 사용 정보"
      },
      "CustomVoiceResponse": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "`uc_` prefix 가 붙은 커스텀 보이스 식별자. `POST /v1/text-to-speech` 등 `voice_id` 를 받는 엔드포인트에 그대로 사용할 수 있습니다.",
            "example": "uc_64a1b2c3d4e5f6a7b8c9d0e1"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "보이스 이름 (1~30자)."
          },
          "model": {
            "type": "string",
            "title": "Model",
            "description": "보이스가 클로닝된 엔진 모델 (`ssfm-v21` 또는 `ssfm-v30`).",
            "allOf": [
              {
                "$ref": "#/components/schemas/TTSModel"
              }
            ]
          }
        },
        "required": [
          "voice_id",
          "name",
          "model"
        ],
        "title": "CustomVoiceResponse",
        "description": "`POST /v1/voices/clone` 응답 - 퀵 클로닝으로 생성된 커스텀 보이스 메타데이터."
      },
      "EmotionEnum": {
        "type": "string",
        "enum": [
          "normal",
          "sad",
          "happy",
          "angry",
          "whisper",
          "toneup",
          "tonedown"
        ],
        "title": "EmotionEnum",
        "description": "음성 합성에 사용 가능한 감정 프리셋. 각 감정은 생성된 음성의 톤, 속도, 표현력에 영향을 줍니다.\n\n**ssfm-v21 지원 감정 (4종류):**\n- normal: 중립적이고 균형 잡힌 톤\n- happy: 밝고 명랑한 표현\n- sad: 우울하고 차분한 톤\n- angry: 강하고 강렬한 전달\n\n**ssfm-v30 지원 감정 (7종류):**\n- normal: 중립적이고 균형 잡힌 톤\n- happy: 밝고 명랑한 표현\n- sad: 우울하고 차분한 톤\n- angry: 강하고 강렬한 전달\n- whisper: 부드럽고 조용한 말\n- toneup: 더 높은 톤 강조\n- tonedown: 더 낮은 톤 강조\n\n/v2/voices API 응답을 통해 각 음성에 사용 가능한 감정을 확인하세요.\n"
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "description": "문제를 설명하는 오류 메시지"
          },
          "error_code": {
            "type": "string",
            "description": "구조화된 오류를 식별하는 코드"
          },
          "message": {
            "type": "string",
            "description": "구조화된 오류에 대한 설명"
          }
        },
        "description": "기존 오류와 유효성 검사 오류는 `detail`을 사용하며, 구조화된 오류는 `error_code`와 `message`를 사용합니다.",
        "example": {
          "error_code": "TEXT_NOT_SYNTHESIZABLE",
          "message": "The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text."
        }
      },
      "GenderEnum": {
        "type": "string",
        "enum": [
          "male",
          "female"
        ],
        "title": "GenderEnum",
        "description": "성별 분류 열거형 - 데이터베이스 값(한국어)을 API 값(영어)으로 변환합니다.\n\n사용 가능한 값:\n- **male**: 남성 보이스\n- **female**: 여성 보이스\n"
      },
      "HTTPValidationError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "title": "Detail"
          }
        },
        "title": "HTTPValidationError"
      },
      "Limits": {
        "type": "object",
        "properties": {
          "concurrency_limit": {
            "type": "integer",
            "title": "Concurrency Limit",
            "description": "허용되는 최대 동시 요청 수"
          },
          "custom_voice_slot": {
            "type": "integer",
            "minimum": 0,
            "title": "Custom Voice Slot",
            "description": "퀵클로닝 슬롯 한도",
            "default": 0
          }
        },
        "required": [
          "concurrency_limit"
        ],
        "title": "Limits",
        "description": "사용 제한 정보"
      },
      "ModelInfo": {
        "type": "object",
        "properties": {
          "version": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "TTS 모델 버전(예: ssfm-v21, ssfm-v30)"
          },
          "emotions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "title": "Emotions",
            "description": "이 모델에서 지원되는 감정 목록"
          }
        },
        "required": [
          "version",
          "emotions"
        ],
        "title": "ModelInfo",
        "description": "버전 및 지원되는 감정을 포함한 모델 정보"
      },
      "Output": {
        "type": "object",
        "properties": {
          "target_lufs": {
            "type": "integer",
            "title": "Target Lufs",
            "description": "출력 음성의 목표 절대 음량(LUFS) 설정. 원본 음성의 크기와 상관없이 모든 음성을 일정한 크기로 정규화하여 생성합니다. 값이 0에 가까울수록 소리가 커지며, -70에 가까울수록 작아집니다.\n\n- 필수 범위: -70 <= x <= 0\n- 권장값: -14 (일반적인 스트리밍 표준), -23 (방송 표준)\n- **주의:** `volume` 파라미터와 함께 사용할 수 없습니다. 절대적인 음량 기준이 필요할 때는 `target_lufs`를, 상대적인 비율 조절이 필요할 때는 `volume`을 선택하여 사용하세요.\n",
            "example": -14,
            "anyOf": [
              {
                "type": "number",
                "maximum": 0,
                "minimum": -70
              },
              {
                "type": "null"
              }
            ]
          },
          "volume": {
            "title": "Volume",
            "description": "출력 음성의 상대적인 음량 조절: 0(완전 무음), 50(절반 볼륨), 100(표준 볼륨, 기본값), 150(표준보다 50% 크게), 200(최대 볼륨, 표준의 두 배).\n\n출력된 음성마다 음량이 다를 경우, 단순 비율 조절인 `volume`을 사용하면 음성 간의 음량 편차가 더욱 커질 수 있습니다. 일정한 음량 출력이 필요한 경우 `target_lufs` 사용을 권장합니다.\n\n- **주의:** `target_lufs`와 동시에 사용할 수 없습니다.\n\n필수 범위: 0 <= x <= 200\n",
            "example": 100,
            "anyOf": [
              {
                "type": "integer",
                "maximum": 200,
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          },
          "audio_pitch": {
            "type": "integer",
            "maximum": 12,
            "minimum": -12,
            "title": "Audio Pitch",
            "description": "성별과 나이에 영향을 주는 반음 단위의 피치 조정: -12(한 옥타브 낮게, 더 깊은 목소리), -6(반 옥타브 낮게), 0(원래 피치, 기본값), +6(반 옥타브 높게), +12(한 옥타브 높게, 더 높은 목소리)",
            "default": 0,
            "example": 0
          },
          "audio_tempo": {
            "type": "number",
            "maximum": 2,
            "minimum": 0.5,
            "title": "Audio Tempo",
            "description": "음성 속도 제어: 0.5(절반 속도, 매우 느리고 명확함), 0.75(보통보다 약간 느림), 1.0(보통 말하기 속도, 기본값), 1.5(보통보다 50% 빠름), 2.0(두 배 속도, 매우 빠른 음성)",
            "default": 1,
            "example": 1
          },
          "audio_format": {
            "type": "string",
            "enum": [
              "wav",
              "mp3"
            ],
            "title": "Audio Format",
            "description": "출력 오디오 형식.\n\n**WAV 형식:**\n- 비압축 PCM 오디오\n- 16비트 깊이, 모노 채널, 44100 Hz 샘플링 속도\n- 더 높은 품질, 더 큰 파일 크기\n- 전문 오디오 제작에 권장\n\n**MP3 형식:**\n- 압축된 MPEG Layer III 오디오\n- 320 kbps 비트레이트, 44100 Hz 샘플링 속도\n- 더 작은 파일 크기\n- 웹 스트리밍 및 배포에 권장\n",
            "default": "wav",
            "example": "wav"
          }
        },
        "title": "Output"
      },
      "OutputStream": {
        "type": "object",
        "properties": {
          "target_lufs": {
            "type": "integer",
            "title": "Target Lufs",
            "description": "스트리밍 출력 음성의 목표 절대 음량(LUFS) 설정. 원본 음성의 크기와 상관없이 일정한 라우드니스로 정규화합니다. `volume` 파라미터와 함께 사용할 수 없습니다.\n\n권장값: -14(일반적인 스트리밍 표준), -23(방송 표준).\n",
            "example": -14,
            "anyOf": [
              {
                "type": "number",
                "maximum": 0,
                "minimum": -70
              },
              {
                "type": "null"
              }
            ]
          },
          "audio_pitch": {
            "type": "integer",
            "maximum": 12,
            "minimum": -12,
            "title": "Audio Pitch",
            "description": "성별과 나이에 영향을 주는 반음 단위의 피치 조정: -12(한 옥타브 낮게, 더 깊은 목소리), -6(반 옥타브 낮게), 0(원래 피치, 기본값), +6(반 옥타브 높게), +12(한 옥타브 높게, 더 높은 목소리)",
            "default": 0,
            "example": 0
          },
          "audio_tempo": {
            "type": "number",
            "maximum": 2,
            "minimum": 0.5,
            "title": "Audio Tempo",
            "description": "음성 속도 제어: 0.5(절반 속도, 매우 느리고 명확함), 0.75(보통보다 약간 느림), 1.0(보통 말하기 속도, 기본값), 1.5(보통보다 50% 빠름), 2.0(두 배 속도, 매우 빠른 음성)",
            "default": 1,
            "example": 1
          },
          "audio_format": {
            "type": "string",
            "enum": [
              "wav",
              "mp3"
            ],
            "title": "Audio Format",
            "description": "스트리밍용 출력 오디오 형식.\n\n**WAV 형식:**\n- 비압축 PCM 오디오\n- 16비트 깊이, 모노 채널, **32000 Hz** 샘플링 속도\n- 청크 단위 전송: 첫 번째 청크는 WAV 헤더(size = 0xFFFFFFFF)를 포함하고, 이후 청크에는 원시 PCM 데이터가 이어집니다\n- 도착하는 즉시 오디오를 재생하고 싶을 때 권장\n\n**MP3 형식:**\n- 압축된 MPEG Layer III 오디오\n- 320 kbps 비트레이트, 44100 Hz 샘플링 속도\n- 청크 단위 전송: 각 청크에는 독립적으로 디코딩 가능한 MPEG 프레임이 포함됩니다\n- 대역폭이 제한된 클라이언트에 권장\n",
            "default": "wav",
            "example": "wav"
          }
        },
        "title": "OutputStream",
        "description": "스트리밍용 오디오 출력 설정. `target_lufs`로 LUFS 음량 정규화를 적용할 수 있으며, `volume`은 스트리밍 모드에서 사용할 수 없습니다."
      },
      "PauseComposeSegment": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "title": "Type",
            "description": "세그먼트 구분값입니다. 항상 `pause`입니다.",
            "default": "pause",
            "const": "pause"
          },
          "duration_seconds": {
            "type": "number",
            "maximum": 10,
            "title": "Duration Seconds",
            "description": "초 단위 쉼 길이입니다. 개별 쉼은 최대 10초, 모든 쉼의 합은 최대 60초입니다.",
            "example": 1.5,
            "exclusiveMinimum": 0
          }
        },
        "required": [
          "type",
          "duration_seconds"
        ],
        "title": "PauseComposeSegment",
        "description": "크레딧 차감 없이 삽입되는 무음 구간입니다.",
        "additionalProperties": false,
        "examples": [
          {
            "type": "pause",
            "duration_seconds": 1.5
          }
        ]
      },
      "PlanTier": {
        "type": "string",
        "enum": [
          "free",
          "lite",
          "plus",
          "custom"
        ],
        "title": "PlanTier",
        "description": "API 플랜.\n\n사용 가능한 값:\n- **free**: 제한된 크레딧의 무료 등급\n- **lite**: 중간 수준 크레딧의 라이트 플랜\n- **plus**: 높은 크레딧의 플러스 플랜\n- **custom**: 커스텀 엔터프라이즈 플랜"
      },
      "PresetPrompt": {
        "type": "object",
        "properties": {
          "emotion_type": {
            "type": "string",
            "title": "Emotion Type",
            "description": "프롬프트 유형을 식별하는 판별자 필드. 프리셋 기반 감정 제어를 위해 \"preset\"으로 설정해야 합니다.\n",
            "default": "preset",
            "const": "preset"
          },
          "emotion_preset": {
            "$ref": "#/components/schemas/EmotionEnum",
            "description": "생성된 음성에 적용할 감정 프리셋.\n\n지원되는 감정: normal, happy, sad, angry, whisper, toneup, tonedown\n\n/v2/voices API를 통해 각 보이스에 사용 가능한 감정을 확인하세요.\n",
            "default": "normal",
            "example": "normal"
          },
          "emotion_intensity": {
            "type": "number",
            "maximum": 2,
            "minimum": 0,
            "title": "Emotion Intensity",
            "description": "생성된 음성의 감정 표현 강도를 제어합니다.\n\n- 0.0: 완전히 중립적, 감정 색채 없음\n- 0.5: 미묘한 감정 힌트\n- 1.0: 표준 감정 표현(기본값)\n- 1.5: 강한 감정 강조\n- 2.0: 최대 강도, 매우 표현력 있음\n",
            "default": 1,
            "example": 1
          }
        },
        "title": "프리셋 프롬프트 (ssfm-v30)",
        "description": "생성된 음성의 감정 및 스타일 설정.",
        "additionalProperties": false
      },
      "Prompt": {
        "properties": {
          "emotion_preset": {
            "description": "적용할 감정 프리셋.\n\nssfm-v21 지원 감정: normal, happy, sad, angry\n\n/v2/voices API를 통해 각 보이스에 사용 가능한 감정을 확인하세요.\n",
            "example": "normal"
          },
          "emotion_intensity": {
            "description": "감정 표현 강도 제어(0.0~2.0).\n\n- 0.0: 완전히 중립적\n- 1.0: 표준 표현(기본값)\n- 2.0: 최대 강도\n",
            "example": 1
          }
        },
        "title": "프롬프트 (ssfm-v21)",
        "description": "생성된 음성의 감정 및 스타일 설정."
      },
      "RecommendedVoice": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "`tc_` prefix 가 붙은 타입캐스트 보이스 식별자. 텍스트 음성 변환 요청의 `voice_id` 로 사용할 수 있습니다.",
            "example": "tc_60e5426de8b95f1d3000d7b5"
          },
          "voice_name": {
            "type": "string",
            "title": "Voice Name",
            "description": "사람이 읽을 수 있는 보이스 이름.",
            "example": "Olivia"
          },
          "score": {
            "type": "number",
            "title": "Score",
            "description": "추천 관련도 점수. 값이 높을수록 검색어와 더 잘 맞는 후보입니다.",
            "example": 0.92
          }
        },
        "required": [
          "voice_id",
          "voice_name",
          "score"
        ],
        "title": "RecommendedVoice",
        "description": "`GET /v1/voices/recommendations` 응답의 보이스 추천 후보. 관련도 순서로 정렬됩니다."
      },
      "SmartPrompt": {
        "type": "object",
        "properties": {
          "emotion_type": {
            "type": "string",
            "title": "Emotion Type",
            "description": "프롬프트 유형을 식별하는 판별자 필드. 컨텍스트 인식 감정 추론을 위해 \"smart\"로 설정해야 합니다.\n",
            "default": "smart",
            "const": "smart"
          },
          "previous_text": {
            "type": "string",
            "title": "Previous Text",
            "description": "TTSRequest의 `text` 필드 이전에 오는 텍스트. 감정 추론을 위한 후방 컨텍스트를 제공합니다.\n\n모델은 흐름을 분석합니다: `previous_text` → `text`(합성됨) → `next_text`\n\n- 최대 2000자\n- 모델이 감정 빌드업과 컨텍스트를 이해하는 데 도움\n- 이전 컨텍스트가 없으면 비워 둡니다\n",
            "default": "",
            "example": "I feel like I'm walking on air and I just want to scream with joy!"
          },
          "next_text": {
            "type": "string",
            "title": "Next Text",
            "description": "TTSRequest의 `text` 필드 이후에 오는 텍스트. 감정 추론을 위한 전방 컨텍스트를 제공합니다.\n\n모델은 흐름을 분석합니다: `previous_text` → `text`(합성됨) → `next_text`\n\n- 최대 2000자\n- 모델이 감정 전환을 예측하는 데 도움\n- 다음 컨텍스트가 없으면 비워 둡니다\n",
            "default": "",
            "example": "I am literally bursting with happiness and I never want this feeling to end!"
          }
        },
        "title": "스마트 프롬프트 (ssfm-v30)",
        "description": "생성된 음성의 감정 및 스타일 설정.",
        "example": {
          "emotion_type": "smart",
          "previous_text": "I feel like I'm walking on air and I just want to scream with joy!",
          "next_text": "I am literally bursting with happiness and I never want this feeling to end!"
        },
        "additionalProperties": false
      },
      "SubscriptionResponse": {
        "type": "object",
        "properties": {
          "plan": {
            "$ref": "#/components/schemas/PlanTier",
            "description": "현재 구독 플랜명"
          },
          "credits": {
            "$ref": "#/components/schemas/Credits",
            "description": "크레딧 사용 정보"
          },
          "limits": {
            "$ref": "#/components/schemas/Limits",
            "description": "사용 제한 정보"
          }
        },
        "required": [
          "plan",
          "credits",
          "limits"
        ],
        "title": "SubscriptionResponse",
        "description": "구독 정보 응답 모델"
      },
      "TTSComposeSegment": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "타입캐스트 기본 보이스(`tc_`) 또는 커스텀 보이스(`uc_`) 식별자입니다.",
            "example": "tc_672c5f5ce59fac2a48faeaee"
          },
          "text": {
            "type": "string",
            "title": "Text",
            "description": "합성할 텍스트입니다. 모든 `tts` 세그먼트의 텍스트 합은 최대 2,000자입니다.",
            "example": "안녕하세요. 오늘의 소식입니다.",
            "maxLength": 2000,
            "minLength": 1
          },
          "model": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "이 세그먼트에 사용할 음성 모델입니다. 세그먼트마다 다른 모델을 사용할 수 있습니다.",
            "example": "ssfm-v30"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "ISO 639-3 언어 코드입니다. 생략하면 텍스트에서 언어를 감지합니다.",
            "example": "kor"
          },
          "prompt": {
            "title": "Prompt",
            "description": "이 세그먼트의 감정과 문맥 설정입니다.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SmartPrompt"
              },
              {
                "$ref": "#/components/schemas/PresetPrompt"
              },
              {
                "$ref": "#/components/schemas/Prompt"
              }
            ]
          },
          "output": {
            "$ref": "#/components/schemas/Output",
            "description": "이 세그먼트의 오디오 설정입니다. 모든 세그먼트에서 같은 `audio_format`을 사용해야 합니다."
          },
          "seed": {
            "title": "Seed",
            "description": "합성 결과 재현에 사용할 선택적 부호 없는 정수 시드입니다.",
            "example": 42,
            "anyOf": [
              {
                "type": "integer",
                "maximum": 4294967295,
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "type": "string",
            "title": "Type",
            "description": "세그먼트 구분값입니다. 항상 `tts`입니다.",
            "default": "tts",
            "const": "tts"
          }
        },
        "required": [
          "type",
          "voice_id",
          "text",
          "model"
        ],
        "title": "TTSComposeSegment",
        "description": "일반 텍스트 음성 변환 요청과 동일한 합성 옵션을 사용하는 음성 세그먼트입니다.",
        "examples": [
          {
            "type": "tts",
            "voice_id": "tc_672c5f5ce59fac2a48faeaee",
            "text": "안녕하세요. 오늘의 소식입니다.",
            "model": "ssfm-v30",
            "language": "kor",
            "output": {
              "audio_format": "wav"
            }
          }
        ]
      },
      "TTSModel": {
        "type": "string",
        "enum": [
          "ssfm-v30",
          "ssfm-v21"
        ],
        "title": "TTSModel",
        "description": "음성 합성에 사용할 TTS 모델 버전. 다양한 모델은 다양한 기능과 품질 수준을 제공합니다.\n\n사용 가능한 모델:\n- **ssfm-v30**: 향상된 플로우와 추가 감정 프리셋이 있는 최신 모델(권장)\n- **ssfm-v21**: 검증된 신뢰성과 일관된 품질을 갖춘 안정적인 모델\n"
      },
      "TTSRequest": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "보이스 식별자. 두 가지 prefix 를 지원합니다.\n\n- `tc_` - 기본 제공되는 타입캐스트 보이스 (예: `tc_60e5426de8b95f1d3000d7b5`). 사용 가능한 ID 는 [보이스 목록 조회](/docs/ko/api-reference/voices/list-voices) 를 참조하세요.\n- `uc_` - [퀵 클로닝](/docs/ko/api-reference/voices/instant-cloning) 으로 생성한 커스텀 보이스 (예: `uc_64a1b2c3d4e5f6a7b8c9d0e1`). 본인이 소유한 클로닝 보이스만 사용할 수 있습니다.\n\n대소문자 구분: prefix 는 소문자만 사용합니다.",
            "example": "tc_60e5426de8b95f1d3000d7b5"
          },
          "text": {
            "type": "string",
            "title": "Text",
            "description": "음성으로 변환할 텍스트. 최소 1자, 최대 2000자. 텍스트 길이에 따라 크레딧이 소비됩니다. 영어, 한국어, 일본어, 중국어를 포함한 여러 언어를 지원합니다. 특수 문자와 구두점은 자동으로 처리됩니다.",
            "example": "모든 것이 너무나 완벽해서 마치 꿈을 꾸는 것 같습니다.",
            "minLength": 1,
            "maxLength": 2000
          },
          "model": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "음성 합성에 사용할 보이스 모델.\n\n- **ssfm-v30**: 향상된 플로우와 추가 감정 프리셋이 있는 최신 모델(권장)\n- **ssfm-v21**: 빠르고 안정적인 모델로 신뢰할 수 있는 품질 제공\n",
            "example": "ssfm-v30"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "ISO 639-3 표준을 따르는 언어 코드. 대소문자 구분 안 함(\"KOR\"과 \"kor\" 모두 허용). 제공하지 않으면 텍스트 내용을 기반으로 자동 감지됩니다.\n\n<details>\n<summary><strong>ssfm-v30 지원 언어 (37개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | POR | 포르투갈어 |\n| BEN | 벵골어 | ITA | 이탈리아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | JPN | 일본어 | RUS | 러시아어 |\n| CES | 체코어 | KOR | 한국어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | MSA | 말레이어 | SPA | 스페인어 |\n| DEU | 독일어 | NAN | 민남어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | NOR | 노르웨이어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | PAN | 펀자브어 | THA | 태국어 |\n| FRA | 프랑스어 | POL | 폴란드어 | TUR | 터키어 |\n| HIN | 힌디어 | UKR | 우크라이나어 | VIE | 베트남어 |\n| HRV | 크로아티아어 | YUE | 광둥어 | ZHO | 중국어 |\n| HUN | 헝가리어 | | | | |\n\n</details>\n\n<details>\n<summary><strong>ssfm-v21 지원 언어 (27개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | ITA | 이탈리아어 | RUS | 러시아어 |\n| CES | 체코어 | JPN | 일본어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | KOR | 한국어 | SPA | 스페인어 |\n| DEU | 독일어 | MSA | 말레이어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | POL | 폴란드어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | POR | 포르투갈어 | UKR | 우크라이나어 |\n| FRA | 프랑스어 | HRV | 크로아티아어 | ZHO | 중국어 |\n\n</details>\n",
            "example": "kor"
          },
          "prompt": {
            "title": "Prompt",
            "description": "생성된 음성의 감정 및 스타일 설정, 감정 유형(happy/sad/angry/normal) 및 강도(0.0~2.0)를 포함하여 감정 표현을 제어합니다",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SmartPrompt"
              },
              {
                "$ref": "#/components/schemas/PresetPrompt"
              },
              {
                "$ref": "#/components/schemas/Prompt"
              }
            ],
            "discriminator": {
              "propertyName": "emotion_type",
              "mapping": {
                "preset": "#/components/schemas/PresetPrompt",
                "smart": "#/components/schemas/SmartPrompt"
              }
            }
          },
          "output": {
            "$ref": "#/components/schemas/Output",
            "description": "볼륨(0-200), 피치(-12~+12 반음), 템포(0.5배~2.0배), 형식(wav/mp3)을 포함한 오디오 출력 설정으로 최종 오디오 특성을 제어합니다"
          },
          "seed": {
            "type": "integer",
            "minimum": 0,
            "title": "Seed",
            "description": "재현 가능한 음성 생성을 위한 부호 없는 정수 시드. 동일한 시드와 동일한 입력 파라미터로 항상 같은 오디오 결과를 생성합니다.\n\n- 0 이상의 정수만 허용됩니다. 음수 값은 사용할 수 없습니다.\n- 생략하면 서버가 매번 랜덤 시드를 생성하여 약간의 변이가 발생합니다.",
            "example": 42,
            "anyOf": [
              {
                "type": "integer",
                "maximum": 4294967295,
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "format": "uint32"
          }
        },
        "required": [
          "voice_id",
          "text",
          "model"
        ],
        "title": "TTSRequest"
      },
      "TTSRequestStream": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "보이스 식별자. 두 가지 prefix 를 지원합니다.\n\n- `tc_` - 기본 제공되는 타입캐스트 보이스 (예: `tc_60e5426de8b95f1d3000d7b5`). 사용 가능한 ID 는 [보이스 목록 조회](/docs/ko/api-reference/voices/list-voices) 를 참조하세요.\n- `uc_` - [퀵 클로닝](/docs/ko/api-reference/voices/instant-cloning) 으로 생성한 커스텀 보이스 (예: `uc_64a1b2c3d4e5f6a7b8c9d0e1`). 본인이 소유한 클로닝 보이스만 사용할 수 있습니다.\n\n대소문자 구분: prefix 는 소문자만 사용합니다.",
            "example": "tc_60e5426de8b95f1d3000d7b5"
          },
          "text": {
            "type": "string",
            "title": "Text",
            "description": "음성으로 변환할 텍스트. 최소 1자, 최대 2000자. 텍스트 길이에 따라 크레딧이 소비됩니다. 영어, 한국어, 일본어, 중국어를 포함한 여러 언어를 지원합니다. 특수 문자와 구두점은 자동으로 처리됩니다.",
            "example": "모든 것이 너무나 완벽해서 마치 꿈을 꾸는 것 같습니다.",
            "minLength": 1,
            "maxLength": 2000
          },
          "model": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "음성 합성에 사용할 보이스 모델.\n\n- **ssfm-v30**: 향상된 플로우와 추가 감정 프리셋이 있는 최신 모델(권장)\n- **ssfm-v21**: 빠르고 안정적인 모델로 신뢰할 수 있는 품질 제공\n",
            "example": "ssfm-v30"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "ISO 639-3 표준을 따르는 언어 코드. 대소문자 구분 안 함(\"KOR\"과 \"kor\" 모두 허용). 제공하지 않으면 텍스트 내용을 기반으로 자동 감지됩니다.\n\n<details>\n<summary><strong>ssfm-v30 지원 언어 (37개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | POR | 포르투갈어 |\n| BEN | 벵골어 | ITA | 이탈리아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | JPN | 일본어 | RUS | 러시아어 |\n| CES | 체코어 | KOR | 한국어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | MSA | 말레이어 | SPA | 스페인어 |\n| DEU | 독일어 | NAN | 민남어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | NOR | 노르웨이어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | PAN | 펀자브어 | THA | 태국어 |\n| FRA | 프랑스어 | POL | 폴란드어 | TUR | 터키어 |\n| HIN | 힌디어 | UKR | 우크라이나어 | VIE | 베트남어 |\n| HRV | 크로아티아어 | YUE | 광둥어 | ZHO | 중국어 |\n| HUN | 헝가리어 | | | | |\n\n</details>\n\n<details>\n<summary><strong>ssfm-v21 지원 언어 (27개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | ITA | 이탈리아어 | RUS | 러시아어 |\n| CES | 체코어 | JPN | 일본어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | KOR | 한국어 | SPA | 스페인어 |\n| DEU | 독일어 | MSA | 말레이어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | POL | 폴란드어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | POR | 포르투갈어 | UKR | 우크라이나어 |\n| FRA | 프랑스어 | HRV | 크로아티아어 | ZHO | 중국어 |\n\n</details>\n",
            "example": "kor"
          },
          "prompt": {
            "title": "Prompt",
            "description": "생성된 음성의 감정 및 스타일 설정, 감정 유형(happy/sad/angry/normal) 및 강도(0.0~2.0)를 포함하여 감정 표현을 제어합니다",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SmartPrompt"
              },
              {
                "$ref": "#/components/schemas/PresetPrompt"
              },
              {
                "$ref": "#/components/schemas/Prompt"
              }
            ],
            "discriminator": {
              "propertyName": "emotion_type",
              "mapping": {
                "preset": "#/components/schemas/PresetPrompt",
                "smart": "#/components/schemas/SmartPrompt"
              }
            }
          },
          "output": {
            "$ref": "#/components/schemas/OutputStream",
            "description": "피치(-12 ~ +12 반음), 속도(0.5x ~ 2.0x), 형식(wav/mp3), target_lufs(-70 ~ 0 LUFS) 등 스트리밍 오디오 출력 설정. 참고: 스트리밍 모드에서는 volume을 사용할 수 없습니다."
          },
          "seed": {
            "type": "integer",
            "minimum": 0,
            "title": "Seed",
            "description": "재현 가능한 음성 생성을 위한 부호 없는 정수 시드. 동일한 시드와 동일한 입력 파라미터로 항상 같은 오디오 결과를 생성합니다.\n\n- 0 이상의 정수만 허용됩니다. 음수 값은 사용할 수 없습니다.\n- 생략하면 서버가 매번 랜덤 시드를 생성하여 약간의 변이가 발생합니다.",
            "example": 42,
            "anyOf": [
              {
                "type": "integer",
                "maximum": 4294967295,
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "format": "uint32"
          }
        },
        "required": [
          "voice_id",
          "text",
          "model"
        ],
        "title": "TTSRequestStream",
        "description": "스트리밍 텍스트 음성 변환 요청 파라미터"
      },
      "TTSRequestWith-timestamps": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "보이스 식별자. 두 가지 prefix 를 지원합니다.\n\n- `tc_` - 기본 제공되는 타입캐스트 보이스 (예: `tc_60e5426de8b95f1d3000d7b5`). 사용 가능한 ID 는 [보이스 목록 조회](/docs/ko/api-reference/voices/list-voices) 를 참조하세요.\n- `uc_` - [퀵 클로닝](/docs/ko/api-reference/voices/instant-cloning) 으로 생성한 커스텀 보이스 (예: `uc_64a1b2c3d4e5f6a7b8c9d0e1`). 본인이 소유한 클로닝 보이스만 사용할 수 있습니다.\n\n대소문자 구분: prefix 는 소문자만 사용합니다.",
            "example": "tc_60e5426de8b95f1d3000d7b5"
          },
          "text": {
            "type": "string",
            "title": "Text",
            "description": "음성으로 변환할 텍스트. 최소 1자, 최대 2000자. 텍스트 길이에 따라 크레딧이 소비됩니다. 영어, 한국어, 일본어, 중국어를 포함한 여러 언어를 지원합니다. 특수 문자와 구두점은 자동으로 처리됩니다.",
            "example": "모든 것이 너무나 완벽해서 마치 꿈을 꾸는 것 같습니다.",
            "minLength": 1,
            "maxLength": 2000
          },
          "model": {
            "$ref": "#/components/schemas/TTSModel",
            "description": "음성 합성에 사용할 보이스 모델.\n\n- **ssfm-v30**: 향상된 플로우와 추가 감정 프리셋이 있는 최신 모델(권장)\n- **ssfm-v21**: 빠르고 안정적인 모델로 신뢰할 수 있는 품질 제공\n",
            "example": "ssfm-v30"
          },
          "language": {
            "type": "string",
            "title": "Language",
            "description": "ISO 639-3 표준을 따르는 언어 코드. 대소문자 구분 안 함(\"KOR\"과 \"kor\" 모두 허용). 제공하지 않으면 텍스트 내용을 기반으로 자동 감지됩니다.\n\n<details>\n<summary><strong>ssfm-v30 지원 언어 (37개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | POR | 포르투갈어 |\n| BEN | 벵골어 | ITA | 이탈리아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | JPN | 일본어 | RUS | 러시아어 |\n| CES | 체코어 | KOR | 한국어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | MSA | 말레이어 | SPA | 스페인어 |\n| DEU | 독일어 | NAN | 민남어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | NOR | 노르웨이어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | PAN | 펀자브어 | THA | 태국어 |\n| FRA | 프랑스어 | POL | 폴란드어 | TUR | 터키어 |\n| HIN | 힌디어 | UKR | 우크라이나어 | VIE | 베트남어 |\n| HRV | 크로아티아어 | YUE | 광둥어 | ZHO | 중국어 |\n| HUN | 헝가리어 | | | | |\n\n</details>\n\n<details>\n<summary><strong>ssfm-v21 지원 언어 (27개)</strong></summary>\n\n| 코드 | 언어 | 코드 | 언어 | 코드 | 언어 |\n|------|----------|------|----------|------|----------|\n| ARA | 아랍어 | IND | 인도네시아어 | RON | 루마니아어 |\n| BUL | 불가리아어 | ITA | 이탈리아어 | RUS | 러시아어 |\n| CES | 체코어 | JPN | 일본어 | SLK | 슬로바키아어 |\n| DAN | 덴마크어 | KOR | 한국어 | SPA | 스페인어 |\n| DEU | 독일어 | MSA | 말레이어 | SWE | 스웨덴어 |\n| ELL | 그리스어 | NLD | 네덜란드어 | TAM | 타밀어 |\n| ENG | 영어 | POL | 폴란드어 | TGL | 타갈로그어 |\n| FIN | 핀란드어 | POR | 포르투갈어 | UKR | 우크라이나어 |\n| FRA | 프랑스어 | HRV | 크로아티아어 | ZHO | 중국어 |\n\n</details>\n\n> **타임스탬프 엔드포인트 주의.** 일본어(`jpn`) · 중국어(`zho`) 처럼 단어 사이에 공백이 없는 언어는 word 단위 정렬이 문장 전체를 하나의 구간으로 묶어 버립니다. 이런 언어에서는 항상 `granularity=char` 를 함께 지정해 문자 단위 타임스탬프를 받으세요.\n",
            "example": "kor"
          },
          "prompt": {
            "title": "Prompt",
            "description": "생성된 음성의 감정 및 스타일 설정, 감정 유형(happy/sad/angry/normal) 및 강도(0.0~2.0)를 포함하여 감정 표현을 제어합니다",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SmartPrompt"
              },
              {
                "$ref": "#/components/schemas/PresetPrompt"
              },
              {
                "$ref": "#/components/schemas/Prompt"
              }
            ],
            "discriminator": {
              "propertyName": "emotion_type",
              "mapping": {
                "preset": "#/components/schemas/PresetPrompt",
                "smart": "#/components/schemas/SmartPrompt"
              }
            }
          },
          "output": {
            "$ref": "#/components/schemas/Output",
            "description": "볼륨(0-200), 피치(-12~+12 반음), 템포(0.5배~2.0배), 형식(wav/mp3)을 포함한 오디오 출력 설정으로 최종 오디오 특성을 제어합니다"
          },
          "seed": {
            "type": "integer",
            "minimum": 0,
            "title": "Seed",
            "description": "재현 가능한 음성 생성을 위한 부호 없는 정수 시드. 동일한 시드와 동일한 입력 파라미터로 항상 같은 오디오 결과를 생성합니다.\n\n- 0 이상의 정수만 허용됩니다. 음수 값은 사용할 수 없습니다.\n- 생략하면 서버가 매번 랜덤 시드를 생성하여 약간의 변이가 발생합니다.",
            "example": 42,
            "anyOf": [
              {
                "type": "integer",
                "maximum": 4294967295,
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "format": "uint32"
          }
        },
        "required": [
          "voice_id",
          "text",
          "model"
        ],
        "title": "TTSRequestWith-timestamps",
        "description": "TTSRequestWith-timestamps parameters"
      },
      "TTSWithTimestampsResponse": {
        "type": "object",
        "properties": {
          "audio": {
            "type": "string",
            "title": "Audio",
            "description": "base64 로 인코딩된 오디오 바이트. `audio_format` 확장자로 디코딩해 파일로 저장할 수 있습니다."
          },
          "audio_format": {
            "type": "string",
            "enum": [
              "wav",
              "mp3"
            ],
            "title": "Audio Format",
            "description": "`audio` 필드의 오디오 인코딩 포맷 - `wav` 또는 `mp3` (요청의 `output.audio_format` 에 따라 결정)."
          },
          "audio_duration": {
            "type": "number",
            "title": "Audio Duration",
            "description": "생성된 오디오의 길이(초)."
          },
          "words": {
            "title": "Words",
            "description": "단어 단위 타임스탬프(문장부호 포함). 요청이 `granularity=char` 일 때는 `null`.",
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AlignmentSegmentWord"
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "characters": {
            "title": "Characters",
            "description": "문자 단위 타임스탬프(문장부호와 공백 포함). 요청이 `granularity=word` 일 때는 `null`.",
            "anyOf": [
              {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AlignmentSegmentCharacter"
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "audio",
          "audio_format",
          "audio_duration",
          "words",
          "characters"
        ],
        "title": "TTSWithTimestampsResponse",
        "description": "TTS 생성 + 타임스탬프 정렬 통합 응답."
      },
      "UseCasesEnum": {
        "type": "string",
        "enum": [
          "Announcer",
          "Anime",
          "Audiobook",
          "Conversational",
          "Documentary",
          "E-learning",
          "Rapper",
          "Game",
          "Tiktok/Reels",
          "News",
          "Podcast",
          "Voicemail",
          "Ads"
        ],
        "description": "콘텐츠 유형 필터링을 위한 보이스 사용 사례 카테고리. 각 보이스는 특정 콘텐츠 유형에 대한 적합성을 나타내는 하나 이상의 사용 사례로 태그됩니다.\n\n**사용 가능한 사용 사례:**\n- **Announcer**: 공공 발표 및 프레젠테이션\n- **Anime**: 애니메이션 보이스\n- **Audiobook**: 장문 내레이션 및 스토리텔링\n- **Conversational**: 챗봇 및 대화형 AI\n- **Documentary**: 다큐멘터리 내레이션 및 해설\n- **E-learning**: 교육 콘텐츠 및 튜토리얼\n- **Rapper**: 랩 및 음악 퍼포먼스\n- **Game**: 비디오 게임 보이스 및 내레이션\n- **Tiktok/Reels**: SNS 숏츠\n- **News**: 뉴스 방송\n- **Podcast**: 방송 및 팟캐스트 제작\n- **Voicemail**: IVR 시스템 및 음성 비서\n- **Ads**: 광고 및 홍보 콘텐츠\n"
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "loc": {
            "type": "array",
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VoiceType": {
        "type": "string",
        "enum": [
          "original",
          "custom"
        ],
        "title": "VoiceType",
        "description": "보이스 타입 분류.\n\n- `original` - 타입캐스트가 기본 제공하는 스톡 보이스로, 모든 계정에서 사용 가능합니다.\n- `custom` - 사용자가 본인의 샘플을 업로드하거나 클로닝해서 만든 보이스입니다."
      },
      "VoiceV2": {
        "type": "object",
        "properties": {
          "voice_id": {
            "type": "string",
            "title": "Voice Id",
            "description": "고유한 보이스 식별자. 기본 제공 보이스는 `tc_` prefix (예: `tc_60e5426de8b95f1d3000d7b5`), `POST /v1/voices/clone` 으로 만든 커스텀 보이스는 `uc_` prefix 를 사용합니다. 본인이 소유한 `uc_` 보이스도 `/v2/voices` 응답에 포함됩니다."
          },
          "voice_name": {
            "type": "string",
            "title": "Voice Name",
            "description": "사람이 읽을 수 있는 보이스 이름"
          },
          "models": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ModelInfo"
            },
            "title": "Models",
            "description": "사용 가능한 감정이 있는 지원되는 TTS 모델 목록(예: [{'version': 'ssfm-v21', 'emotions': ['happy', 'sad']}])"
          },
          "gender": {
            "description": "보이스 성별 분류(남성/여성)",
            "anyOf": [
              {
                "$ref": "#/components/schemas/GenderEnum"
              },
              {
                "type": "null"
              }
            ]
          },
          "age": {
            "description": "보이스 연령대 분류(어린이/청소년/청년/중년/노년)",
            "anyOf": [
              {
                "$ref": "#/components/schemas/AgeEnum"
              },
              {
                "type": "null"
              }
            ]
          },
          "use_cases": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "title": "Use Cases",
            "description": "이 보이스가 적합한 사용 사례 카테고리 목록\n\n## 보이스 이름 참고\n\n`voice_name` 필드는 영문으로만 반환됩니다. 아래 목록에서 한국어 표기를 확인하실 수 있습니다.\n\n<details>\n<summary><strong>보이스 이름 목록 펼치기 (542개)</strong></summary>\n\n| 영어 | 한국어 | 영어 | 한국어 | 영어 | 한국어 |\n| --- | --- | --- | --- | --- | --- |\n| Aaron | 에런 | Inhye | 인혜 | Piljae | 필재 |\n| Abigail | 아비게일 | Inseong | 인성 | Pyeonghwa | 평화 |\n| Ae-ran | 애란 | Instructor Han | 한유격 교관 | Rachel | 레이첼 |\n| Ael | 아엘 | Insun | 인선 | Ravi | 라비 |\n| Agatha | 아가사 | Jabbaba | 자바바 | Rayeon | 라연 |\n| Aiden | 에이든 | Jack | 잭 | Rebecca | 레베카 |\n| Alena | 알레나 | Jack-o’-Lantern | 잭오랜턴 | Reporter Bona | 다보나 기자 |\n| Alex | 알렉스 | Jackson | 잭슨 | Reporter Catalina | 카탈리나 기자 |\n| Amber | 엠버 | Jaeho | 재호 | Reporter Jinsub | 송진섭 기자 |\n| Anchor Hwa | 김경화 앵커 | Jaehun | 재훈 | Reporter Kang | 강수정 기자 |\n| Angela | 안젤라 | Jaejun | 재준 | Reporter Lee | 이승주 기자 |\n| Anja | 안냐 | Jaekyung | 재경 | Reporter Parkchan | 박찬 기자 |\n| Annabelle the Ghost | 귀신 애나벨 | Jaesun | 재선 | Rex | 렉스 |\n| Annie | 애니 | JaeYi | 재이 | Riley | 라일리 |\n| April | 에이프릴 | Jaeyoung | 재영 | Risan Ji | 지리산 |\n| Arang | 아랑 | Jain | 자인 | Rita | 리타 |\n| Ari | 아리 | Jake | 제이크 | River | 리버 |\n| Arin | 아린 | Janet | 재닛 | Robert | 로버트 |\n| Athena | 아테나 | Jangho | 장호 | Robo | 로보 |\n| Audrey | 오드리 | Jangwoon | 장운 | Romi | 로미 |\n| Avery | 에이버리 | Jechan | 제찬 | Ron | 론 |\n| Avong | 아봉 | Jeff | 제프 | Roro | 로로 |\n| Azzi | 아찌 | Jenna | 제나 | Rowoon | 로운 |\n| Babilon | 바빌론 | Jennifer | 제니퍼 | Royce | 로이스 |\n| Bell | 벨 | Jeong Choi | 최정 | Rudolph | 루돌프 |\n| Ben | 벤 | Jeongah | 정아 | Ruri | 루리 |\n| Benny | 베니 | JeongJin | 정진 | Rusty | 러스티 |\n| Beri | 베리 | Jeongseob | 정섭 | Ryan | 라이언 |\n| Billie | 빌리 | Jerome | 제롬 | Ryueun | 류은 |\n| Bomi | 이보미 | Jewby | 쥬비 | Sabrina the Witch | 마녀 사브리나 |\n| Bonggyu | 봉규 | Jian | 지안 | Saeron | 새론 |\n| Bongman Kim | 김봉만 | Jicheol | 지철 | Salty Chan-gu | 삐뚤어진 찬구 |\n| Bono | 보노 | Jihee | 지희 | Samantha | 사만다 |\n| Bora | 보라 | Jihoon | 지훈 | Sammy | 새미 |\n| Brad | 브래드 | Jihyun | 지현 | Sangdo | 상도 |\n| Bruce | 브루스 | Jimmy | 지미 | Sanghoon | 상훈 |\n| Buddy | 버디 | Jin | 진 | Sangwoo | 상우 |\n| Bumsoo | 범수 | Jinhan | 진한 | Santa | 산타 |\n| Buttaguy | 빠다가이 | Jinhang Kim | 김진행 | Santa Claus | 산타클로스 |\n| Caitlyn | 케이틀린 | Jinhee | 진희 | Santa Reporter | VJ 싼타 |\n| Callan | 칼란 | Jinhyuk | 진혁 | Sara | 세라 |\n| Camila | 카밀라 | Jinseo | 진서 | Sean | 션 |\n| Captain Bill | 캡틴 빌 | Jinung | 진웅 | SeHee | 세희 |\n| Carl | 칼 | Jinwoo | 진우 | Seheon | 세헌 |\n| Carlos | 카를로스 | Jiwoo | 지우 | Sejin | 세진 |\n| Carol | 캐롤 | Jiyoon | 지윤 | Sena | 세나 |\n| Catherine | 캐서린 | Jiyoung | 지영 | Seohee | 서희 |\n| Chad | 채드 | Jodie | 조디 | Seojin | 서진 |\n| Chaeah | 채아 | Jolly | 졸리 | Seojoon | 서준 |\n| Chan-gu | 찬구 | Jongdae | 종대 | Seok Choi | 최석 |\n| Changbae | 창배 | Jooeun | 주은 | SeokPil | 한석필 |\n| Changhee | 창희 | Joonghyun | 중현 | Seokpyo | 석표 |\n| Changmin | 창민 | Joongsik | 중식 | Seolhwa | 설화 |\n| Changsu | 박창수 | Joonkyu | 준규 | Seonha | 선하 |\n| Chanhyuk | 찬혁 | Joshua | 조슈아 | Seoyeon | 서연 |\n| Charlotte | 샬롯 | Juha | 주하 | Seoyoon | 서윤 |\n| Chase | 체이스 | Juho | 주호 | Seungah | 승아 |\n| Cheolhoon | 철훈 | Jungbong | 정봉 | Seungheon | 승헌 |\n| Cheolyong | 리철용 | Junghee | 정희 | Seungho | 승호 |\n| Cherry | 체리 | Jungjae | 정재 | Seunghwa | 승화 |\n| Chester | 체스터 | Jungmin | 정민 | Seungjae | 승재 |\n| Chiho | 치호 | Jungseok | 정석 | Seungmoon | 승문 |\n| Chloe | 클로이 | Jungsoon | 정순 | Seungwon | 승원 |\n| Choyeon | 강초연 교관 | Jungwon | 정원 | Seungyeon | 승연 |\n| Chungah | 청아 | Junhee | 준희 | Sewoo | 세우 |\n| Chunsik Kang | 강춘식 기자 | Junho | 준호 | Shana | 샤나 |\n| Claire | 클레어 | JunKi | 준기 | Sheriff Kim | 김반장 |\n| Classic Narrator | 미스타 변사 | Junsang | 준상 | Shinhe | 신혜 |\n| Cole | 콜 | Junseong | 준성 | Shinwook | 신욱 |\n| Cox | 콕스 | Justice Roh | 정의로 | Shotgun | 샷건 |\n| Cyrus | 사이러스 | Justin | 저스틴 | Simon | 사이먼 |\n| Dabin | 다빈 | Juwon | 주원 | Sindarin | 신다린 |\n| Daegil | 대길 | Juyoung | 주영 | Sio | 시오 |\n| Dahee | 다희 | K-Santa | 산타 할아버지 | Siwon | 시원 |\n| Dahyeon | 다현 | Kangil | 강일 | Siwoo | 시우 |\n| Damian | 데이미언 | Kanno | 칸노 | Siyeon | 시연 |\n| Dan | 댄 | Katie | 케이티 | Skylar | 스카일러 |\n| Dana | 다나 | Kelly | 켈리 | Slushy | 슬러시 |\n| Dasom | 다솜 | Kelsey | 켈시 | Smoke | 스모크 |\n| David | 데이비드 | Kevin | 케빈 | Sohye | 소혜 |\n| Dean | 딘 | Keybo | 키보 | Sojin | 소진 |\n| Deokhwan | 덕환 | Kijang Kim | 김기장 | Soobin | 수빈 |\n| Dohan | 도한 | Killian the Vampire | 뱀파이어 킬리언 | Sookhee | 숙희 |\n| Dohee | 도희 | Kiseob | 기섭 | Sooni | 순이 |\n| Dohyun | 도현 | Klip Kim | 클립 킴 | Sophia | 소피아 |\n| Dollar Jr. | 달러 주니어 | Koombo | 쿰보 | Sora | 소라 |\n| Doug | 더그 | Kristen | 크리스틴 | Soye | 소예 |\n| Doughnut | 도넛 | Kukhee | 국희 | Soyi | 소이 |\n| DU5T | 더스트 | Kwonil | 권일 | Soyoung | 소영 |\n| Duckchun | 덕춘 | Kyumin | 규민 | Soyul | 소율 |\n| Duke | 듀크 | Kyungho | 경호 | Spice | 스파이스 |\n| Dukgu | 덕구 | Kyungsoo | 경수 | Sportscaster Kang | 강수정 캐스터 |\n| Duman | 두만 | Kyungsook | 경숙 | Sportscaster Tony | 이영광 캐스터 |\n| Dupil | 곽두필 | Lady Cho | 단희빈 | Starling | 스탈링 |\n| DVZY | 데이지 | Lala | 라라 | Stephanie | 스테파니 |\n| Dylan | 딜런 | Lamie | 라미 | Storyteller Jinsub | 송진섭 스토리텔러 |\n| E-seller Sherri | 쇼린이 | Landon | 랜던 | Sua | 수아 |\n| Echo | 에코 | Larry | 래리 | Suho | 수호 |\n| Edward | 에드워드 | Leo | 레오 | Suji | 수지 |\n| Elias | 엘리아스 | Liam | 리암 | Sujin | 수진 |\n| Elise | 엘리스 | Lindsay | 린지 | Sullock Hong | 홍설록 |\n| Ella | 엘라 | Liz | 리즈 | Sumin | 수민 |\n| Eman | 이만 | Lloyd | 로이드 | Sungbae | 성배 |\n| Emma | 엠마 | Logan | 로건 | Sunggyu | 성규 |\n| Eunbin | 은빈 | Lucille | 루실 | Sungho | 성호 |\n| Eunchae | 은채 | Luna | 루나 | Sunghoon | 성훈 |\n| Eunha | 은하 | Lydia | 리디아 | Sunghyun | 성현 |\n| Eunsol | 은솔 | Maddie | 매디 | Sungjun | 홈쇼핑 성준 |\n| Frankenstein | 프랑켄슈타인 | Maisie | 메이시 | Sungkwon | 성권 |\n| Furnando | 터르난도 | Margaret | 마가렛 | Sungtae | 성태 |\n| Gaeul | 가을 | Margot | 마고 | Sungwook | 성욱 |\n| Gahee | 가희 | Matthew | 매튜 | Sunyoung | 선영 |\n| George | 조지 | MBTI EF (F) | MBTI EF 여 | Suyoon | 수윤 |\n| GeumHee | 금희 | MBTI EF (M) | MBTI EF 남 | Sylvia | 실비아 |\n| Geunhyeok | 근혁 | MBTI ET (F) | MBTI ET 여 | Taebaek | 장태백 |\n| Geunseok | 근석 | MBTI ET (M) | MBTI ET 남 | Taeji | 태지 |\n| Geunwoo | 근우 | MBTI IF (F) | MBTI IF 여 | Taejoong | 태중 |\n| Geunyeong | 근영 | MBTI IF (M) | MBTI IF 남 | Taemin | 태민 |\n| Ggami | 까미 | MBTI IT (F) | MBTI IT 여 | Taesub | 태섭 |\n| Ggomi | 꼬미 | MBTI IT (M) | MBTI IT 남 | Taewoo | 태우 |\n| Glenda | 글렌다 | MC Kong | MC콩 | Teal | 틸 |\n| Goat Kim | 김고트 | MC TypeCast | MC 타캐 | Tessa | 테사 |\n| Gongchul | 공철 | Mia | 미아 | Tian | 티안 |\n| Gowoon | 고운 | Michael | 마이클 | Tim | 팀 |\n| Grace | 그레이스 | Mija | 오미자 | Tina | 티나 |\n| Graham | 그레이엄 | Mijin | 미진 | Toby | 토비 |\n| Gunseok | 건석 | Mikyung | 미경 | Tommy | 토미 |\n| Gunwoo | 건우 | Millie | 밀리 | Tyson | 타이슨 |\n| Guri | 구리 | Minchae | 민채 | UiChan | 의찬이 |\n| Gus | 거스 | Minji | 민지 | Uncle Hank | 행크 |\n| Ha Eun | 하은 | Minjoon | 민준 | Valerie | 밸러리 |\n| Haejun | 해준 | Minju | 민주 | Valkyrie | 발키리 |\n| Haerang | 해랑 | Minjung | 민정 | Vanessa | 바네사 |\n| Hailey | 헤일리 | Minsang | 민상 | Verna | 베르나 |\n| Hajun | 하준 | Minsu | 민수 | Victoria | 빅토리아 |\n| Hakchul | 학철 | Mio | 미오 | Viktor | 빅토르 |\n| Hamchu | 햄쮸 | Miran Choi | 최미란 | Vincent | 빈센트 |\n| Han Taesung Caster | 한태성 캐스터 | Mirine | 미리내 | Vivien | 비비안 |\n| Hana | 하나 | Miseon | 미선 | Wade | 웨이드 |\n| Hangyeol | 한결 | Miso | 미소 | Walter | 월터 |\n| Hanjun | 한준 | Mister Gop | 미스터 갑 | Wangkwon | 왕권 |\n| Hanna | 한나 | Monggun | 몽군 | Weather Reporter Sky | 하늘 캐스터 |\n| Hans | 한스 | Moonjung | 문정 | West | 웨스트 |\n| Hansol | 한솔 | Mooyeol | 무열 | Wonho | 원호 |\n| Hanyoung | 한영 | Morgan | 모건 | Wonkyung | 원경 |\n| Harin | 하린 | Moru | 머루 | Wonwoo | 원우 |\n| Harper | 하퍼 | Mrs. Claus | 미세스 클로스 | Wooju | 우주 |\n| Hayul | 하율 | Munseok | 문석 | Woosung | 우성 |\n| Heejoon | 희준 | Munsu | 문수 | Xavier | 자비에르 |\n| Helena | 헬레나 | Myeonghee | 명희 | Yeeun | 예은 |\n| Henry | 헨리 | Myungil | 명일 | Yejin | 예진 |\n| Homun Sim | 심호문 | Myungjoo | 명주 | Yejoon | 예준 |\n| Hoon | 훈 | Naeun | 나은 | YeLin | 예린 |\n| Hosik | 호식 | Najin | 나진 | Yena | 예나 |\n| Hosun | 호선 | Namjoon | 남준 | Yeonah | 연아 |\n| Hoyoung | 호영 | Nana | 나나 | Yeonggeol | 영걸 |\n| Hugh | 휴 | Nari | 개나리 | Yeonhwa | 연화 |\n| Hwimin | 휘민 | Nathan | 네이선 | Yeonja | 연자 |\n| Hyejung | 혜정 | Neel | 닐 | Yeonsuh | 연서 |\n| Hyelee | 혜리 | Neoguard | 네오가드 | Yeonwoo | 연우 |\n| Hyemin | 혜민 | News anchor Jinsub | 송진섭 앵커 | Yeseul | 예슬 |\n| Hyena | 혜나 | Newscaster John | 존 앵커 | Yongsik | 용식이 |\n| Hyeongjin | 형진 | Nia | 니아 | Yoonseo | 윤서 |\n| Hyera | 혜라 | Noa | 노아 | Yoonsung | 윤성 |\n| Hyesu | 홈쇼핑 혜수 | Noel | 노엘 | Younggil | 영길 |\n| Hyewon | 혜원 | Noeul | 노을 | Younghee | 영희 |\n| Hyun | 현 | Norah | 노라 | Younghwan | 영환 |\n| Hyunji | 현지 | Nova | 노바 | Youngji | 영지 |\n| Hyunjin | 현진 | Old radio | 레디오 | Youngkyu | 영규 |\n| Hyunju | 현주 | Oliver | 올리버 | Youngmok | 영목 |\n| Hyunkyung | 현경 | Olivia | 올리비아 | Yubin | 유빈 |\n| Hyunmin | 현민 | Oscar | 오스카 | Yujin | 유진 |\n| Hyunseung | 현승 | Owen | 오언 | Yumi | 유미 |\n| HyunWoo | 현우 | P-0150N | 포이즌 | Yumin | 유민 |\n| Ian | 이안 | Pacang | 파캉 | Yunbin | 윤빈 |\n| Icarus | 이카루스 | Paige | 페이지 | Yunjeong | 윤정 |\n| Igyeom | 이겸 | Pangpang | 팡팡 | Yura | 유라 |\n| Ijun | 이준 | Patricia | 패트리샤 | Yuri | 유리 |\n| Ilho | 일호 | Patrick | 패트릭 | Yuseong | 유성 |\n| Ina | 이나 | Peter | 피터 | Zoey | 조이 |\n| Inhwa | 인화 | Philip | 필립 |  |  |\n\n</details>\n"
          },
          "voice_type": {
            "$ref": "#/components/schemas/VoiceType",
            "description": "보이스 타입 - `original` 은 타입캐스트가 기본 제공하는 스톡 보이스, `custom` 은 사용자가 업로드/클론한 보이스입니다."
          }
        },
        "required": [
          "voice_id",
          "voice_name",
          "models",
          "voice_type"
        ],
        "title": "VoiceV2",
        "description": "모델별로 그룹화된 감정과 향상된 메타데이터가 있는 V2 보이스 응답 모델"
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-KEY",
        "description": "인증을 위한 API 키. 타입캐스트 API 콘솔에서 API 키를 생성할 수 있습니다."
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  }
}
```
