> For clean Markdown of any page, append `.md` to the page URL. > For a complete documentation index, see https://docs.sarvam.ai/llms.txt. > For full documentation content in one file, see https://docs.sarvam.ai/llms-full.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.sarvam.ai/_mcp/server. # REST Stream POST https://api.sarvam.ai/voices/clone/stream Content-Type: multipart/form-data Converts the input text into a streamed spoken audio response using a cloned voice. **Step 1:** Create a voice with `POST /voices/create` and save the returned `voice_id`. **Step 2:** Pass that `voice_id` with `text` and `language_code` to this endpoint. The response is a binary audio stream (not JSON), so you can begin playback as soon as the first sentence is ready. Accepts `multipart/form-data`. **Base URL:** `https://api.sarvam.ai`. **Auth:** send your key in the `api-subscription-key` header (recommended); `Authorization: Bearer ` is also accepted. **Streaming codecs:** `mp3` (default), `wav`, `linear16`, `mulaw`, `alaw`. `flac`, `aac`, and `opus` are not supported on this endpoint because each sentence would be a complete container that cannot be concatenated. Quality checks (QC/VAD) and duration bounds (`min_audio_duration` / `max_audio_duration`) are not accepted — the stream path optimizes for time-to-first-byte. **Billing:** charged per character of `text` against the `text_to_speech_voice_cloning` API. See the [pricing page](https://docs.sarvam.ai/api/getting-started/pricing). Reference: https://docs.sarvam.ai/api-reference/voice-cloning/clone-stream ## Authentication - `api-subscription-key` header (required) — API Key authentication via header ## Request ### Body (multipart/form-data) This endpoint expects a multipart form. - `voice_id` (string, required) — Required cloned voice ID (`svc-{uuid}`). Create one with `POST /voices/create`, or use a voice from the same organization's Content Studio Voice Library. - `text` (string, required) — Text to synthesize in the cloned voice. Native scripts and code-mixed text are supported. Maximum 1000 characters; longer text is rejected with a 400. Split longer input client-side and synthesize it in parts. - `language_code` (enum, required) — BCP-47 language code for the synthesized output. The cloned voice can speak any supported language, regardless of the reference clip's language (cross-lingual cloning). **Available Options:** - `as-IN`: Assamese - `bn-IN`: Bengali - `en-IN`: English (Indian) - `gu-IN`: Gujarati - `hi-IN`: Hindi - `kn-IN`: Kannada - `ml-IN`: Malayalam - `mr-IN`: Marathi - `od-IN`: Odia - `pa-IN`: Punjabi - `ta-IN`: Tamil - `te-IN`: Telugu - `pace` (double, optional) — Speech speed multiplier. `1.0` is natural speed; `0.5` to `2.0` is accepted. Speed is adjusted without changing pitch. - `output_audio_codec` (enum, optional) — Audio codec for the streamed output. Default is `mp3`. - `mp3`: Self-framing; clients can decode and play as chunks arrive. Recommended. - `wav`: One RIFF header (unknown length), then raw PCM chunks. - `linear16`: Raw 16-bit PCM (no header). - `mulaw` / `alaw`: 8-bit telephony codecs for IVR pipelines. - `output_audio_bitrate` (enum, optional) — Bitrate for lossy codecs (`mp3`). Default is `128k`. Options: `32k`, `64k`, `96k`, `128k`, `192k`. - `speech_sample_rate` (enum, optional) — Output sample rate in Hz. Supported values are 8000, 16000, 22050, 24000, 32000, 44100, 48000. If omitted, the API returns 24000 Hz. - `enable_text_normalization` (boolean, optional) — Enable pre-TTS text normalization: numbers, currencies and dates are converted to their spoken form before synthesis (e.g. `9840950950` becomes the spoken digit sequence). Defaults to the server-side setting. ## Response ### 200 Success. Returns a streamed audio response in the requested format (e.g., `audio/mpeg` for MP3, `audio/wav` for WAV). - File download. ## Errors ### 400 Bad Request Error Bad Request. Missing or invalid `voice_id`, empty `text`, or unsupported stream codec. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 402 Payment Required Error Quota Exceeded - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 403 Forbidden Error Forbidden. The `api-subscription-key` is missing, malformed, invalid. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 422 Unprocessable Entity Error Unprocessable Entity. The form fields failed validation; the body is invalid. Check enum values and required fields. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 429 Too Many Requests Error Rate Limit Exceeded. Retry with exponential backoff. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 500 Internal Server Error Internal Server Error. Model unavailable or generation failed before the first audio byte. Retry once; if it persists, log the `request_id` and contact support. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 502 Bad Gateway Error Billing Service Unavailable. The billing service could not record usage for this request. Retry with exponential backoff; if it persists, contact support with the request_id. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 503 Service Unavailable Error Model Unavailable or Overloaded. The model call failed or the model is overloaded. Retry with exponential backoff. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ### 504 Gateway Timeout Error Gateway Timeout. The model call timed out. Retry with exponential backoff. - `error` (Sarvam_Model_API_ErrorDetails, required) — Error details ## Types ### Sarvam_Model_API_ErrorDetails - `request_id` (string, required, nullable) - `message` (string, required) — Message describing the error - `code` (enum, required) — Error code for the specific error that has occurred. Refer to the error code documentation for more details. - Allowed values: `invalid_request_error`, `internal_server_error`, `unprocessable_entity_error`, `insufficient_quota_error`, `invalid_api_key_error`, `authentication_error`, `not_found_error`, `rate_limit_exceeded_error`, `model_call_error`, `gateway_timeout_error`, `billing_service_unavailable_error` ## Examples **Request** ```json { "language_code": "hi-IN", "output_audio_codec": "mp3", "text": "नमस्ते। यह एक स्ट्रीमिंग टेस्ट है।", "voice_id": "svc-123e4567-e89b-12d3-a456-426614174000" } ``` **SDK Code** ```typescript import { SarvamAIClient } from "sarvamai"; import fs from "fs"; const client = new SarvamAIClient({ apiSubscriptionKey: process.env.SARVAM_API_KEY, }); const response = await client.voiceCloning.textToSpeechStream({ voiceId: "svc-123e4567-e89b-12d3-a456-426614174000", text: "\u0928\u092e\u0938\u094d\u0924\u0947\u0964 \u092f\u0939 \u090f\u0915 \u0938\u094d\u091f\u094d\u0930\u0940\u092e\u093f\u0902\u0917 \u091f\u0947\u0938\u094d\u091f \u0939\u0948\u0964", language_code: "hi-IN", output_audio_codec: "mp3", }); const audio = Buffer.from(await response.arrayBuffer()); fs.writeFileSync("output.mp3", audio); ``` ```python import requests url = "https://api.sarvam.ai/voices/clone/stream" payload = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"enable_text_normalization\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language_code\"\r\n\r\nhi-IN\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_bitrate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_codec\"\r\n\r\nmp3\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"pace\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"speech_sample_rate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nनमस्ते। यह एक स्ट्रीमिंग टेस्ट है।\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"voice_id\"\r\n\r\nsvc-123e4567-e89b-12d3-a456-426614174000\r\n-----011000010111000001101001--\r\n" headers = { "api-subscription-key": "", "Content-Type": "multipart/form-data; boundary=---011000010111000001101001" } response = requests.post(url, data=payload, headers=headers) print(response.json()) ``` ```go package main import ( "fmt" "strings" "net/http" "io" ) func main() { url := "https://api.sarvam.ai/voices/clone/stream" payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"enable_text_normalization\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language_code\"\r\n\r\nhi-IN\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_bitrate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_codec\"\r\n\r\nmp3\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"pace\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"speech_sample_rate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nनमस्ते। यह एक स्ट्रीमिंग टेस्ट है।\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"voice_id\"\r\n\r\nsvc-123e4567-e89b-12d3-a456-426614174000\r\n-----011000010111000001101001--\r\n") req, _ := http.NewRequest("POST", url, payload) req.Header.Add("api-subscription-key", "") req.Header.Add("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.sarvam.ai/voices/clone/stream") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Post.new(url) request["api-subscription-key"] = '' request["Content-Type"] = 'multipart/form-data; boundary=---011000010111000001101001' request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"enable_text_normalization\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language_code\"\r\n\r\nhi-IN\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_bitrate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_codec\"\r\n\r\nmp3\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"pace\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"speech_sample_rate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nनमस्ते। यह एक स्ट्रीमिंग टेस्ट है।\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"voice_id\"\r\n\r\nsvc-123e4567-e89b-12d3-a456-426614174000\r\n-----011000010111000001101001--\r\n" response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.post("https://api.sarvam.ai/voices/clone/stream") .header("api-subscription-key", "") .header("Content-Type", "multipart/form-data; boundary=---011000010111000001101001") .body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"enable_text_normalization\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language_code\"\r\n\r\nhi-IN\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_bitrate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_codec\"\r\n\r\nmp3\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"pace\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"speech_sample_rate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nनमस्ते। यह एक स्ट्रीमिंग टेस्ट है।\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"voice_id\"\r\n\r\nsvc-123e4567-e89b-12d3-a456-426614174000\r\n-----011000010111000001101001--\r\n") .asString(); ``` ```php request('POST', 'https://api.sarvam.ai/voices/clone/stream', [ 'multipart' => [ [ 'name' => 'language_code', 'contents' => 'hi-IN' ], [ 'name' => 'output_audio_codec', 'contents' => 'mp3' ], [ 'name' => 'text', 'contents' => 'नमस्ते। यह एक स्ट्रीमिंग टेस्ट है।' ], [ 'name' => 'voice_id', 'contents' => 'svc-123e4567-e89b-12d3-a456-426614174000' ] ] 'headers' => [ 'api-subscription-key' => '', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.sarvam.ai/voices/clone/stream"); var request = new RestRequest(Method.POST); request.AddHeader("api-subscription-key", ""); request.AddParameter("multipart/form-data; boundary=---011000010111000001101001", "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"enable_text_normalization\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"language_code\"\r\n\r\nhi-IN\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_bitrate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"output_audio_codec\"\r\n\r\nmp3\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"pace\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"speech_sample_rate\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"text\"\r\n\r\nनमस्ते। यह एक स्ट्रीमिंग टेस्ट है।\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"voice_id\"\r\n\r\nsvc-123e4567-e89b-12d3-a456-426614174000\r\n-----011000010111000001101001--\r\n", ParameterType.RequestBody); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = [ "api-subscription-key": "", "Content-Type": "multipart/form-data; boundary=---011000010111000001101001" ] let parameters = [ [ "name": "enable_text_normalization", "value": ], [ "name": "language_code", "value": "hi-IN" ], [ "name": "output_audio_bitrate", "value": ], [ "name": "output_audio_codec", "value": "mp3" ], [ "name": "pace", "value": ], [ "name": "speech_sample_rate", "value": ], [ "name": "text", "value": "नमस्ते। यह एक स्ट्रीमिंग टेस्ट है।" ], [ "name": "voice_id", "value": "svc-123e4567-e89b-12d3-a456-426614174000" ] ] let boundary = "---011000010111000001101001" var body = "" var error: NSError? = nil for param in parameters { let paramName = param["name"]! body += "--\(boundary)\r\n" body += "Content-Disposition:form-data; name=\"\(paramName)\"" if let filename = param["fileName"] { let contentType = param["content-type"]! let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8) if (error != nil) { print(error as Any) } body += "; filename=\"\(filename)\"\r\n" body += "Content-Type: \(contentType)\r\n\r\n" body += fileContent } else if let paramValue = param["value"] { body += "\r\n\r\n\(paramValue)" } } let request = NSMutableURLRequest(url: NSURL(string: "https://api.sarvam.ai/voices/clone/stream")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "POST" request.allHTTPHeaderFields = headers request.httpBody = postData as Data let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```