# Audio

> Speech-to-text with POST /v1/audio/transcriptions, text-to-speech with POST /v1/audio/speech, and audio answers from chat completions: models, voices, formats and pricing.

```text
POST https://api.clonvo.com/v1/audio/transcriptions
POST https://api.clonvo.com/v1/audio/speech
```

Turn speech into text and text into speech. Both endpoints follow OpenAI's Audio API, so the OpenAI SDKs work by changing the base URL, and use the same API key, credits, your own provider keys and spending limits as chat completions. Speech and transcription models only serve these endpoints: sending one to chat completions returns `400` with the code `model_not_chat`. Some chat models also answer with audio, through chat completions (see [Audio output from chat](#audio-output-from-chat)).

## Speech to text

| Model id | Provider | Audio | Price |
| --- | --- | --- | --- |
| `openai/gpt-transcribe` | OpenAI | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 25 MB | $0.0045 per minute |
| `mistralai/voxtral-mini-transcribe-3-0` | Mistral | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 25 MB | $0.0035 per minute |
| `mistralai/voxtral-small-transcribe-3-0` | Mistral | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 25 MB | $0.004 per minute |
| `google/gemini-3.5-transcribe` | Google AI Studio | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 20 MB and 60 minutes | $2.00 per 1M audio tokens in, $12.00 per 1M text tokens out |
| `x-ai/grok-voice-transcribe-2.0` | xAI | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 25 MB | $0.0017 per minute |
| `qwen/qwen3-asr-flash` | Alibaba Cloud (Qwen) | MP3, WAV, M4A, OGG, FLAC, WebM and more, up to 7 MB and 5 minutes | $0.0021 per minute |
| `meta/muse-voice-transcribe-1.0` | Meta | WAV only, up to 32 MB and 10 minutes | $0.003 per minute |

Send the audio as multipart form data, as with OpenAI:

```ts
import fs from "node:fs";
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.clonvo.com/v1", apiKey: process.env.CLONVO_API_KEY });

const transcription = await client.audio.transcriptions.create({
  model: "openai/gpt-transcribe",
  file: fs.createReadStream("meeting.mp3"),
});
console.log(transcription.text);
```

Or as JSON, as on OpenRouter: `{"model": "x-ai/grok-voice-transcribe-2.0", "input_audio": {"data": "<base64>", "format": "mp3"}}`.

