TokenHot
HomeModelsConsoleDocumentationBlog
✓ English简体中文繁體中文日本語FrançaisРусскийTiếng Việt
TokenHot

One API. A model catalog. Usage-based billing.

Product

  • Models
  • Pricing
  • About
  • Support

Popular Models

  • GPT-5.6
  • Claude Opus 5
  • Claude Fable 5
  • Gemini 3.5 Flash
  • Claude Sonnet 5
  • DeepSeek V4 Pro
  • Kimi K3
  • Seedance 2.5

Model Providers

  • OpenAI
  • Anthropic
  • Google
  • DeepSeek
  • Qwen
  • ByteDance
  • Doubao
  • MiniMax
  • Z.ai (GLM)

Resources

  • Docs
  • Blog
  • hi@tokenhot.ai
  • Terms
  • Privacy
  • Refund Policy
© 2026 NEXORA AI PTE. LTD. · Tokenhot
HomeBlogAPI GuidesGemini TTS API: From Text to Playable Audio in Python
API Guides

Gemini TTS API: From Text to Playable Audio in Python

TTokenhot Team·October 18, 2026·6 min read
Gemini TTS API: From Text to Playable Audio in Python

The Gemini TTS API returns audio inside a response object, not necessarily a ready-to-save WAV file. For Tokenhot’s documented gemini-2.5-flash-preview-tts route, build a generateContent request, select the voice, keep the response, and decode the audio according to its actual MIME type. Renaming the entire JSON response to speech.wav will not make it playable.

This tutorial stays with Tokenhot’s Gemini 2.5 Flash TTS reference. Its example uses Zephyr and labels the returned audio audio/mp3. That is a documentation example, not a recording generated for this article. The Python companion has offline checks; no live synthesis or listening test was performed.

Version check before starting: as checked on October 11, 2026, Google’s deprecation table lists November 17, 2026 as the earliest possible shutdown date for its Gemini 2.5 TTS previews. This is not a confirmed Tokenhot cutoff or proof of an equivalent replacement route. Confirm the gateway model remains available before committing a new workflow to it.

1. Keep the model, protocol, and voice fields together

This route uses:

POST https://api.tokenhot.ai/v1beta/models/gemini-2.5-flash-preview-tts:generateContent
Authorization: Bearer YOUR_TOKENHOT_API_KEY
Content-Type: application/json

Do not substitute /v1/chat/completions merely because another Tokenhot audio model uses it. Likewise, do not combine this request with a newer Gemini model’s voice-field nesting or output-format options.

Here is an authored single-voice request using the documented structure:

{
  "contents": [
    {
      "parts": [
        {"text": "Say clearly and warmly: Your report is ready. Open the dashboard to review it."}
      ]
    }
  ],
  "generationConfig": {
    "responseModalities": ["AUDIO"],
    "speechConfig": {
      "voiceConfig": {
        "prebuiltVoiceConfig": {"voiceName": "Zephyr"}
      }
    }
  }
}

The style instruction and spoken copy are in the text prompt here. Inspect the eventual recording to confirm which words were spoken and how. The example does not establish exact pronunciation, timing, or that every instruction will be followed.

The companion deliberately fixes the voice to the documented Zephyr example. To use a different voice, first confirm it for this model and route, then change the preparation function and its validation together. A voice listed for a different API/version is not enough evidence.

2. Prepare the request locally

Download the complete Python companion and save it as media_workflows.py in your working directory. It uses the Python standard library; the author’s checks used Python 3.13.5. There is no package installation or embedded key.

Create a UTF-8 file named speech.txt containing the prompt above, then run:

python media_workflows.py tts-request --text-file speech.txt --out speech-request.json

Preparation writes a new JSON file and stops without opening a connection. Inspect the file before sending it. Existing files are not overwritten; use a new filename for an intentional revision.

Use Tokenhot’s Quick Start to locate your key, then set TOKENHOT_API_KEY in your shell or secret manager. For example, in PowerShell:

$env:TOKENHOT_API_KEY = "YOUR_TOKENHOT_API_KEY"

Replace the placeholder privately. Do not put the actual key in the request file, article, source control, or shared terminal output.

3. Submit once and retain the complete response

This command sends an authenticated request and may incur usage charges:

python media_workflows.py submit --kind tts --request speech-request.json --run runs/tts-001 --execute

