WhatIsTTS
WhatIsTTS

API Documentation

One unified API. 24+ TTS models, speech-to-text, voice cloning, and audio tools routed through a single endpoint.

Authentication

All authenticated requests require an API key passed in the Authorization header as a Bearer token. API keys are prefixed with sk-tts- and can be generated from your account page or via the API.

API Key Authentication

Include your API key in every request:

curl https://whatistts.com/api/v1/tts/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello world", "model": "openai-tts-1"}'
import requests

API_KEY = "sk-tts-your-api-key"
BASE_URL = "https://whatistts.com/api"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(f"{BASE_URL}/v1/tts/", headers=headers, json={
    "text": "Hello world",
    "model": "openai-tts-1"
})
const API_KEY = "sk-tts-your-api-key";
const BASE_URL = "https://whatistts.com/api";

const response = await fetch(`${BASE_URL}/v1/tts/`, {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        text: "Hello world",
        model: "openai-tts-1"
    })
});
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

const (
    apiKey  = "sk-tts-your-api-key"
    baseURL = "https://whatistts.com/api"
)

func main() {
    payload, _ := json.Marshal(map[string]string{
        "text":  "Hello world",
        "model": "openai-tts-1",
    })

    req, _ := http.NewRequest("POST", baseURL+"/v1/tts/", bytes.NewBuffer(payload))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()
}
Session Tokens (Frontend)

For browser-based applications, request a temporary session token using your user session cookie. This is used internally by the WhatIsTTS frontend.

# Requires an active session cookie
curl -X POST https://whatistts.com/api/session-token/ \
  -H "Cookie: sessionid=your-session-cookie" \
  -H "X-CSRFToken: your-csrf-token"

# Response:
# {
#   "authenticated": true,
#   "api_key": "sk-tts-...",
#   "credits": 500,
#   "plan": "pro",
#   "is_plan_active": true
# }
import requests

session = requests.Session()
# Log in first to get session cookie
session.post("https://whatistts.com/login/", data={
    "email": "user@example.com",
    "password": "your-password"
})

# Then get session token
response = session.post("https://whatistts.com/api/session-token/")
data = response.json()
api_key = data["api_key"]
credits = data["credits"]
// In-browser: session cookie is sent automatically
const response = await fetch("/api/session-token/", {
    method: "POST",
    headers: {
        "X-CSRFToken": window.TTS.csrfToken
    }
});
const data = await response.json();
// data.api_key, data.credits, data.plan
// Session tokens are primarily for browser-based usage.
// For server-to-server integrations, use API key auth instead.

req, _ := http.NewRequest("POST", "https://whatistts.com/api/session-token/", nil)
req.Header.Set("Cookie", "sessionid=your-session-cookie")
req.Header.Set("X-CSRFToken", "your-csrf-token")

client := &http.Client{}
resp, _ := client.Do(req)
Generate API Keys

Create new API keys programmatically:

curl -X POST https://whatistts.com/api/generate-key/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Production Key"}'

# Response:
# {"key": "sk-tts-abc123...", "name": "My Production Key", "id": 42}
response = requests.post(
    "https://whatistts.com/api/generate-key/",
    headers=headers,
    json={"name": "My Production Key"}
)
new_key = response.json()["key"]
print(f"New API key: {new_key}")
const response = await fetch("https://whatistts.com/api/generate-key/", {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
    },
    body: JSON.stringify({ name: "My Production Key" })
});
const { key, name, id } = await response.json();
payload, _ := json.Marshal(map[string]string{
    "name": "My Production Key",
})

req, _ := http.NewRequest("POST", baseURL+"/generate-key/", bytes.NewBuffer(payload))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")

client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()

Text to Speech

POST /api/v1/tts/

Convert text to speech using any of 24+ available models. The response is an audio file (binary) or a JSON object containing a URL to the generated audio, depending on the model and configuration.

