Create cloned voice
curl --request POST \
--url https://supertoneapi.com/v1/custom-voices/cloned-voice \
--header 'Content-Type: multipart/form-data' \
--header 'x-sup-api-key: <api-key>' \
--form files='@example-file' \
--form 'name=<string>' \
--form 'description=<string>'import requests
url = "https://supertoneapi.com/v1/custom-voices/cloned-voice"
files = { "files": ("example-file", open("example-file", "rb")) }
payload = {
"name": "<string>",
"description": "<string>"
}
headers = {"x-sup-api-key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('files', '<string>');
form.append('name', '<string>');
form.append('description', '<string>');
const options = {method: 'POST', headers: {'x-sup-api-key': '<api-key>'}};
options.body = form;
fetch('https://supertoneapi.com/v1/custom-voices/cloned-voice', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://supertoneapi.com/v1/custom-voices/cloned-voice"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-sup-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://supertoneapi.com/v1/custom-voices/cloned-voice",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-sup-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://supertoneapi.com/v1/custom-voices/cloned-voice")
.header("x-sup-api-key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();{
"voice_id": "voice_123456789"
}{
"status": "error",
"message": "Invalid request data"
}{
"status": "error",
"message": {
"message": "Invalid API Key",
"error": "Unauthorized"
}
}{
"status": "error",
"message": {
"message": "Permission denied",
"error": "Forbidden"
}
}{
"status": "error",
"message": {
"message": "Voice not found",
"error": "Not Found"
}
}{
"status": "error",
"message": {
"message": "File too large",
"error": "Payload Too Large"
}
}{
"status": "error",
"message": "Unsupported audio format. Supported formats: WAV, MP3. Received: application/json"
}{
"status": "error",
"message": {
"message": "rate limit exceeded",
"error": "Too Many Requests"
}
}{
"status": "error",
"message": {
"message": "Failed to convert text to speech",
"error": "Internal Server Error"
}
}Custom voices
Create cloned voice
Register a new custom voice by uploading a sample audio file.
POST
/
v1
/
custom-voices
/
cloned-voice
Create cloned voice
curl --request POST \
--url https://supertoneapi.com/v1/custom-voices/cloned-voice \
--header 'Content-Type: multipart/form-data' \
--header 'x-sup-api-key: <api-key>' \
--form files='@example-file' \
--form 'name=<string>' \
--form 'description=<string>'import requests
url = "https://supertoneapi.com/v1/custom-voices/cloned-voice"
files = { "files": ("example-file", open("example-file", "rb")) }
payload = {
"name": "<string>",
"description": "<string>"
}
headers = {"x-sup-api-key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('files', '<string>');
form.append('name', '<string>');
form.append('description', '<string>');
const options = {method: 'POST', headers: {'x-sup-api-key': '<api-key>'}};
options.body = form;
fetch('https://supertoneapi.com/v1/custom-voices/cloned-voice', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://supertoneapi.com/v1/custom-voices/cloned-voice"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-sup-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://supertoneapi.com/v1/custom-voices/cloned-voice",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"x-sup-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}HttpResponse<String> response = Unirest.post("https://supertoneapi.com/v1/custom-voices/cloned-voice")
.header("x-sup-api-key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"files\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"description\"\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();{
"voice_id": "voice_123456789"
}{
"status": "error",
"message": "Invalid request data"
}{
"status": "error",
"message": {
"message": "Invalid API Key",
"error": "Unauthorized"
}
}{
"status": "error",
"message": {
"message": "Permission denied",
"error": "Forbidden"
}
}{
"status": "error",
"message": {
"message": "Voice not found",
"error": "Not Found"
}
}{
"status": "error",
"message": {
"message": "File too large",
"error": "Payload Too Large"
}
}{
"status": "error",
"message": "Unsupported audio format. Supported formats: WAV, MP3. Received: application/json"
}{
"status": "error",
"message": {
"message": "rate limit exceeded",
"error": "Too Many Requests"
}
}{
"status": "error",
"message": {
"message": "Failed to convert text to speech",
"error": "Internal Server Error"
}
}Clones a voice from an uploaded audio sample and registers it as a custom voice on your account. The returned
Send as
voice_id is immediately callable through the same TTS endpoints as preset voices.
Voice cloning via the API is not available on the Free tier. Free-tier accounts can clone in Supertone Play.
Endpoint
POST https://supertoneapi.com/v1/custom-voices/cloned-voice
multipart/form-data.
Request body
| Field | Required | Description |
|---|---|---|
files | ✅ | The audio sample to clone from. Must be WAV or MP3, under 3 MB. |
name | ✅ | Voice name. Max 100 characters. |
description | — | Free-form description. |
Sample quality tips
For the best clone quality:- Clean, single-speaker audio with minimal background noise.
- 5–30 seconds is usually sufficient.
- Mono is preferred; high sample rate is fine.
Response
Returns the new custom voice object, including the assignedvoice_id. Save the ID — pass it to Create speech to use the voice.
Errors
| Status | Cause |
|---|---|
400 Bad Request | Missing files or name, or name too long. |
413 Payload Too Large | Audio file exceeds 3 MB. |
415 Unsupported Media Type | File is not WAV or MP3. |
403 Forbidden | Free tier account (cloning via API not permitted). |
See also
Docs: Custom voices
Lifecycle walkthrough with SDK examples.
Custom voice example
End-to-end: clone, list, and call.
Authorizations
Body
multipart/form-data
Audio file and voice metadata
Response
Successfully created cloned voice
Unique identifier for the created voice
Example:
"voice_123456789"
⌘I