curl https://api.tts.runatlas.com/v1/voices \
-H "Authorization: Bearer $ATLAS_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"name\": \"Narrator\", \"consent\": true, \"audio_b64\": \"$(base64 < reference.wav | tr -d '\n')\"}"
import base64, os, requests
with open("reference.wav", "rb") as f:
audio_b64 = base64.b64encode(f.read()).decode()
res = requests.post(
"https://api.tts.runatlas.com/v1/voices",
headers={"Authorization": f"Bearer {os.environ['ATLAS_API_KEY']}"},
json={"name": "Narrator", "consent": True, "audio_b64": audio_b64},
)
res.raise_for_status()
voice_id = res.json()["id"]
import fs from "node:fs";
const res = await fetch("https://api.tts.runatlas.com/v1/voices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATLAS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Narrator",
consent: true,
audio_b64: fs.readFileSync("reference.wav").toString("base64"),
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { id: voiceId } = await res.json();
{
"id": "tmp-a1b2c3-x9y8z7",
"object": "voice",
"name": "Narrator",
"created": 1791454123,
"owned_by": "user",
"reference_seconds": 5.2
}
{
"error": {
"message": "You already have a voice named \"Narrator\"",
"type": "invalid_request_error"
}
}
API reference
Create a voice clone
Clone a voice from a short reference clip.
POST
/
v1
/
voices
curl https://api.tts.runatlas.com/v1/voices \
-H "Authorization: Bearer $ATLAS_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"name\": \"Narrator\", \"consent\": true, \"audio_b64\": \"$(base64 < reference.wav | tr -d '\n')\"}"
import base64, os, requests
with open("reference.wav", "rb") as f:
audio_b64 = base64.b64encode(f.read()).decode()
res = requests.post(
"https://api.tts.runatlas.com/v1/voices",
headers={"Authorization": f"Bearer {os.environ['ATLAS_API_KEY']}"},
json={"name": "Narrator", "consent": True, "audio_b64": audio_b64},
)
res.raise_for_status()
voice_id = res.json()["id"]
import fs from "node:fs";
const res = await fetch("https://api.tts.runatlas.com/v1/voices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATLAS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Narrator",
consent: true,
audio_b64: fs.readFileSync("reference.wav").toString("base64"),
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { id: voiceId } = await res.json();
{
"id": "tmp-a1b2c3-x9y8z7",
"object": "voice",
"name": "Narrator",
"created": 1791454123,
"owned_by": "user",
"reference_seconds": 5.2
}
{
"error": {
"message": "You already have a voice named \"Narrator\"",
"type": "invalid_request_error"
}
}
Creates a voice from a reference recording and saves it to your account. The returned
id can
be passed as voice to Generate speech and the
streaming endpoint right away, and it is listed in
/v1/models with owned_by: "user".
Clones are private. Only API keys on the account that created a clone can use or delete it.
Each account can keep up to 10 cloned voices. Delete one with
DELETE /v1/voices/{id} to make room for another. Cloning is
English-only.Authorization
string
required
Bearer sk_… — your secret API key.Body
string
required
A display name for the voice, up to 40 characters. Must be unique among your voices
(case-insensitive).
string
required
The reference clip as base64-encoded WAV, 3–12 seconds long. Use clean speech from a
single speaker with no music or background noise. The request body may be up to 16 MB.
boolean
required
Must be
true. This confirms you have permission to clone the voice in the clip.Response
string
The new voice id. Pass this as
voice when generating speech.string
Always
voice.string
The display name, with surrounding whitespace trimmed.
number
Unix timestamp (seconds) the voice was created.
string
Always
user.number
Length of the reference clip in seconds.
Errors
| Status | type | Cause |
|---|---|---|
400 | invalid_request_error | Missing consent, name, or audio_b64; the clip is not a readable WAV or is outside 3–12 s; or the 10-voice limit is reached. |
409 | invalid_request_error | You already have a voice with this name. |
401 | auth_error | Missing, malformed, or revoked API key. |
curl https://api.tts.runatlas.com/v1/voices \
-H "Authorization: Bearer $ATLAS_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"name\": \"Narrator\", \"consent\": true, \"audio_b64\": \"$(base64 < reference.wav | tr -d '\n')\"}"
import base64, os, requests
with open("reference.wav", "rb") as f:
audio_b64 = base64.b64encode(f.read()).decode()
res = requests.post(
"https://api.tts.runatlas.com/v1/voices",
headers={"Authorization": f"Bearer {os.environ['ATLAS_API_KEY']}"},
json={"name": "Narrator", "consent": True, "audio_b64": audio_b64},
)
res.raise_for_status()
voice_id = res.json()["id"]
import fs from "node:fs";
const res = await fetch("https://api.tts.runatlas.com/v1/voices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ATLAS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Narrator",
consent: true,
audio_b64: fs.readFileSync("reference.wav").toString("base64"),
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
const { id: voiceId } = await res.json();
{
"id": "tmp-a1b2c3-x9y8z7",
"object": "voice",
"name": "Narrator",
"created": 1791454123,
"owned_by": "user",
"reference_seconds": 5.2
}
{
"error": {
"message": "You already have a voice named \"Narrator\"",
"type": "invalid_request_error"
}
}