Request Parameters
ParameterTypeDescription
text required string The text to synthesize. Free tier is limited to 500 characters. Authenticated users can send up to 5,000 characters per request.
model optional string TTS model to use. Defaults to google-standard. See Models for available options. Model determines the credit cost per request.
voice optional string Voice ID to use. Defaults vary by model. See Voices for available voices per model. Example: alloy (OpenAI), en-US-Standard-A (Google Cloud), Joanna (Amazon Polly).
format optional string Output audio format. One of mp3, wav, ogg, flac. Defaults to mp3.
speed optional float Speaking speed multiplier. Range: 0.5 to 2.0. Defaults to 1.0. Not all models support speed adjustment.
Model Tiers & Pricing
TierCostModels
Standard 2 credits / 1K chars OpenAI TTS-1, Google Cloud Standard, Azure Neural, Amazon Polly Neural, ElevenLabs Flash, ElevenLabs Turbo v2, Cartesia Sonic Turbo, Deepgram Aura, and more
Premium 5 credits / 1K chars ElevenLabs Multilingual v2, OpenAI TTS-1-HD, OpenAI GPT-4o-mini TTS, Google Cloud Studio, Azure HD, Cartesia Sonic 2, Cartesia Sonic 3, Deepgram Aura HD, and more
Example Request
curl -X POST https://whatistts.com/api/v1/tts/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome to the future of text to speech.",
    "model": "openai-tts-1",
    "voice": "alloy",
    "format": "mp3",
    "speed": 1.0
  }' \
  --output speech.mp3
import requests

API_KEY = "sk-tts-your-api-key"

response = requests.post(
    "https://whatistts.com/api/v1/tts/",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    },
    json={
        "text": "Welcome to the future of text to speech.",
        "model": "openai-tts-1",
        "voice": "alloy",
        "format": "mp3",
        "speed": 1.0
    }
)

if response.status_code == 200:
    content_type = response.headers.get("Content-Type", "")
    if "audio/" in content_type:
        # Binary audio response
        with open("speech.mp3", "wb") as f:
            f.write(response.content)
        print("Saved to speech.mp3")
    else:
        # JSON response with URL
        data = response.json()
        print(f"Audio URL: {data.get('url')}")
else:
    print(f"Error {response.status_code}: {response.text}")
const API_KEY = "sk-tts-your-api-key";

const response = await fetch("https://whatistts.com/api/v1/tts/", {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${API_KEY}`,
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        text: "Welcome to the future of text to speech.",
        model: "openai-tts-1",
        voice: "alloy",
        format: "mp3",
        speed: 1.0
    })
});

if (response.ok) {
    const contentType = response.headers.get("Content-Type") || "";
    if (contentType.includes("audio/")) {
        const blob = await response.blob();
        const url = URL.createObjectURL(blob);
        // Play it
        const audio = new Audio(url);
        audio.play();
    } else {
        const data = await response.json();
        console.log("Audio URL:", data.url);
    }
}
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    payload, _ := json.Marshal(map[string]interface{}{
        "text":   "Welcome to the future of text to speech.",
        "model":  "openai-tts-1",
        "voice":  "alloy",
        "format": "mp3",
        "speed":  1.0,
    })

    req, _ := http.NewRequest("POST", "https://whatistts.com/api/v1/tts/", bytes.NewBuffer(payload))
    req.Header.Set("Authorization", "Bearer sk-tts-your-api-key")
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    if resp.StatusCode == 200 {
        file, _ := os.Create("speech.mp3")
        defer file.Close()
        io.Copy(file, resp.Body)
        fmt.Println("Saved to speech.mp3")
    } else {
        body, _ := io.ReadAll(resp.Body)
        fmt.Printf("Error %d: %s\n", resp.StatusCode, string(body))
    }
}
Response

On success, the API returns either:

  • Binary audio with Content-Type: audio/mpeg (or audio/wav, audio/ogg, audio/flac) -- stream directly or save to file.
  • JSON with a url field pointing to the generated audio file.
{
    "url": "https://whatistts.com/media/output/abc123.mp3",
    "model": "openai-tts-1",
    "voice": "alloy",
    "duration": 3.2,
    "credits_charged": 2
}
Try It

Try It

Speech to Text

POST /api/v1/stt/

Transcribe audio files to text. Supports Whisper, Faster Whisper, and SenseVoice models. The request must use multipart/form-data encoding to upload the audio file.

Request Parameters
ParameterTypeDescription
file required file Audio file to transcribe. Supported formats: mp3, wav, ogg, flac, m4a, webm. Max size: 50MB.
model optional string STT model to use. One of whisper, faster-whisper, sensevoice. Defaults to faster-whisper.
language optional string ISO 639-1 language code (e.g., en, es, fr). Auto-detected if not specified.

Cost: 2 credits per minute of audio (rounded up).

Example Request
curl -X POST https://whatistts.com/api/v1/stt/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -F "file=@recording.mp3" \
  -F "model=faster-whisper" \
  -F "language=en"
import requests

API_KEY = "sk-tts-your-api-key"

with open("recording.mp3", "rb") as f:
    response = requests.post(
        "https://whatistts.com/api/v1/stt/",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"file": ("recording.mp3", f, "audio/mpeg")},
        data={
            "model": "faster-whisper",
            "language": "en"
        }
    )

data = response.json()
print(data["text"])
print(f"Duration: {data['duration']}s")
const API_KEY = "sk-tts-your-api-key";

const formData = new FormData();
formData.append("file", audioFile); // File or Blob object
formData.append("model", "faster-whisper");
formData.append("language", "en");

const response = await fetch("https://whatistts.com/api/v1/stt/", {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${API_KEY}`
        // Do NOT set Content-Type -- browser sets it with boundary
    },
    body: formData
});

