The Voices API
On this page
Course updated November 3, 2026 for Voxtral TTS 3, based on the Migrate from Voxtral 2 guide and Mistral’s Text to Speech pages:
voxtral-mini-tts-2603, deprecated October 31, 2026 and removed April 30, 2027, is replaced in examples byvoxtral-mini-tts-3-0. Voxtral 2 predefined voices (gb_jane_neutral…) remain accepted; Voxtral 3 adds[emotion=…]and[pace=…]tags in text, theexpressivenesssetting, custom pronunciation (phoneme_hints), and 35 languages. Mistral recommends re-measuring latency after migration. Sources: Migrate from Voxtral 2 · Speech generation.
The /v1/voices Endpoint
Mistral’s Voices API is your entry point for managing custom voices. It exposes a full set of CRUD operations—Create, Read, Update, Delete—letting you create, list, retrieve, modify, and delete voices. If you have worked with a standard REST API before, you are on familiar ground: nothing here deals directly with audio processing; this is purely about managing a catalog of objects.
Every voice created via the API receives a unique identifier, the voice_id, which you will use later to generate speech. Keep this in mind: voices are persistent. Once created, they remain available in your account until explicitly deleted. You do not need to resend the audio sample for every generation, so your applications only need to store a string in their configuration.
Creating a Voice
Creation happens via a POST call to the /v1/voices endpoint. You provide an audio sample encoded in base64 along with descriptive metadata:
import base64
from pathlib import Path
from mistralai.client import Mistral
client = Mistral(api_key="your-api-key")
# Encode the audio sample to base64
sample_audio_b64 = base64.b64encode(
Path("sample.mp3").read_bytes()
).decode()
# Create the voice
voice = client.audio.voices.create(
name="my-pro-voice",
sample_audio=sample_audio_b64,
sample_filename="sample.mp3",
languages=["fr", "en"],
gender="female",
age=35,
tags=["professional", "podcast"]
)
print(f"Voice created: {voice.id}")
Using base64 is necessary because the request is a JSON document, and JSON cannot carry binary data. The API returns an object containing the voice_id that you will keep for all generation requests. In the example above, we print it, but in production you should write it to your configuration or database.
Listing, Retrieving, and Modifying
To retrieve a list of all your voices, the list() method supports pagination:
# Get the first 10 voices
voices = client.audio.voices.list(limit=10, offset=0)
for v in voices.items:
print(f"{v.id} — {v.name} ({v.gender}, {v.languages})")
Pagination is offset-based: you specify the number of items with limit and the starting point with offset. To browse Mistral’s predefined voices as well (Marie in French, fr_marie_neutral, Jane in British English, etc.), voices.search lists both families, distinguished by the type field: preset or custom. To get the second page of ten voices, you call the method with offset=10. This mechanism becomes useful as soon as an agency manages voices for dozens of clients.
When you need details on a specific voice, get() returns its full metadata:
voice = client.audio.voices.get(voice_id="your-voice-id")
print(f"Name: {voice.name}")
print(f"Gender: {voice.gender}")
print(f"Languages: {voice.languages}")
print(f"Tags: {voice.tags}")
Make it a habit to call this operation before a major generation run. This verifies that the voice_id hardcoded in your application points to the expected voice and not one from an old project.
You can modify the metadata of an existing voice without touching the audio sample:
updated_voice = client.audio.voices.update(
voice_id="your-voice-id",
name="my-pro-voice-v2",
languages=["fr", "en", "es"],
tags=["professional", "podcast", "multilingual"]
)
print(f"Voice updated: {updated_voice.name}")
Modifiable fields include name, languages, gender, age, tags, and description. The original audio sample, however, cannot be modified. If you want to change the audio, you must create a new voice. In practice, a poorly recorded voice cannot be repaired—it must be replaced, and you will need to propagate the new voice_id across your applications.
Deleting and Retrieving the Sample
Deletion is permanent and irreversible:
client.audio.voices.delete(voice_id="your-voice-id")
print("Voice deleted")
After deletion, any generation request using that voice_id will fail. A classic nightmare scenario: a developer cleans up test voices, accidentally deletes one that is actually powering the support IVR, and the incident breaks the next morning on the first incoming call. Always ensure your applications are updated before deleting a voice in production.
You can also download the original audio used to create a voice:
response = client.audio.voices.get_sample_audio(voice_id="your-voice-id")
Path("retrieved_sample.mp3").write_bytes(response.content)
This feature helps you archive your samples or verify the source audio quality if a voice disappoints you. By listening to the original, you often discover that the flaw heard during generation was already present in the recording.
Organizing Your Voice Catalog
Clean management costs little and prevents significant confusion. Name your voices clearly with a project prefix, following patterns like podcast-narrator or app-assistant-fr, rather than voice1 and test-final-2. Use tags to categorize by use case, project, or client, making lists manageable as they grow. Document voice_ids in your application configuration, never in an isolated file on a workstation. And never delete a production voice without first verifying that it is no longer referenced anywhere.
Key Takeaways
- The Voices API exposes full CRUD capabilities: create, list, retrieve, update, delete
- Each voice receives a unique
voice_idused in generation requests - Offset-based pagination lets you manage a large number of voices
- Deletion is permanent—all requests using that voice_id will fail
- The original audio sample can be retrieved via the sample endpoint