The explicit --execute flag is required. The helper reserves a new run directory, stores the request without authorization headers, and makes one POST. A received body goes into runs/tts-001/response.json before response parsing. It also records the HTTP status separately.

The run-directory guard prevents an accidental rerun with the same local directory. It is not server-side idempotency: using another directory can send another request. If the connection ends without a usable response, reconcile that attempt before deciding to synthesize again.

Local responses can contain private text and generated audio. Keep them out of Git and redact them before asking for help. A response-size limit in this example is a memory guard, not a provider quota.

4. Save the returned format rather than guessing one

The documented audio location is candidates[0].content.parts[].inlineData. The relevant fields are mimeType and Base64 data; the example’s candidate ends with finishReason: "STOP". The string Base64_String_Here in that example is a placeholder, not a usable test recording.

Run the local decoder:

python media_workflows.py audio --response runs/tts-001/response.json --output-stem output/voiceover

Use an output stem without an extension. The helper selects .mp3 or .wav from the returned type and prints the actual destination.

Actual response Local handling
audio/mp3 or audio/mpeg Decode Base64, check for a recognizable MP3 signature, and save .mp3 unchanged.
audio/wav, audio/x-wav, or audio/wave Check the RIFF/WAVE container and PCM frame data, then preserve the existing WAV bytes.
Raw audio/L16 or audio/pcm Stop by default. Obtain the actual sample format, byte order, rate, and channel count before wrapping it.
Missing audio, an unfinished candidate, or an unsupported type Keep the response for diagnosis rather than writing a misleading audio file.

These are the companion’s handling branches, not a claim that Tokenhot has been observed returning every format in the table. Its published sample only labels MP3. The MP3 signature check is also not a full codec decode or a listening test.

The script selects candidate zero and requires one inline audio part. It does not concatenate alternative candidates or multiple encoded containers. Such responses need separately verified framing, not a blind byte join.

Raw PCM requires an explicit, confirmed contract

Raw samples need metadata that a WAV container normally carries. Only when your provider confirms signed 16-bit little-endian PCM with the applicable rate and channels should you use the explicit override. For example, if separately confirmed as 24,000 Hz, mono:

python media_workflows.py audio --response runs/tts-001/response.json --output-stem output/voiceover --pcm-s16le 24000 1

Those numbers illustrate an explicit conversion configuration, not a verified Tokenhot default. An audio/L16 label by itself does not confirm the little-endian assumption. Do not use this override to make an unknown payload appear to work.

Python 3.13’s wave module handles supported uncompressed PCM WAV data, not MP3 transcoding. Adding a WAV header to MP3 or adding a second header to an existing WAV corrupts the intended interpretation instead of converting the codec.

5. Recover the file before repeating synthesis

The audio command has no network path and needs no API key. When the complete response already exists, it can decode again to a fresh destination without another synthesis request.

If Base64 decoding fails, inspect the saved fields. If the MIME type and bytes disagree, ask for the exact route output contract. If the file already exists, inspect it or choose another name. If the POST timed out and no complete response exists, a local decoder cannot recover audio it never received.

The example refuses HTTP redirects and uses hard-link file installation to avoid overwriting an existing destination. A filesystem that does not support that operation will fail safely; move the working directory to a supported local filesystem rather than rerunning synthesis as a workaround.

Finally, open the saved file in an audio player. Check completeness, product-name pronunciation, numbers, unwanted spoken instructions, and pacing. File validation cannot establish those qualities. Keep the exact request beside each deliberately generated version so later comparisons are meaningful.

Does this also cover live speech or voice cloning?

No. This guide demonstrates one non-streaming, preset-voice request on the documented Tokenhot route. It does not establish support for live sessions, cloning, multi-speaker generation, or newer Gemini TTS settings. Those require their own model-specific request and response evidence.

Summary

Use Tokenhot’s documented Gemini 2.5 TTS route, select a voice, decode the returned audio format, and recover saved responses without another synthesis.

Back to Blog

Related Articles

MiMo TTS API: Turn Text into a Playable WAV File

MiMo TTS API: Turn Text into a Playable WAV File

October 11, 2026
Grok Imagine Video API: Animate a Product Image

Grok Imagine Video API: Animate a Product Image

October 18, 2026
How to Extend a Veo 3.1 Video Through an API

How to Extend a Veo 3.1 Video Through an API

October 18, 2026