---
url: https://docs.freetheai.org/api/audio-speech.md
description: >-
  POST /v1/audio/speech - turn text into spoken audio in the OpenAI Speech
  format, priced per million characters.
---

# Speech

Turns text into spoken audio in the OpenAI Speech format. Speech models are paid models from providers: each one's price per million characters is on its page at [freetheai.org/models](https://freetheai.org/models?kind=audio).

`POST https://api.freetheai.org/v1/audio/speech`

## Request

::: code-group

```bash [curl]
curl https://api.freetheai.org/v1/audio/speech \
  -H "Authorization: Bearer $FTAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "MODEL_ID", "input": "Hello from FreeTheAI!", "voice": "alloy"}' \
  -o speech.mp3
```

```python [Python]
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.freetheai.org/v1", api_key=os.environ["FTAI_KEY"])

audio = client.audio.speech.create(model="MODEL_ID", input="Hello from FreeTheAI!", voice="alloy")
audio.write_to_file("speech.mp3")
```

```ts [TypeScript]
import { writeFile } from 'node:fs/promises'
import OpenAI from 'openai'

const client = new OpenAI({ baseURL: 'https://api.freetheai.org/v1', apiKey: process.env.FTAI_KEY })

const audio = await client.audio.speech.create({ model: 'MODEL_ID', input: 'Hello from FreeTheAI!', voice: 'alloy' })
await writeFile('speech.mp3', Buffer.from(await audio.arrayBuffer()))
```

:::

| Field | Type | Description |
| --- | --- | --- |
| `model` | string | A speech model ID from [`GET /v1/models`](/api/models) (`"type": "speech"`). |
| `input` | string | The text to speak, at most 4,096 characters. |
| `voice` | string | The voice. Names depend on the model; see its page. |
| `instructions` | string | Optional. How to speak (tone, pace), for models that support it. |
| `response_format` | string | Optional. `mp3` (default), `opus`, `aac`, `flac`, `wav`, or `pcm`. |
| `speed` | number | Optional. Speaking speed, for models that support it. |

## Response

The audio file itself, with a matching `Content-Type` (for example `audio/mpeg`). You are charged for the characters in `input`.

## Errors

| Status | Meaning |
| --- | --- |
| `400` | `input must be at most 4096 characters`, or another field has a value the endpoint does not take. Split long text into several requests. |
| `401` | Missing or invalid API key. |
| `402` | Not enough wallet balance, or the key's budget is used ([paid usage errors](/errors#billing)). |
| `404` | No model has that ID, or none of the providers you follow serve it. |
| `502` / `503` | The provider failed or is busy. Retry; a failed request is not charged. |