const data = await response.json();
console.log(data.text);
package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

func main() {
    file, _ := os.Open("recording.mp3")
    defer file.Close()

    var body bytes.Buffer
    writer := multipart.NewWriter(&body)

    part, _ := writer.CreateFormFile("file", "recording.mp3")
    io.Copy(part, file)

    writer.WriteField("model", "faster-whisper")
    writer.WriteField("language", "en")
    writer.Close()

    req, _ := http.NewRequest("POST", "https://whatistts.com/api/v1/stt/", &body)
    req.Header.Set("Authorization", "Bearer sk-tts-your-api-key")
    req.Header.Set("Content-Type", writer.FormDataContentType())

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    result, _ := io.ReadAll(resp.Body)
    fmt.Println(string(result))
}
Response
{
    "text": "Hello, this is a transcription of the uploaded audio file.",
    "language": "en",
    "duration": 12.5,
    "segments": [
        {
            "start": 0.0,
            "end": 3.2,
            "text": "Hello, this is a transcription"
        },
        {
            "start": 3.2,
            "end": 5.8,
            "text": "of the uploaded audio file."
        }
    ],
    "credits_charged": 2
}

Voice Cloning

POST /api/v1/voice-clone/

Clone a voice from a reference audio sample and generate speech in that voice. Upload a short audio clip (5-30 seconds recommended) as the reference, along with the text you want spoken. Requires a model that supports cloning (ElevenLabs, OpenAI, Cartesia, and others).

Cost: 20 credits flat per clone operation.

Request Parameters
ParameterTypeDescription
reference_audio required file Audio file of the voice to clone. 5-30 seconds recommended. Formats: mp3, wav, ogg, flac. Max 50MB.
text required string Text to synthesize in the cloned voice.
model optional string Model to use for cloning. Must support voice cloning. Defaults to elevenlabs-multilingual-v2.
language optional string Target language for synthesis. ISO 639-1 code. Defaults to en.
Example Request
curl -X POST https://whatistts.com/api/v1/voice-clone/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -F "reference_audio=@my_voice.wav" \
  -F "text=This is my cloned voice speaking." \
  -F "model=elevenlabs-multilingual-v2" \
  -F "language=en"
import requests

API_KEY = "sk-tts-your-api-key"

