Voice API
Overtone, Undertone, Duotone and Truetone over one key. Speech and transcription follow the OpenAI audio API shapes.
Authentication
Base URL: https://tts-api.yoob.com/v1. Send your API key as a bearer token on every request. Keys start with yoob_live_ or yoob_test_ and are shown once, when you create them in the console. Keep keys on your server: anyone who can read a key can spend your credits until you revoke it. A revoked key stops working within a minute.
from openai import OpenAI
client = OpenAI(base_url="https://tts-api.yoob.com/v1", api_key=os.environ["YOOB_API_KEY"])
print(client.models.list())
A missing, wrong or revoked key gets 401 with "code": "invalid_api_key".
Text to speech (Overtone)
POST /audio/speech with JSON. Returns 48 kHz WAV. Up to 500 characters a request; long input is split into chunks of about 40 words at sentence ends.
curl https://tts-api.yoob.com/v1/audio/speech \
-H "Authorization: Bearer $YOOB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "yoob-tts-1", "voice": "m0770", "quality": "fast",
"input": "[tender] Hey. [sigh] Whatever happens tomorrow, you are not doing it alone."}' \
--output line.wav
| Field | Value |
|---|---|
model | yoob-tts-1 |
voice | A voice id: w1243, m0770, w0110, m0035, w0073, m0886, w0043, m0290, w0059, m0112. Hear them on Overtone. |
input | The line, with tags (below) |
quality | best: several takes per sentence, keeps the cleanest. fast: one take, first audio sooner, for realtime. |
For audio as it is made, use POST /audio/speech/stream with the same body and read the response as a stream.
Emotion, sound and delivery tags
Write how the line should sound into the line, in lower-case square brackets.
- Emotion, at the start: sets the feeling and pacing of the whole line.
[angry] [calm] [desire] [disgust] [excited] [fear] [flirty] [grief] [hurt] [intimate] [joy] [longing] [nervous] [neutral] [playful] [relief] [sad] [shock] [surprise] [tender] [tired]. Common synonyms such ashappyorscaredare mapped onto these. - Sounds, anywhere: performed where they stand.
[laughing] [giggle] [chuckle] [sigh] [gasp] [breathing] [inhale] [exhale] [crying] [sobbing] [sniff] [groan] [panting] [cough] [clear throat] [yawn] [scream] - Delivery spans, around words:
[whisper]…[/whisper],[low voice],[shouting],[tearful],[trembling]. Close the span; closed spans render better.
[sad] [sigh] I walked past his old office today. [tearful] The nameplate was already gone. [/tearful]
Speech to text (Undertone)
POST /audio/transcriptions with the audio as the request body and its Content-Type; options go in the query string. Model yoob-asr-1.
curl "https://tts-api.yoob.com/v1/audio/transcriptions?response_format=verbose_json" \
-H "Authorization: Bearer $YOOB_API_KEY" \
-H "Content-Type: audio/wav" \
--data-binary @clip.wav
response_format | Returns |
|---|---|
json | The default: {"text": "..."} |
text | The transcript as plain text |
verbose_json | Segments with caption, tags, emotion, word timings, voice fields and p_human, plus the speaker profile |
A real verbose_json response, shortened:
{
"task": "transcribe",
"language": "english",
"duration": 4.4,
"text": "We still got some work to do and I look forward to getting that work done.",
"caption": "[emo:joy] We still got some work to do and <shouting> I look forward to getting that work done. </shouting>",
"segments": [{
"start": 0.0, "end": 4.384,
"caption": "[emo:joy] We still got some work to do and <shouting> I look forward to ... </shouting>",
"tags": [["<shouting>", 1.84], ["</shouting>", 4.16]],
"emotion": "joy",
"emotion_probs": { "joy": 0.943, "sad": 0.031, "surprise": 0.007, ... },
"words": [{ "word": "We", "start": 0.0, "end": 0.16 }, ...],
"voice": { "f0_hz": 89.4, "wpm": 274.3, "snr_db": 15.9 },
"p_human": 0.997
}],
"speaker": { "gender": {...}, "age": [...], "accent": {...}, "p_human": 0.997 },
"model": "yoob-asr-1"
}
caption marks up how the words sounded: [emo:joy] for the feeling from that point on, [laughing], [sigh] or [breath] for sounds where they happened, and <whisper>…</whisper> for words said a particular way. Emotions come in eight families: joy, tender, surprise, neutral, sad, fear, angry and disgust, plus none.
Realtime transcription
Open wss://tts-api.yoob.com/v1/audio/transcriptions/stream with the same bearer header and send 16-bit PCM, mono, 16 kHz. You receive partial messages with the whole utterance so far (replace, don’t append) and a final message with the caption and emotion when the speaker finishes.
Voice detection (Truetone)
Every transcript carries p_human, the probability from 0 to 1 that the voice is a real person: on each segment for that sentence, and on speaker for the voice across the clip. The live socket reports it as the person talks.
p_human | Read it as |
|---|---|
| 0.65 and above | Sounds human |
| 0.35 to 0.65 | Can’t tell for sure |
| Below 0.35 | Sounds AI-generated |
The detector is built to catch AI audio played through a speaker into a microphone. It catches about 98% of replayed AI from engines it was trained on, and 70 to 99% (89% on average) from engines it hasn’t heard. About 3 to 5% of real voices played through speakers are flagged, and 0.3% of clean files; whispery or quiet voices are flagged more often. Treat the score as one signal, not proof.
Duotone socket
One WebSocket per call: wss://tts-api.yoob.com/v1/duotone. Open it from your server with your key, send a config message first ({} starts a call with the default persona and voice w1243), then stream the caller’s microphone as 16-bit PCM, mono, 16 kHz, in frames of up to 1 s (40 ms works well). Keep sending while Duotone speaks: that is how it hears the caller cut in. Capture with echo cancellation on.
| You receive | What it is |
|---|---|
ready | The call is live: start the microphone |
user | What the caller is saying, updated as they speak; final: true ends their turn |
reply | The reply as it is written, voice tags included |
| binary frames | The reply’s audio: 16-bit PCM, mono, 48 kHz |
reply_done | The reply is complete; interrupted: true means the caller cut in, so stop playing it |
done | The call has ended, with usage |
Avatar SDK docs are at /docs/. Questions: team@yoob.com.