Skip to main content
Lesson 4 of 14 · Text-to-Speech API

Audio response and pricing

Lesson 4 of 14 Updated November 3, 2026 Developer
On this page
  1. Handle the response and keep costs under control
  2. Anatomy of the HTTP response
  3. Codec to Content-Type mapping
  4. Pricing in detail
  5. Estimate audio length
  6. Key takeaways

Updated November 3, 2026, based on the xAI Pricing, Rate limits, and Text to Speech pages. Sources: Pricing · Rate limits · Text to Speech.

Handle the response and keep costs under control

When the TTS API succeeds, it returns a stream of audio bytes directly in the HTTP body. Knowing how to handle that response and anticipate costs is essential to running TTS in production.

Anatomy of the HTTP response

The response has status 200, and the body contains nothing but audio bytes. There’s no JSON envelope. The important HTTP headers are:

  • Content-Type: the audio format (audio/mpeg for MP3, audio/wav for WAV, audio/pcm for PCM)
  • Content-Length: the size of the audio file in bytes
response = requests.post("https://api.x.ai/v1/tts", ...)

# Check for success
if response.status_code == 200:
    content_type = response.headers["Content-Type"]
    audio_size = len(response.content)
    print(f"Format: {content_type}, Size: {audio_size} bytes")

Write to a file

The simplest approach is to write the response straight to a file:

with open("output.mp3", "wb") as f:
    f.write(response.content)

Stream the response

For large files, stream the response so you don’t load all the audio into memory:

response = requests.post(
    "https://api.x.ai/v1/tts",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"text": long_text, "voice_id": "eve", "language": "en"},
    stream=True
)

with open("output.mp3", "wb") as f:
    for chunk in response.iter_content(chunk_size=8192):
        f.write(chunk)

Play it directly in the browser

In client-side JavaScript (after relaying the audio through your backend), you can create an audio element on the fly:

const audioBlob = new Blob([audioBuffer], { type: "audio/mpeg" });
const audioUrl = URL.createObjectURL(audioBlob);
const audio = new Audio(audioUrl);
audio.play();

Remember to release the Blob URL after playback to avoid memory leaks (the production lesson covers this in detail).

Codec to Content-Type mapping

Requested codecContent-Type receivedFile extension
mp3audio/mpeg.mp3
wavaudio/wav.wav
pcmaudio/pcm.pcm
mulawaudio/basic.ul
alawaudio/alaw.al

Pricing in detail

TTS costs $15 per million characters (xAI pricing as of November 3, 2026). You’re billed for the contents of the text field as you send it, expressive tags included.

Cost estimates

VolumeCharactersEstimated cost
1 sentence~100$0.0015
1 paragraph~500$0.0075
1 printed page~2,000$0.03
1 blog post~5,000$0.075
1 book (200 pages)~400,000$6
1 million characters1,000,000$15

Tags and billing

Expressive tags such as [pause], <whisper>, and <loud> count toward the character total. A 1,000-character text with 50 characters of tags is billed as 1,050 characters. That’s usually less than 5% of the total text.

Concurrency limits

According to the xAI Rate limits page, TTS accepts 50 requests per second and 100 concurrent sessions on the entry tier, limits that grow with your team’s tier (up to 500 and 500). The Text to Speech page also mentions 50 concurrent WebSocket sessions per team. Beyond that, the API returns a 429 error: for large volumes, space out your requests or use a queue.

Estimate audio length

The length of the generated audio depends on the text, the voice, and the speed setting. As a ballpark, read speech runs at around 150 words per minute, or roughly 850 characters per minute in English: measure it with your voice before you promise a duration. For an exact figure, with_timestamps returns the audio duration (duration) along with the timestamps.

At that pace, a 60,000-character text, the limit for one request, produces a little over an hour of audio.

Key takeaways

  • The TTS response is a binary stream, not JSON
  • The Content-Type tells you which audio format you received
  • Stream large files
  • It costs $15 per million characters, tags included
  • On the entry tier: 50 requests per second and 100 concurrent sessions
  • A 60,000-character request produces roughly an hour of audio