# Give your app a voice with text-to-speech in AI Gateway

> Turn text into speech with Gemini, xAI, MiniMax, and Qwen voices on your ngrok credits, or bring your own Groq and Mistral keys.

- Date: 2026-10-30
- Shipped by: Mohamed, Brenden Ehlers, and Jarod Clark
- Products: AI Gateway
- URL: https://ngrok.com/changelog/ai-gateway-text-to-speech

Every on-call robot deserves a proper voicemail greeting. AI Gateway now serves text-to-speech models from six providers, so the access key that answers your chat requests can also read your text out loud.

We wrote the robot a greeting and sent it to four voices:

> Hi, you've reached the on-call robot. I'm restarting the database for the third time tonight. Leave a message after the beep, or open a ticket like a civilized human. Beep.

<Figure className="grid gap-6 sm:grid-cols-2">
	<div>
		<p className="mb-2 font-sans text-sm text-muted">Gemini 3.8 Flash TTS, $0.00265</p>
		<audio
			controls
			preload="metadata"
			aria-label="Gemini 3.8 Flash TTS reading the greeting"
			src="https://ngrok.com/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/gemini-3.8-flash-tts.mp3"
			className="w-full"
		>
			<a href="/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/gemini-3.8-flash-tts.mp3">
				Download the Gemini 3.8 Flash TTS greeting (MP3)
			</a>
		</audio>
	</div>
	<div>
		<p className="mb-2 font-sans text-sm text-muted">Grok TTS, $0.00258</p>
		<audio
			controls
			preload="metadata"
			aria-label="Grok TTS reading the greeting"
			src="https://ngrok.com/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/grok-tts.mp3"
			className="w-full"
		>
			<a href="/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/grok-tts.mp3">
				Download the Grok TTS greeting (MP3)
			</a>
		</audio>
	</div>
	<div>
		<p className="mb-2 font-sans text-sm text-muted">MiniMax Speech 2.8 Turbo, $0.01032</p>
		<audio
			controls
			preload="metadata"
			aria-label="MiniMax Speech 2.8 Turbo reading the greeting"
			src="https://ngrok.com/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/speech-2.8-turbo.mp3"
			className="w-full"
		>
			<a href="/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/speech-2.8-turbo.mp3">
				Download the MiniMax Speech 2.8 Turbo greeting (MP3)
			</a>
		</audio>
	</div>
	<div>
		<p className="mb-2 font-sans text-sm text-muted">Qwen3-TTS-Flash, $0.00172</p>
		<audio
			controls
			preload="metadata"
			aria-label="Qwen3-TTS-Flash reading the greeting"
			src="https://ngrok.com/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/qwen3-tts-flash.mp3"
			className="w-full"
		>
			<a href="/blog-assets/audio/2026-10-30-ai-gateway-text-to-speech/qwen3-tts-flash.mp3">
				Download the Qwen3-TTS-Flash greeting (MP3)
			</a>
		</audio>
	</div>
</Figure>