with open("my_voice.wav", "rb") as ref:
    response = requests.post(
        "https://whatistts.com/api/v1/voice-clone/",
        headers={"Authorization": f"Bearer {API_KEY}"},
        files={"reference_audio": ("my_voice.wav", ref, "audio/wav")},
        data={
            "text": "This is my cloned voice speaking.",
            "model": "elevenlabs-multilingual-v2",
            "language": "en"
        }
    )

if response.status_code == 200:
    with open("cloned_output.mp3", "wb") as f:
        f.write(response.content)
    print("Saved cloned speech to cloned_output.mp3")
const API_KEY = "sk-tts-your-api-key";

const formData = new FormData();
formData.append("reference_audio", referenceFile); // File object
formData.append("text", "This is my cloned voice speaking.");
formData.append("model", "elevenlabs-multilingual-v2");
formData.append("language", "en");

const response = await fetch("https://whatistts.com/api/v1/voice-clone/", {
    method: "POST",
    headers: {
        "Authorization": `Bearer ${API_KEY}`
    },
    body: formData
});

if (response.ok) {
    const blob = await response.blob();
    const url = URL.createObjectURL(blob);
    const audio = new Audio(url);
    audio.play();
}
package main

import (
    "bytes"
    "fmt"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

func main() {
    file, _ := os.Open("my_voice.wav")
    defer file.Close()

    var body bytes.Buffer
    writer := multipart.NewWriter(&body)

    part, _ := writer.CreateFormFile("reference_audio", "my_voice.wav")
    io.Copy(part, file)

    writer.WriteField("text", "This is my cloned voice speaking.")
    writer.WriteField("model", "elevenlabs-multilingual-v2")
    writer.WriteField("language", "en")
    writer.Close()

    req, _ := http.NewRequest("POST", "https://whatistts.com/api/v1/voice-clone/", &body)
    req.Header.Set("Authorization", "Bearer sk-tts-your-api-key")
    req.Header.Set("Content-Type", writer.FormDataContentType())

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    output, _ := os.Create("cloned_output.mp3")
    defer output.Close()
    io.Copy(output, resp.Body)
    fmt.Println("Saved to cloned_output.mp3")
}
Response

Returns binary audio of the synthesized cloned voice, or a JSON object with a URL.

{
    "url": "https://whatistts.com/media/output/clone_xyz789.mp3",
    "model": "elevenlabs-multilingual-v2",
    "duration": 4.1,
    "credits_charged": 20
}
Models Supporting Voice Cloning
ElevenLabs Multilingual v2
ElevenLabs Flash v2.5
ElevenLabs Turbo v2.5
Microsoft Azure Neural
Microsoft Azure Neural HD
Cartesia Sonic 2
Cartesia Sonic Turbo
Cartesia Sonic 3

Voices

GET /api/v1/voices/

Retrieve the full voice catalog. Filter by model or language using query parameters. This endpoint does not require authentication.

Query Parameters
ParameterTypeDescription
model optional string Filter voices by model name. Example: openai-tts-1, elevenlabs-multilingual-v2.
language optional string Filter voices by language code. Example: en, es, fr.
Example Request
# Get all voices
curl https://whatistts.com/api/v1/voices/

# Filter by model
curl "https://whatistts.com/api/v1/voices/?model=openai-tts-1"

# Filter by language
curl "https://whatistts.com/api/v1/voices/?language=en"

# Filter by both
curl "https://whatistts.com/api/v1/voices/?model=openai-tts-1&language=en"
import requests

# Get all voices
response = requests.get("https://whatistts.com/api/v1/voices/")
voices = response.json()["voices"]
print(f"Total voices: {len(voices)}")

# Filter by model
response = requests.get("https://whatistts.com/api/v1/voices/", params={
    "model": "openai-tts-1"
})
openai_voices = response.json()["voices"]
for voice in openai_voices:
    print(f"  {voice['voice_id']} - {voice['name']} ({voice['language']})")
// Get all voices
const response = await fetch("https://whatistts.com/api/v1/voices/");
const { voices } = await response.json();
console.log(`Total voices: ${voices.length}`);

// Filter by model
const filtered = await fetch("https://whatistts.com/api/v1/voices/?model=openai-tts-1");
const { voices: openaiVoices } = await filtered.json();
openaiVoices.forEach(v => {
    console.log(`${v.voice_id} - ${v.name} (${v.language})`);
});
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type VoicesResponse struct {
    Voices []struct {
        ModelName  string `json:"model_name"`
        VoiceID    string `json:"voice_id"`
        Name       string `json:"name"`
        Language   string `json:"language"`
        Gender     string `json:"gender"`
        PreviewURL string `json:"preview_url"`
        IsPremium  bool   `json:"is_premium"`
    } `json:"voices"`
}

func main() {
    resp, _ := http.Get("https://whatistts.com/api/v1/voices/?model=openai-tts-1")
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var result VoicesResponse
    json.Unmarshal(body, &result)

    for _, v := range result.Voices {
        fmt.Printf("%s - %s (%s)\n", v.VoiceID, v.Name, v.Language)
    }
}
Response
{
    "voices": [
        {
            "model_name": "openai-tts-1",
            "voice_id": "alloy",
            "name": "Alloy",
            "language": "en",
            "gender": "neutral",
            "preview_url": "https://whatistts.com/media/previews/openai-tts-1_alloy.mp3",
            "is_premium": false,
            "tags": ["natural", "warm"]
        },
        {
            "model_name": "openai-tts-1",
            "voice_id": "nova",
            "name": "Nova",
            "language": "en",
            "gender": "female",
            "preview_url": "https://whatistts.com/media/previews/openai-tts-1_nova.mp3",
            "is_premium": false,
            "tags": ["clear", "professional"]
        }
    ]
}

Models

GET /api/v1/models/

Retrieve the list of all available TTS models with their tier and credit cost. This endpoint does not require authentication.

Example Request
curl https://whatistts.com/api/v1/models/
import requests

response = requests.get("https://whatistts.com/api/v1/models/")
models = response.json()["models"]

for model in models:
    print(f"{model['name']:20s} tier={model['tier']:10s} cost={model['credits_per_1k']} credits/1K chars")
const response = await fetch("https://whatistts.com/api/v1/models/");
const { models } = await response.json();

models.forEach(m => {
    console.log(`${m.name} (${m.tier}) - ${m.credits_per_1k} credits/1K chars`);
});
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type ModelsResponse struct {
    Models []struct {
        Name         string `json:"name"`
        Tier         string `json:"tier"`
        CreditsPer1K int    `json:"credits_per_1k"`
    } `json:"models"`
}

func main() {
    resp, _ := http.Get("https://whatistts.com/api/v1/models/")
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var result ModelsResponse
    json.Unmarshal(body, &result)

    for _, m := range result.Models {
        fmt.Printf("%-20s tier=%-10s cost=%d credits/1K\n", m.Name, m.Tier, m.CreditsPer1K)
    }
}
Response
{
    "models": [
        {"name": "google-standard", "tier": "standard", "credits_per_1k": 2},
        {"name": "openai-tts-1", "tier": "standard", "credits_per_1k": 2},
        {"name": "google-neural2", "tier": "standard", "credits_per_1k": 2},
        {"name": "azure-neural", "tier": "standard", "credits_per_1k": 2},
        {"name": "polly-neural", "tier": "standard", "credits_per_1k": 2},
        {"name": "elevenlabs-flash", "tier": "standard", "credits_per_1k": 2},
        {"name": "deepgram-aura", "tier": "standard", "credits_per_1k": 2},
        {"name": "elevenlabs-multilingual-v2", "tier": "premium", "credits_per_1k": 5},
        {"name": "openai-tts-1-hd", "tier": "premium", "credits_per_1k": 5},
        {"name": "cartesia-sonic", "tier": "premium", "credits_per_1k": 5}
    ]
}
Available Models
ModelTierSpeedQualityCloningDeveloper
elevenlabs-multilingual-v2 premium fast ElevenLabs
elevenlabs-flash-v2 standard fast ElevenLabs
elevenlabs-turbo-v2 standard fast ElevenLabs
openai-tts-1 standard fast -- OpenAI
openai-tts-1-hd premium medium -- OpenAI
openai-gpt-4o-mini-tts premium medium -- OpenAI
google-standard standard fast -- Google
google-wavenet standard fast -- Google
google-neural2 standard fast -- Google
google-studio premium medium -- Google
azure-neural standard fast Microsoft
azure-neural-hd premium medium Microsoft
polly-standard standard fast -- Amazon Web Services
polly-neural standard fast -- Amazon Web Services
polly-generative premium medium -- Amazon Web Services
polly-long-form premium medium -- Amazon Web Services
deepgram-aura-2 premium fast -- Deepgram
cartesia-sonic-2 premium fast Cartesia
cartesia-sonic-turbo standard very fast Cartesia
cartesia-sonic-3 premium fast Cartesia
STT Models
ModelLanguagesDeveloperDescription
openai-whisper-1 57+ OpenAI OpenAI's robust speech recognition API supporting 57 languages.
openai-gpt-4o-transcribe 57+ OpenAI OpenAI's latest transcription model with improved accuracy and structured output.
deepgram-nova-3 36+ Deepgram Deepgram's fastest and most accurate STT with real-time streaming and diarization.
google-chirp-3 100+ Google Google's latest speech recognition with 100+ language support and auto-punctuation.
azure-stt 100+ Microsoft Azure speech recognition with 100+ languages, custom models, and real-time streaming.
elevenlabs-scribe 99+ ElevenLabs ElevenLabs' speech-to-text with speaker diarization and 99 language support.

Rate Limits

WhatIsTTS enforces rate limits to ensure fair usage across all users. Limits differ based on authentication status and plan.

TierRate LimitCharacter LimitModelsAuth Required
Free (No Account) 3 requests / hour 500 characters / request Google Cloud Standard and Amazon Polly only No
Free Account 10 requests / hour 5,000 characters / request All free + standard models Yes
Paid Plan Per plan allocation 5,000 characters / request All models Yes
Rate Limit Headers

When you exceed rate limits, the API returns a 429 Too Many Requests response:

{
    "error": "rate_limit",
    "message": "Free tier limit reached. Sign up for more."
}
Handling Rate Limits
# Check the HTTP status code
response=$(curl -s -w "\n%{http_code}" -X POST https://whatistts.com/api/v1/tts/ \
  -H "Authorization: Bearer sk-tts-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello", "model": "openai-tts-1"}')

status=$(echo "$response" | tail -1)
body=$(echo "$response" | head -1)

if [ "$status" = "429" ]; then
    echo "Rate limited. Wait and retry."
fi
import time
import requests

API_KEY = "sk-tts-your-api-key"

def generate_speech(text, model="openai-tts-1", retries=3):
    for attempt in range(retries):
        response = requests.post(
            "https://whatistts.com/api/v1/tts/",
            headers={
                "Authorization": f"Bearer {API_KEY}",
                "Content-Type": "application/json"
            },
            json={"text": text, "model": model}
        )

        if response.status_code == 200:
            return response.content
        elif response.status_code == 429:
            wait = 2 ** attempt  # Exponential backoff
            print(f"Rate limited. Retrying in {wait}s...")
            time.sleep(wait)
        else:
            response.raise_for_status()

    raise Exception("Max retries exceeded")
async function generateSpeech(text, model = "openai-tts-1", retries = 3) {
    for (let attempt = 0; attempt < retries; attempt++) {
        const response = await fetch("https://whatistts.com/api/v1/tts/", {
            method: "POST",
            headers: {
                "Authorization": `Bearer ${API_KEY}`,
                "Content-Type": "application/json"
            },
            body: JSON.stringify({ text, model })
        });

        if (response.ok) return await response.blob();

        if (response.status === 429) {
            const wait = Math.pow(2, attempt) * 1000;
            console.log(`Rate limited. Retrying in ${wait}ms...`);
            await new Promise(r => setTimeout(r, wait));
            continue;
        }

        throw new Error(`HTTP ${response.status}: ${await response.text()}`);
    }
    throw new Error("Max retries exceeded");
}
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "math"
    "net/http"
    "time"
)