| Parameter | Type | Description |
| --- | --- | --- |
| `file` | file | **Required** (multipart). The audio. Up to 25 MB unless the table says otherwise. |
| `input_audio` | object | **Required** (JSON). `data` (base64, with or without a `data:` prefix) and `format` (`mp3`, `wav`, `m4a`, …). |
| `model` | string | **Required.** A model id from the table above. |
| `language` | string | The spoken language as an ISO-639-1 code (`en`, `fr`). Improves accuracy; most models detect it otherwise. |
| `prompt` | string | Words or context to expect. OpenAI only. |
| `response_format` | string | `json` (default), `verbose_json` (adds `language`, `duration` and, on xAI, word timestamps), or `text`. |
| `provider` | object | **Extension.** `order` and `allow_fallbacks` choose between your own key and credits (see [Fallbacks and routing](https://clonvo.com/docs/fallbacks.md)). |

```json
{
  "text": "Hello from Clonvo.",
  "usage": { "seconds": 5, "input_tokens": 0, "output_tokens": 0, "cost": 0.000375, "is_byok": false },
  "model": "openai/gpt-transcribe",
  "provider": "OpenAI"
}
```

`usage.cost` is what the request cost. Models priced per minute report the billed `seconds`; Gemini reports tokens.

## Text to speech

| Model id | Provider | Formats | Voices | Max input | Price |
| --- | --- | --- | --- | --- | --- |
| `google/gemini-3.8-flash-tts` | Google AI Studio | wav, pcm | 30 (default `Kore`) | 30,000 characters | $0.50 per 1M text tokens in, $9.00 per 1M audio tokens out |
| `google/gemini-3.8-flash-lite-tts` | Google AI Studio | wav, pcm | 30 (default `Kore`) | 30,000 characters | $0.50 per 1M text tokens in, $6.00 per 1M audio tokens out |
| `mistralai/voxtral-mini-tts-3-0` | Mistral | mp3, wav, pcm, flac, opus | 36 (default `voice_478`) | 20,000 characters | $13.00 per 1M characters |
| `x-ai/grok-voice-tts-1.0` | xAI | mp3, wav, pcm | 26 (default `eve`) | 60,000 characters | $15.00 per 1M characters |
| `qwen/qwen3-tts-flash` | Alibaba Cloud (Qwen) | wav, pcm | 48 (default `Cherry`) | 600 characters | $10.00 per 1M characters |
| `qwen/qwen-audio-3.0-tts-flash` | Alibaba Cloud (Qwen) | mp3, wav, opus, pcm | 12 (default `loongeva_v3.6`) | characters | $15.00 per 1M characters |
| `qwen/qwen-audio-3.0-tts-plus` | Alibaba Cloud (Qwen) | mp3, wav, opus, pcm | 2 (default `longanlingxin`) | characters | $20.00 per 1M characters |

```ts
const speech = await client.audio.speech.create({
  model: "google/gemini-3.8-flash-tts",
  input: "Your order has shipped.",
  voice: "Kore",
  response_format: "wav",
});
fs.writeFileSync("order.wav", Buffer.from(await speech.arrayBuffer()));
```

| Parameter | Type | Description |
| --- | --- | --- |
| `model` | string | **Required.** A model id from the table above. |
| `input` | string | **Required.** The text to speak, up to the model's limit. |
| `voice` | string | One of the model's voices (matched without regard to case). Defaults to its first voice. `GET /v1/models?output_modalities=speech` lists them in `supported_voices`. |
| `response_format` | string | A format from the table; defaults to the model's first. `pcm` is raw 16-bit little-endian samples without a header. |
| `speed` | number | xAI only: 0.7 to 1.5. |
| `instructions` | string | Gemini only: how to say it ("cheerful and friendly"). |

The response is the audio itself, with its `Content-Type` (`audio/wav`, `audio/mpeg`, …) and the `x-clonvo-generation-id` header; look up its cost with `GET /v1/generation?id=…` (see [Other endpoints](https://clonvo.com/docs/other-endpoints.md)).

## Audio output from chat

| Model id | Provider | Formats | Voices | Price |
| --- | --- | --- | --- | --- |
| `openai/gpt-audio-1.5` | OpenAI | mp3, wav, aac, flac, opus, pcm16 | 10 (default `alloy`) | $2.50 / $10.00 per 1M text tokens in / out, $32.00 / $64.00 per 1M audio tokens in / out |
| `google/lyria-3.5` | Google AI Studio | mp3, wav | Music | $0.08 per song |
| `google/lyria-3-clip-preview` | Google AI Studio | mp3 | Music | $0.04 per song |
| `google/lyria-3-pro-preview` | Google AI Studio | mp3 | Music | $0.08 per song |

Send `modalities: ["text", "audio"]` and `audio: {voice, format}` to `POST /v1/chat/completions`, as on OpenRouter and OpenAI:

```ts
const completion = await client.chat.completions.create({
  model: "openai/gpt-audio-1.5",
  modalities: ["text", "audio"],
  audio: { voice: "alloy", format: "mp3" },
  messages: [{ role: "user", content: "Say hello in a friendly tone." }],
});
const audio = completion.choices[0].message.audio;
fs.writeFileSync("hello.mp3", Buffer.from(audio.data, "base64"));
console.log(audio.transcript);
```

| Parameter | Type | Description |
| --- | --- | --- |
| `modalities` | array | `["text", "audio"]` for an answer with audio. Without it, GPT Audio answers in text. |
| `audio.voice` | string or object | One of the model's voices, or a custom OpenAI voice as `{"id": "voice_…"}`. Defaults to the model's first voice. |
| `audio.format` | string | A format from the table. Defaults to `mp3`, or `pcm16` when streaming on OpenAI. |

```json
{
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "audio": { "id": "audio_6af5…", "data": "<base64>", "transcript": "Hello there!", "expires_at": 1794485959, "format": "mp3" }
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 214,
    "prompt_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
    "completion_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 169 },
    "cost": 0.0113,
    "is_byok": false
  }
}
```

`message.audio.data` is the audio as base64 and `transcript` what it says. Audio tokens are billed at the model's audio prices and reported in `prompt_tokens_details.audio_tokens` and `completion_tokens_details.audio_tokens`. To continue a spoken conversation on OpenAI, send the assistant turn back as `{"role": "assistant", "audio": {"id": "audio_6af5…"}}` until `expires_at`.

With `stream: true` the audio arrives in `delta.audio` pieces: join every `data` (base64) and every `transcript` in order. OpenAI streams `pcm16` by default, raw 16-bit 24 kHz mono samples without a header.

Lyria models write music. They always answer with audio, with or without `modalities`. The prompt is the last user message (text and up to 10 images) and any system message; earlier turns are ignored. Lyria 3 Clip writes 30 seconds, Lyria 3.5 and Lyria 3 Pro a couple of minutes, steered by the prompt ("a 2-minute song"). `content` holds Lyria's text: the lyrics, a song structure or `<instrumental>`. Each song costs the model's per-song price, and a streamed request gets the song in one chunk once it's written.

## Listing audio models

`GET /v1/models?output_modalities=transcription` and `?output_modalities=speech` list them, as on OpenRouter; they aren't in the default list, which holds chat models. `?output_modalities=audio` lists the chat models that answer with audio; they have `output_modalities: ["text", "audio"]` and are in the default list too. Per-minute models list their price per second in `pricing.prompt`, and per-character models their price per character, as OpenRouter does.

## Errors

Asking for audio from a chat model that can't answer with it, or for a format it doesn't return, returns `400` `unsupported_parameter`. Wrong-kind models return `400` `model_wrong_kind`; voices, formats and lengths a model doesn't take return `400` with `unsupported_voice`, `unsupported_parameter` or `input_too_long`; files over the limit return `413`. Everything else is as for chat (see [Errors](https://clonvo.com/docs/errors.md)).