![The AI Gateway Activity page in dark mode with four successful requests from the access key on-call-robot. Gemini 3.8 Flash TTS used 334 tokens and cost $0.00265. Grok TTS, Speech 2.8 Turbo, and Qwen3-TTS-Flash each billed 172 characters and cost $0.00258, $0.01032, and $0.00172.](https://ngrok.com/blog-assets/images/2026-10-30-ai-gateway-text-to-speech/activity-four-voices-dark.jpg)

Same 172 characters, four robots, and a price spread of about 6x: Qwen3-TTS-Flash cost $0.00172, Grok TTS $0.00258, Gemini 3.8 Flash TTS $0.00265, and MiniMax's Speech 2.8 Turbo $0.01032. Audition voices against your real script, then pick one for its sound and its cost. Switching providers changes the endpoint and the model, not your key or your bill.

Speech models arrive two ways. Google's Gemini TTS models run on the Gemini Interactions and GenerateContent APIs and bill per token. Prices are per million tokens:

| Model ID                    | Input | Audio output |
| --------------------------- | ----- | ------------ |
| `gemini-3.8-flash-tts`      | $0.50 | $9.00        |
| `gemini-3.8-flash-lite-tts` | $0.50 | $6.00        |

The rest use each provider's own speech endpoint and bill per character of the text you send:

| Model ID                                        | Provider | Endpoint                                                 | Per million characters |
| ----------------------------------------------- | -------- | -------------------------------------------------------- | ---------------------- |
| `qwen3-tts-flash`                               | Qwen     | `/api/v1/services/aigc/multimodal-generation/generation` | $10.00                 |
| `grok-tts`                                      | xAI      | `/v1/tts`                                                | $15.00                 |
| `qwen-audio-3.1-tts-plus`                       | Qwen     | `/api/v1/services/audio/tts/SpeechSynthesizer`           | $30.00                 |
| `speech-2.8-turbo`                              | MiniMax  | `/v1/t2a_v2`                                             | $60.00                 |
| `speech-2.8-hd`                                 | MiniMax  | `/v1/t2a_v2`                                             | $100.00                |
| `qwen-audio-3.1-tts-flash`                      | Qwen     | `/api/v1/services/audio/tts/SpeechSynthesizer`           | Your own Qwen key      |
| `orpheus-v1-english`, `orpheus-arabic-saudi`    | Groq     | `/v1/audio/speech`                                       | Your own Groq key      |
| `voxtral-mini-tts-3-0`, `voxtral-mini-tts-2603` | Mistral  | `/v1/audio/speech`                                       | Your own Mistral key   |

Google's Gemini TTS rates double on January 1, 2027, so check [**Model Catalog**](https://app.ngrok.ai/models) for current pricing. With your own provider key attached to the gateway, that provider bills you directly.

Each speech endpoint keeps its provider's request and response format. If your code already calls xAI, MiniMax, or Qwen for speech, point it at `https://gateway.ngrok.ai` and swap in your ngrok access key.

In the [playground](https://app.ngrok.ai/playground), pick **Gemini 3.8 Flash TTS** or **Gemini 3.8 Flash-Lite TTS**, type a script, and the reply comes back as audio you can play and **Download**. The per-character models show up in the model picker too, but the playground can't call their endpoints yet, so try them from your code.

For a model that talks back instead of reading a script, try **GPT Audio 1.5** (`gpt-audio-1.5`) on chat completions. It answers with text and audio in the same reply, and the playground plays it with a transcript. Audio costs $32.00 per million input tokens and $64.00 per million output tokens.

## Get started

[Create an ngrok account or sign in](https://app.ngrok.ai/). Create an [**access key**](https://app.ngrok.ai/keys) that allows your chosen provider, and confirm your account has credits. To use your own provider key instead, attach it to the gateway. The Groq, Mistral, and `qwen-audio-3.1-tts-flash` models need one.

To hear the greeting before you write any code, paste it into the [playground](https://app.ngrok.ai/playground) with **Gemini 3.8 Flash TTS**.

This example uses Google's Gen AI SDK for TypeScript, because Gemini TTS runs on Google's native Interactions API. The [Google Gen AI SDK guide](https://ngrok.com/docs/ai-gateway/sdks/google) covers the rest of the SDK setup. Install the SDK and a TypeScript runner:

```bash
npm install @google/genai && npm install --save-dev tsx
```

Save your ngrok access key in `.env.local`. Keep this file out of version control:

```bash
AI_GATEWAY_API_KEY=your_access_key_here
```

The example records the robot's greeting in Gemini's **Kore** voice and saves it to disk. `response_format` asks for audio, and `speech_config` picks the voice. Use an ES module project (`"type": "module"` in `package.json`) for top-level `await`. Save this example as `index.ts`:

```typescript
import { writeFile } from "node:fs/promises";
import { GoogleGenAI } from "@google/genai";

const client = new GoogleGenAI({
	apiKey: process.env.AI_GATEWAY_API_KEY,
	httpOptions: {
		baseUrl: "https://gateway.ngrok.ai",
		apiVersion: "v1beta",
	},
});

const interaction = await client.interactions.create({
	model: "gemini-3.8-flash-tts",
	input:
		"Hi, you've reached the on-call robot. I'm restarting the database for the third time tonight. Leave a message after the beep, or open a ticket like a civilized human. Beep.",
	response_format: { type: "audio" },
	generation_config: { speech_config: [{ voice: "Kore" }] },
});

const greeting = interaction.output_audio;
if (greeting?.data) {
	await writeFile("voicemail.wav", Buffer.from(greeting.data, "base64"));
	console.log(`Saved voicemail.wav (${greeting.mime_type})`);
}
```

Run the example from your project directory:

```bash
node --env-file=.env.local --import tsx index.ts
```

`interaction.output_audio.data` holds the recording as base64. Our run saved a 12-second, 24 kHz mono WAV:

```text
Saved voicemail.wav (audio/wav)
```

To try the cheaper voice, change `model` to `"gemini-3.8-flash-lite-tts"`.

The per-character endpoints take plain HTTP. This version sends the same greeting to xAI's `/v1/tts` with Node.js's built-in `fetch`, so it doesn't need an SDK. Run it on Node.js 20.6 or later, which supports `--env-file`. Save it as `xai.ts` in the same project:

```typescript
import { writeFile } from "node:fs/promises";

const response = await fetch("https://gateway.ngrok.ai/v1/tts", {
	method: "POST",
	headers: {
		Authorization: `Bearer ${process.env.AI_GATEWAY_API_KEY}`,
		"Content-Type": "application/json",
	},
	body: JSON.stringify({
		text: "Hi, you've reached the on-call robot. I'm restarting the database for the third time tonight. Leave a message after the beep, or open a ticket like a civilized human. Beep.",
		language: "en",
	}),
});

if (!response.ok) {
	throw new Error(`${response.status}: ${await response.text()}`);
}

await writeFile("voicemail.mp3", Buffer.from(await response.arrayBuffer()));
console.log("Saved voicemail.mp3");
```

Run it with `node --env-file=.env.local --import tsx xai.ts`. xAI's body names no model, so the gateway sends it to `grok-tts`, and the MP3 comes back as the response body. xAI requires `language`, and the request fails without it.

Open [**Activity**](https://app.ngrok.ai/activity) and find your greetings. Each row shows the model, provider, status, and cost. **Usage** shows tokens for Gemini and billed characters for the per-character models.
