Mandarin museum audio guide — A Mandarin guide script; the language is detected from the text.
Gemini 3.8 Flash TTS Text to Speech API
google/gemini-3.8-flash/text-to-speechGemini 3.8 Flash TTS Text to Speech turns scripts and two-speaker dialogues into WAV speech across 130 languages with 30 preset voices. Give the whole request and each line its own style instructions, so delivery follows your direction while the transcript is read as written.
Input
Examples
Gemini 3.8 Flash TTS Text to Speech API
Generate speech with the API
Submit a script, keep the returned task_id, and retrieve the completed audio through the task status endpoint.
Authenticate your request
Send your Vidgo API key in the Authorization header using Bearer authentication.
- Endpoint
- POST
https://api.vidgo.ai/api/generate/submit - Authentication
- Authorization: Bearer YOUR_API_KEY
Submit the script or dialogue
Send model and input as JSON. The example below uses the first audio sample on this page.
REQUEST_BODY=$(cat <<'JSON'
{
"model": "google/gemini-3.8-flash/text-to-speech",
"input": {
"text": "The snow had been falling for three days when the letter arrived. It carried no stamp, no return address, only my name, written in my grandmother's careful hand.",
"voice": "Charon",
"style_instructions": "Read like a seasoned audiobook narrator: unhurried, low and warm, with a short pause after each sentence.",
"enable_safety_checker": true
}
}
JSON
)
RESPONSE=$(curl --silent --show-error --fail-with-body \
--request POST \
--url "https://api.vidgo.ai/api/generate/submit" \
--header "Authorization: Bearer $VIDGO_API_KEY" \
--header "Content-Type: application/json" \
--data "$REQUEST_BODY")
CODE=$(printf '%s' "$RESPONSE" | jq -r '.code // empty')
if [ "$CODE" != "0" ] && [ "$CODE" != "200" ]; then
printf 'API error: %s
' "$RESPONSE" >&2
exit 1
fi
printf '%s
' "$RESPONSE"Follow the task
Query the returned task_id until status is finished or failed.
Status endpoint
GET https://api.vidgo.ai/api/generate/status/{task_id}Keep the task_id from submission. Check its status and read the generated files when it finishes.
not_startedrunningfinishedfailed{
"code": 200,
"data": {
"task_id": "3LCLZTC34PBO54EP",
"status": "not_started",
"created_time": "2026-11-05T07:14:43"
}
}{
"code": 200,
"data": {
"task_id": "3LCLZTC34PBO54EP",
"status": "finished",
"files": [
{
"file_url": "https://cdn.vidgo.ai/apis/models/google/gemini-3.8-flash/text-to-speech/v2/02/speech-01.wav",
"file_type": "audio",
"file_name": "speech-01.wav"
}
],
"created_time": "2026-11-05T07:14:43",
"error_message": null,
"progress": 100
}
}Read the audio files
Use the audio file_url to play or download the WAV file.
set -euo pipefail
: "${VIDGO_API_KEY:?Set VIDGO_API_KEY in your environment}"
REQUEST_BODY=$(cat <<'JSON'
{
"model": "google/gemini-3.8-flash/text-to-speech",
"input": {
"text": "The snow had been falling for three days when the letter arrived. It carried no stamp, no return address, only my name, written in my grandmother's careful hand.",
"voice": "Charon",
"style_instructions": "Read like a seasoned audiobook narrator: unhurried, low and warm, with a short pause after each sentence.",
"enable_safety_checker": true
}
}
JSON
)
SUBMIT_RESPONSE=$(curl --silent --show-error --fail-with-body \
--request POST \
--url "https://api.vidgo.ai/api/generate/submit" \
--header "Authorization: Bearer $VIDGO_API_KEY" \
--header "Content-Type: application/json" \
--data "$REQUEST_BODY")
TASK_ID=$(printf '%s' "$SUBMIT_RESPONSE" | jq -r '.data.task_id // .task_id // empty')
BUSINESS_CODE=$(printf '%s' "$SUBMIT_RESPONSE" | jq -r '.code // empty')
if [ "$BUSINESS_CODE" != "0" ] && [ "$BUSINESS_CODE" != "200" ]; then
printf 'Submit failed:
%s
' "$SUBMIT_RESPONSE" >&2
exit 1
fi
if [ -z "$TASK_ID" ]; then
printf 'Submit response did not include task_id:
%s
' "$SUBMIT_RESPONSE" >&2
exit 1
fi
START_TIME=$(date +%s)
POLL_DELAY=2
while true; do
if [ $(( $(date +%s) - START_TIME )) -ge 600 ]; then
printf 'Timed out after 600 seconds
' >&2
exit 1
fi
STATUS_RESPONSE=$(curl --silent --show-error --fail-with-body \
--url "https://api.vidgo.ai/api/generate/status/$TASK_ID" \
--header "Authorization: Bearer $VIDGO_API_KEY")
STATUS=$(printf '%s' "$STATUS_RESPONSE" | jq -r '.data.status // .status // empty')
BUSINESS_CODE=$(printf '%s' "$STATUS_RESPONSE" | jq -r '.code // empty')
if [ "$BUSINESS_CODE" != "0" ] && [ "$BUSINESS_CODE" != "200" ]; then
printf 'Status request failed:
%s
' "$STATUS_RESPONSE" >&2
exit 1
fi
case "$STATUS" in
finished)
printf '%s' "$STATUS_RESPONSE" | jq -r '(.data.files // .files // [])[]?.file_url'
break
;;
failed)
printf '%s' "$STATUS_RESPONSE" | jq -r '.data.error_message // .error_message // "Generation failed"' >&2
exit 1
;;
not_started|running)
sleep "$POLL_DELAY"
if [ "$POLL_DELAY" -lt 10 ]; then POLL_DELAY=$((POLL_DELAY + 1)); fi
;;
*)
printf 'Unexpected task status: %s
' "$STATUS" >&2
exit 1
;;
esac
doneRequest parameters
Place speech controls inside input; keep model and callback_url at the top level.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| model | string | Yes | — | Use google/gemini-3.8-flash/text-to-speech to select this speech model. |
| input | object | Yes | — | Use text and voice for one speaker, or speakers and turns for a dialogue, plus the optional fields below. |
| input.text | string | Single speaker | — | Single speaker: the script to speak. Write the words as they should be heard; place acting directions in Style Instructions. |
| input.voice | string | Optional | Kore | Single speaker: one of the 30 preset voices. Default Kore. Voices: Achernar, Achird, Algenib, Algieba, Alnilam, Aoede, Autonoe, Callirrhoe, Charon, Despina, Enceladus, Erinome, Fenrir, Gacrux, Iapetus, Kore, Laomedeia, Leda, Orus, Pulcherrima, Puck, Rasalgethi, Sadachbia, Sadaltager, Schedar, Sulafat, Umbriel, Vindemiatrix, Zephyr, Zubenelgenubi. |
| input.speakers | array | Dialogue | — | Dialogue: exactly two speakers, each with a unique speaker_id and one of the 30 preset voices. |
| input.speakers[].speaker_id | string | Per item | — | A unique, non-empty name for the speaker, such as Host. |
| input.speakers[].voice | string | Per item | — | The speaker's preset voice. Voices: Achernar, Achird, Algenib, Algieba, Alnilam, Aoede, Autonoe, Callirrhoe, Charon, Despina, Enceladus, Erinome, Fenrir, Gacrux, Iapetus, Kore, Laomedeia, Leda, Orus, Pulcherrima, Puck, Rasalgethi, Sadachbia, Sadaltager, Schedar, Sulafat, Umbriel, Vindemiatrix, Zephyr, Zubenelgenubi. |
| input.turns | array | Dialogue | — | Dialogue: the lines in order. Each turn names a speaker_id from Speakers, its text, and optional style_instructions for that line. |
| input.turns[].speaker_id | string | Per item | — | The speaker_id of the speaker who says this line. |
| input.turns[].text | string | Per item | — | The words of this line, not blank. |
| input.turns[].style_instructions | string | Optional | — | Optional direction for this line only. |
| input.style_instructions | string | Optional | — | Optional delivery direction for the whole request, such as tone, pace or setting. Its characters count toward billing. |
| input.enable_safety_checker | boolean | Optional | true | Runs the upstream safety checker on the request. Default true. |
| callback_url | string | No | — | Optional HTTP or HTTPS URL for task notifications. Include it at the top level of the request. |
Response fields
Submission identifies the task. Status responses report progress toward the completed audio.
| Field | Type | Description |
|---|---|---|
| code | integer | Response code. A successful response uses 200 or 0. |
| data.task_id | string | Task identifier used to query status. |
| data.status | string | Task state: not_started, running, finished, or failed. |
| data.created_time | string | Task creation time returned by the service. |
| data.files | array | Generated files; the audio entry holds the WAV speech. |
| data.files[].file_url | string | URL used to play or download a generated file. |
| data.files[].file_type | string | audio for the generated speech. |
| data.files[].file_name | string | File name, when returned. |
| data.error_message | string | null | Error details when a task fails. |
Task lifecycle
Use the task state to decide when to check again or read the result.
not_startedThe task has been accepted and is waiting to start.
runningSpeech generation is in progress. Continue checking the same task.
finishedGeneration is complete. Read files for the WAV audio.
failedGeneration failed. Read error_message before deciding whether to submit a new request.
Handle results and interruptions
- Keep the current task identifierIf a status request is interrupted, query the same task_id again to recover its latest state.
- Match each file to its purposeRead the audio entry in files and use its file_url and file_name for download.
- Inspect a failed taskWhen status is failed, read error_message and review the script and settings before submitting another generation.
Speech specifications
| Item | Value | Description |
|---|---|---|
| Task | Text to Speech | Single-speaker speech or a two-speaker dialogue. |
| Voices | 30 presets | Kore by default; one voice per speaker in dialogue. |
| Speakers | 1 or 2 | Dialogue uses exactly two speakers and one or more turns. |
| Languages | 130 | Detected automatically from the transcript. |
| Output | WAV | One audio file per task. |
| Price | $0.045 / 1K characters | 9 credits per 1,000 billable characters. |
Explore more speech models
Gemini 3.8 Flash TTS Text to Speech API frequently asked questions
What is the Gemini 3.8 Flash TTS Text to Speech API?
Gemini 3.8 Flash TTS Text to Speech is a Google model for generating natural speech from text. It produces single-voice narration or two-speaker dialogue in 130 languages with 30 preset voices and style instructions for tone and pace. Google built the 3.8 Flash tier for voice fidelity and acting nuance, and it reads the transcript as written while following your direction. You can call it programmatically or try it from the playground above.
How do I create a two-speaker dialogue with Gemini 3.8 Flash TTS?
Choose Dialogue and send exactly two speakers, each with a speaker_id and a preset voice, plus a turns list. Every turn names one speaker_id, its text and an optional style_instructions. Top-level text and voice are left out in this form.
Where should acting directions go in Gemini 3.8 Flash TTS?
Put them in style_instructions, either for the whole request or for a single turn. Google notes that Gemini 3.8 TTS reads the transcript literally, so directions written inside the text may be spoken aloud.
Which voices does Gemini 3.8 Flash TTS offer?
There are 30 presets: Achernar, Achird, Algenib, Algieba, Alnilam, Aoede, Autonoe, Callirrhoe, Charon, Despina, Enceladus, Erinome, Fenrir, Gacrux, Iapetus, Kore, Laomedeia, Leda, Orus, Pulcherrima, Puck, Rasalgethi, Sadachbia, Sadaltager, Schedar, Sulafat, Umbriel, Vindemiatrix, Zephyr, Zubenelgenubi. Kore is the default for a single speaker.
How does Gemini 3.8 Flash TTS handle languages?
Gemini 3.8 Flash TTS detects the language from the transcript across 130 languages. Write each script in its target language; there is no separate language setting.
Should I choose Gemini 3.8 Flash TTS or Gemini 3.8 Flash Lite TTS?
Choose Gemini 3.8 Flash TTS when acting nuance, dialects and complex dialogue matter most; Google positions it as the flagship creative tier with 130 languages. Gemini 3.8 Flash Lite TTS covers 101 languages at 6 credits per 1,000 characters for high-volume work. Both accept the same fields.
What audio format does Gemini 3.8 Flash TTS return?
Each finished task returns a WAV file in files. Convert it to MP3 or Opus in your audio tool if your player or platform needs a compressed format.
How are Gemini 3.8 Flash TTS characters counted for billing?
Billing counts Text, Style Instructions, and in dialogue every turn's text and style instructions, at 9 credits ($0.045) per 1,000 characters. Speaker IDs are not counted.


