curl --request POST \
--url https://api.typecast.ai/v1/text-to-speech/compose \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--output output.wav \
--data @- <<EOF
{
"segments": [
{
"type": "tts",
"voice_id": "tc_672c5f5ce59fac2a48faeaee",
"text": "Welcome to today's update.",
"model": "ssfm-v30",
"language": "eng",
"output": { "audio_format": "wav" }
},
{ "type": "pause", "duration_seconds": 1.5 },
{
"type": "tts",
"voice_id": "tc_66aca22c7d31e45ff05ff418",
"text": "Here is the first story.",
"model": "ssfm-v30",
"language": "eng",
"output": { "audio_format": "wav" }
}
]
}
EOFimport requests
response = requests.post(
"https://api.typecast.ai/v1/text-to-speech/compose",
headers={"X-API-KEY": "<api-key>"},
json={
"segments": [
{
"type": "tts",
"voice_id": "tc_672c5f5ce59fac2a48faeaee",
"text": "Welcome to today's update.",
"model": "ssfm-v30",
"language": "eng",
"output": {"audio_format": "wav"},
},
{"type": "pause", "duration_seconds": 1.5},
{
"type": "tts",
"voice_id": "tc_66aca22c7d31e45ff05ff418",
"text": "Here is the first story.",
"model": "ssfm-v30",
"language": "eng",
"output": {"audio_format": "wav"},
},
]
},
timeout=120,
)
response.raise_for_status()
with open("output.wav", "wb") as audio_file:
audio_file.write(response.content)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
segments: [
{
type: 'tts',
voice_id: 'tc_672c5f5ce59fac2a48faeaee',
text: 'Welcome to today\'s update.',
model: 'ssfm-v30',
language: 'eng',
output: {audio_format: 'wav'}
},
{type: 'pause', duration_seconds: 1.5},
{
type: 'tts',
voice_id: 'tc_66aca22c7d31e45ff05ff418',
text: 'Here is the first story.',
model: 'ssfm-v30',
language: 'eng',
output: {audio_format: 'wav'}
}
]
})
};
fetch('https://api.typecast.ai/v1/text-to-speech/compose', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.typecast.ai/v1/text-to-speech/compose",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'segments' => [
[
'type' => 'tts',
'voice_id' => 'tc_672c5f5ce59fac2a48faeaee',
'text' => 'Welcome to today\'s update.',
'model' => 'ssfm-v30',
'language' => 'eng',
'output' => [
'audio_format' => 'wav'
]
],
[
'type' => 'pause',
'duration_seconds' => 1.5
],
[
'type' => 'tts',
'voice_id' => 'tc_66aca22c7d31e45ff05ff418',
'text' => 'Here is the first story.',
'model' => 'ssfm-v30',
'language' => 'eng',
'output' => [
'audio_format' => 'wav'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.typecast.ai/v1/text-to-speech/compose"
payload := strings.NewReader("{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.typecast.ai/v1/text-to-speech/compose")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.typecast.ai/v1/text-to-speech/compose")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body"[Binary audio data - WAV file content]"{
"detail": "Invalid API key"
}{
"detail": "Insufficient credit"
}{
"detail": "Invalid request format"
}{
"detail": "An unexpected error occurred"
}Compose Text To Speech
Generate multiple speech segments and pauses as one audio file. Add tts and pause objects to segments in the order they should appear. Each tts segment accepts the same voice, model, prompt, and output settings as POST /v1/text-to-speech; voices and models may differ between segments.
Limits
- Up to 50 total segments, with at least one
ttssegment - Up to 2,000 characters across all
ttssegments - Up to 10 seconds per pause and 60 seconds across all pauses
- All
ttssegments must use the sameaudio_format
Credits are charged only for the combined text length; pauses are free. Segments are synthesized in parallel and returned in input order. If any segment fails, the entire request fails and no credits are charged.
Response
A successful request returns the composed audio directly as binary data, not JSON. The response Content-Type is audio/wav or audio/mpeg, based on the audio_format requested by the segments.
curl --request POST \
--url https://api.typecast.ai/v1/text-to-speech/compose \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--output output.wav \
--data @- <<EOF
{
"segments": [
{
"type": "tts",
"voice_id": "tc_672c5f5ce59fac2a48faeaee",
"text": "Welcome to today's update.",
"model": "ssfm-v30",
"language": "eng",
"output": { "audio_format": "wav" }
},
{ "type": "pause", "duration_seconds": 1.5 },
{
"type": "tts",
"voice_id": "tc_66aca22c7d31e45ff05ff418",
"text": "Here is the first story.",
"model": "ssfm-v30",
"language": "eng",
"output": { "audio_format": "wav" }
}
]
}
EOFimport requests
response = requests.post(
"https://api.typecast.ai/v1/text-to-speech/compose",
headers={"X-API-KEY": "<api-key>"},
json={
"segments": [
{
"type": "tts",
"voice_id": "tc_672c5f5ce59fac2a48faeaee",
"text": "Welcome to today's update.",
"model": "ssfm-v30",
"language": "eng",
"output": {"audio_format": "wav"},
},
{"type": "pause", "duration_seconds": 1.5},
{
"type": "tts",
"voice_id": "tc_66aca22c7d31e45ff05ff418",
"text": "Here is the first story.",
"model": "ssfm-v30",
"language": "eng",
"output": {"audio_format": "wav"},
},
]
},
timeout=120,
)
response.raise_for_status()
with open("output.wav", "wb") as audio_file:
audio_file.write(response.content)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
segments: [
{
type: 'tts',
voice_id: 'tc_672c5f5ce59fac2a48faeaee',
text: 'Welcome to today\'s update.',
model: 'ssfm-v30',
language: 'eng',
output: {audio_format: 'wav'}
},
{type: 'pause', duration_seconds: 1.5},
{
type: 'tts',
voice_id: 'tc_66aca22c7d31e45ff05ff418',
text: 'Here is the first story.',
model: 'ssfm-v30',
language: 'eng',
output: {audio_format: 'wav'}
}
]
})
};
fetch('https://api.typecast.ai/v1/text-to-speech/compose', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.typecast.ai/v1/text-to-speech/compose",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'segments' => [
[
'type' => 'tts',
'voice_id' => 'tc_672c5f5ce59fac2a48faeaee',
'text' => 'Welcome to today\'s update.',
'model' => 'ssfm-v30',
'language' => 'eng',
'output' => [
'audio_format' => 'wav'
]
],
[
'type' => 'pause',
'duration_seconds' => 1.5
],
[
'type' => 'tts',
'voice_id' => 'tc_66aca22c7d31e45ff05ff418',
'text' => 'Here is the first story.',
'model' => 'ssfm-v30',
'language' => 'eng',
'output' => [
'audio_format' => 'wav'
]
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.typecast.ai/v1/text-to-speech/compose"
payload := strings.NewReader("{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.typecast.ai/v1/text-to-speech/compose")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.typecast.ai/v1/text-to-speech/compose")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"segments\": [\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n \"text\": \"Welcome to today's update.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n },\n {\n \"type\": \"pause\",\n \"duration_seconds\": 1.5\n },\n {\n \"type\": \"tts\",\n \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n \"text\": \"Here is the first story.\",\n \"model\": \"ssfm-v30\",\n \"language\": \"eng\",\n \"output\": {\n \"audio_format\": \"wav\"\n }\n }\n ]\n}"
response = http.request(request)
puts response.read_body"[Binary audio data - WAV file content]"{
"detail": "Invalid API key"
}{
"detail": "Insufficient credit"
}{
"detail": "Invalid request format"
}{
"detail": "An unexpected error occurred"
}Authorizations
API key for authentication. You can obtain an API key from the Typecast API Console.
Body
A sequence of speech and pause segments returned as one audio file.
Speech and pause segments in output order. Provide 1–50 segments with at least one tts segment.
1 - 50 elementsA speech segment with the same synthesis options as a standard text-to-speech request.
- TTSComposeSegment
- PauseComposeSegment
Show child attributes
Show child attributes
{
"type": "tts",
"voice_id": "tc_672c5f5ce59fac2a48faeaee",
"text": "Welcome to today's update.",
"model": "ssfm-v30",
"language": "eng",
"output": { "audio_format": "wav" }
}
Response
Binary composed audio. The media type matches the requested audio_format.
The response is of type file.