func generateSpeech(text, model string) (*http.Response, error) {
    maxRetries := 3
    for attempt := 0; attempt < maxRetries; attempt++ {
        payload, _ := json.Marshal(map[string]string{
            "text":  text,
            "model": model,
        })

        req, _ := http.NewRequest("POST", "https://whatistts.com/api/v1/tts/", bytes.NewBuffer(payload))
        req.Header.Set("Authorization", "Bearer sk-tts-your-api-key")
        req.Header.Set("Content-Type", "application/json")

        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return nil, err
        }

        if resp.StatusCode == 200 {
            return resp, nil
        }
        resp.Body.Close()

        if resp.StatusCode == 429 {
            wait := time.Duration(math.Pow(2, float64(attempt))) * time.Second
            fmt.Printf("Rate limited. Retrying in %v...\n", wait)
            time.Sleep(wait)
            continue
        }

        return nil, fmt.Errorf("HTTP %d", resp.StatusCode)
    }
    return nil, fmt.Errorf("max retries exceeded")
}
Credit Costs Reference
OperationCostUnit
TTS (trial: Google Standard, Polly Standard)0 creditsper 1K chars
TTS (standard models)2 creditsper 1K chars
TTS (premium models)5 creditsper 1K chars
Speech to Text2 creditsper minute
Voice Cloning20 creditsflat
Voice Conversion5 creditsper minute
Speech Translation5 creditsper minute
Audio Enhancement3 creditsper minute
Echo/Reverb Removal3 creditsper minute
Stem Splitting5 creditsflat
Voice Chat3 creditsper minute
Audio Converter / Key-BPM / Recorder0 creditsfree

