curl --request POST \
--url https://api.infery.ai/v1/audio/speech \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"input": "<string>",
"voice": "<string>",
"instructions": "<string>",
"response_format": "mp3",
"speed": 1
}
'import requests
url = "https://api.infery.ai/v1/audio/speech"
payload = {
"model": "<string>",
"input": "<string>",
"voice": "<string>",
"instructions": "<string>",
"response_format": "mp3",
"speed": 1
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
input: '<string>',
voice: '<string>',
instructions: '<string>',
response_format: 'mp3',
speed: 1
})
};
fetch('https://api.infery.ai/v1/audio/speech', 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.infery.ai/v1/audio/speech",
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([
'model' => '<string>',
'input' => '<string>',
'voice' => '<string>',
'instructions' => '<string>',
'response_format' => 'mp3',
'speed' => 1
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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.infery.ai/v1/audio/speech"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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.infery.ai/v1/audio/speech")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/audio/speech")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}"
response = http.request(request)
puts response.read_body"/samples/tts.wav"{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}Text-to-speech
POST /v1/audio/speech — synthesise speech from text.
curl --request POST \
--url https://api.infery.ai/v1/audio/speech \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "<string>",
"input": "<string>",
"voice": "<string>",
"instructions": "<string>",
"response_format": "mp3",
"speed": 1
}
'import requests
url = "https://api.infery.ai/v1/audio/speech"
payload = {
"model": "<string>",
"input": "<string>",
"voice": "<string>",
"instructions": "<string>",
"response_format": "mp3",
"speed": 1
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: '<string>',
input: '<string>',
voice: '<string>',
instructions: '<string>',
response_format: 'mp3',
speed: 1
})
};
fetch('https://api.infery.ai/v1/audio/speech', 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.infery.ai/v1/audio/speech",
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([
'model' => '<string>',
'input' => '<string>',
'voice' => '<string>',
'instructions' => '<string>',
'response_format' => 'mp3',
'speed' => 1
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$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.infery.ai/v1/audio/speech"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<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.infery.ai/v1/audio/speech")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.infery.ai/v1/audio/speech")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"<string>\",\n \"input\": \"<string>\",\n \"voice\": \"<string>\",\n \"instructions\": \"<string>\",\n \"response_format\": \"mp3\",\n \"speed\": 1\n}"
response = http.request(request)
puts response.read_body"/samples/tts.wav"{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}{
"error": {
"message": "Model not found",
"type": "invalid_request_error",
"code": "model_not_found",
"param": "model",
"job_id": "job_1hR9xTPZqK4mVLc2nJ7fY5wB"
}
}curl https://api.infery.ai/v1/audio/speech \
-H "Authorization: Bearer $INFERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "tts-1",
"input": "Hello from Infery",
"voice": "alloy"
}' --output out.mp3
audio/mpeg / audio/wav depending on response_format).
Sample output
Generated withgemini-2.5-flash-tts, voice Kore. Download tts.wav.
Parameters
voice— model-dependent (alloy,echo,onyx,nova,shimmer, etc.)instructions— a description of the voice, for models that design one from wordsresponse_format—mp3,wav,opus,flac,pcmspeed— 0.25–4.0
Designing a voice
Some models do not pick a voice from a list — they build one from a description. Those carryaccepts_voice_instructions in allowed_params on their
GET /v1/models entry, and the ones that cannot synthesise without a
description carry requires_voice_instructions (they answer 400 without one,
before anything is billed). Send the words in input and the voice in
instructions:
curl https://api.infery.ai/v1/audio/speech \
-H "Authorization: Bearer $INFERY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen-3-tts-voice-design-1.7b",
"input": "Lets go!",
"instructions": "high-pitched, cute energetic anime girl voice, cheerful, youthful"
}' --output out.wav
instructions rather than failing on it — the
description is dropped instead of being pushed into a field that means
something else.Authorizations
API key in format: Bearer inf_***
Body
Model ID to use for TTS
Text to synthesize into speech. Maximum 4096 characters.
4096Voice to use for synthesis. Accepted values are model-specific — see allowed_params on the model's GET /v1/models entry.
OPTIONAL. Omitting it is a supported call, not a degraded one, but WHICH voice you get is the routed provider's answer rather than one of ours: the OpenAI and Google paths substitute alloy (Google then maps that name onto one of its own voices), the xAI path substitutes eve, and the Alibaba, FAL and Replicate paths send no voice at all so the model applies its own default. Pass one when the voice matters.
Sending one is not a guarantee either. On FAL and Replicate the value is forwarded only when the chosen model's own input schema declares a voice field that takes a NAME, and only when the value is a member of that field's enum where it has one — anything else is dropped silently so the model falls back to its default, rather than failing the request on a name that model has never heard of.
A DESCRIPTION of the voice to synthesize — "high-pitched, cute energetic anime girl voice, cheerful, youthful". Distinct from voice, which names one the model already has: this one designs a voice from words.
OPTIONAL for most models and IGNORED by them — it is forwarded only to models whose own input schema carries a field for it, which you can read as accepts_voice_instructions in allowed_params on the model's GET /v1/models entry. Sending it to a model without one is not an error; the description is simply dropped rather than pushed into a field that means something else.
REQUIRED by the models that synthesize their voice FROM it (requires_voice_instructions in the same allowed_params). Those answer 400 without it, before anything is billed.
4096Container for the returned audio. Sets the response Content-Type.
mp3, opus, aac, flac, wav, pcm Speed of the generated audio (0.25 to 4.0)
0.25 <= x <= 4Response
Binary audio stream. Content-Type reflects the requested response_format: audio/mpeg (mp3, default), audio/wav, audio/ogg (opus), audio/flac, audio/aac, or audio/pcm. Credits deducted are returned in the x-credits-used response header.
The response is of type file.