Error Codes

WhatIsTTS uses standard HTTP status codes. All error responses return JSON with an error field and an optional message field.

CodeStatusDescription
200 OK Request succeeded. Response contains the generated audio or requested data.
400 Bad Request The request was malformed. Check that required parameters are present and valid. Common causes: missing text field, invalid model name, unsupported format.
401 Unauthorized Authentication failed. The API key is missing, invalid, or revoked. Ensure your Authorization header contains a valid Bearer sk-tts-... token.
402 Payment Required Insufficient credits for this operation. The response includes credits_remaining and credits_needed fields. Purchase more credits.
403 Forbidden You do not have permission for this action. Common causes: trying to use a paid model without an account, email not verified, or API key lacks required scope.
429 Too Many Requests Rate limit exceeded. Free tier: 3 requests per hour. Implement exponential backoff and retry after a delay. See Rate Limits for details.
500 Internal Server Error Something went wrong on our end. This may indicate a temporary issue with an upstream provider. Retry after a short delay. If the problem persists, contact support.
Error Response Format
{
    "authorized": false,
    "error": "invalid_api_key"
}
{
    "authorized": false,
    "error": "insufficient_credits",
    "credits_remaining": 1,
    "credits_needed": 5
}
{
    "error": "rate_limit",
    "message": "Free tier limit reached. Sign up for more."
}
{
    "error": "upstream_provider_error",
    "message": "The TTS provider returned an unexpected error. Please try again."
}
Best Practices
  • Always check the status code before processing the response body.
  • Implement exponential backoff for 429 and 500 errors. Start at 1 second and double on each retry, up to 3 attempts.
  • Monitor your credit balance using the credits_remaining field in verify and error responses to avoid unexpected 402 errors.
  • Validate input client-side before sending to reduce unnecessary API calls. Check text length, model names, and format values.
  • Keep API keys secret. Never expose sk-tts- keys in client-side code or public repositories. Use session tokens for browser-based apps.