Guides

Synthèse vocale (TTS) par l'API : une voix française en 5 minutes

TchaviPar Gael — fondateur de Tchavi

Publié le · Mis à jour le · 10 min de lecture

Retour au blog

Sommaire

Pour donner une voix française à ton bot ou à ton app, il te faut un seul appel : POST /v1/audio/speech avec un texte, un modèle et une voix. La réponse est un fichier audio brut, pas du JSON. Tu l'enregistres, tu le joues ou tu l'envoies.

J'ai fait les appels pour de vrai en octobre 2026, via Tchavi, avec cURL, Node, Python et le SDK OpenAI, sur un message de livraison de 131 caractères. Voici le code, ce que j'ai mesuré, et comment tu vérifies que ce que tu reçois est bien de l'audio.

Mise à jour du 26 octobre 2026. OpenAI arrête tts-1, tts-1-hd et gpt-4o-mini-tts le 6 janvier 2027, et Tchavi cesse de les servir le même jour. Le code ci-dessous marche jusque-là. Ensuite, passe à voxtral-tts-3 (voix française fr_marie_neutral, mp3, 29 crédits pour 1 000 caractères) ou à gemini-3.8-flash-lite-tts (wav ou pcm, 38 crédits) : change le modèle et la voix. Détails dans la doc audio.

En bref

  • Tchavi, une passerelle d'API IA compatible OpenAI que tu paies en mobile money, expose POST /v1/audio/speech : le même format que l'API OpenAI, donc le SDK OpenAI marche en changeant la baseURL et la clé.
  • Trois modèles de synthèse vocale : tts-1 (32 crédits pour 1 000 caractères), tts-1-hd (64) et gpt-4o-mini-tts (40), le seul qui accepte des instructions de ton et de rythme.
  • La facture se calcule au caractère : mes quatre clips de 131 caractères ont coûté 4,192, 5,24, 5,24 et 8,384 crédits, exactement le prix par 1 000 caractères au prorata. Avec 3 crédits pour 1 F, la phrase la moins chère revient à 1,4 F.
  • Chaque appel a duré entre 1,8 et 2,3 secondes pour environ 8 à 10 secondes d'audio. Le fichier arrive en un bloc, il n'y a pas de lecture progressive dans ces tests.
  • Vérifie toujours le content-type : en cas d'erreur, tu reçois du JSON à la place de l'audio.

Le premier appel, avec cURL

Crée une clé dans ton tableau de bord, puis :

curl -X POST https://tchavi.com/api/v1/audio/speech \
  -H "Authorization: Bearer $TCHAVI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tts-1",
    "voice": "nova",
    "input": "Bonjour Awa, ta commande est partie de Cotonou. Le livreur arrive entre quinze heures et dix-sept heures. Merci pour ta confiance !"
  }' \
  -D - \
  -o livraison.mp3

L'option -D - affiche les en-têtes. Sur mon appel, j'ai obtenu content-type: audio/mpeg, 129 408 octets et x-credits-used: 4.192. Le MP3 est le format par défaut.

Les paramètres de la requête, tels que la documentation audio les décrit :

ParamètreRôle
modeltts-1, tts-1-hd ou gpt-4o-mini-tts
inputLe texte à dire : 4 096 caractères au maximum, 2 000 pour gpt-4o-mini-tts
voicealloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, et cedar, marin, verse en plus pour gpt-4o-mini-tts
instructionsgpt-4o-mini-tts seulement : comment parler
response_formatmp3 (par défaut), opus, aac, flac, wav, pcm
speedDe 0,25 à 4,0, par défaut 1,0

Node.js

Avec fetch, sans dépendance :

import { writeFileSync } from 'node:fs';

const res = await fetch('https://tchavi.com/api/v1/audio/speech', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.TCHAVI_API_KEY}`,
  },
  body: JSON.stringify({
    model: 'tts-1',
    voice: 'nova',
    input: 'Bonjour Awa, ta commande est partie de Cotonou.',
  }),
});

// fetch ne lève pas d'exception sur un 4xx ou un 5xx : on contrôle nous-mêmes.
const type = res.headers.get('content-type') ?? '';
if (!res.ok || !type.startsWith('audio/')) {
  throw new Error(`TTS refusé (${res.status}) : ${await res.text()}`);
}

const audio = Buffer.from(await res.arrayBuffer());
console.log(type, audio.length, 'octets,', res.headers.get('x-credits-used'), 'crédits');
writeFileSync('livraison.mp3', audio);

Python

import os
import requests

r = requests.post(
    "https://tchavi.com/api/v1/audio/speech",
    headers={"Authorization": f"Bearer {os.environ['TCHAVI_API_KEY']}"},
    json={
        "model": "tts-1-hd",
        "voice": "onyx",
        "input": "Bonjour Awa, ta commande est partie de Cotonou.",
        "response_format": "mp3",
    },
    timeout=60,
)
r.raise_for_status()
assert r.headers["content-type"].startswith("audio/"), r.text[:200]

print(len(r.content), "octets,", r.headers.get("x-credits-used"), "crédits")
open("livraison.mp3", "wb").write(r.content)

raise_for_status() couvre les erreurs HTTP. L'assert est là pour le cas où un proxy te renverrait une page HTML avec un code 200.

Le SDK OpenAI

Si ton code utilise déjà le SDK OpenAI, tu ne changes que l'adresse et la clé. C'est la version que j'ai exécutée, avec gpt-4o-mini-tts et la voix marin :

import OpenAI from 'openai';
import { writeFileSync } from 'node:fs';

const client = new OpenAI({
  apiKey: process.env.TCHAVI_API_KEY,
  baseURL: 'https://tchavi.com/api/v1',
});

const res = await client.audio.speech.create({
  model: 'gpt-4o-mini-tts',
  voice: 'marin',
  input: 'Bonjour Awa, ta commande est partie de Cotonou.',
  instructions: 'Ton enjoué et rapide, comme une vendeuse qui annonce une bonne nouvelle.',
  response_format: 'mp3',
});

writeFileSync('livraison.mp3', Buffer.from(await res.arrayBuffer()));
console.log(res.headers.get('content-type'), res.headers.get('x-credits-used'));

Résultat sur mon essai : audio/mpeg, 145 920 octets, 5,24 crédits, 2,3 secondes.

Choisir le modèle et la voix

ModèleCrédits pour 1 000 caractèresEntrée maxCe qu'il apporte
tts-1324 096Le moins cher des trois, le plus simple
tts-1-hd644 096Une qualité audio supérieure, au double du prix
gpt-4o-mini-tts402 000instructions, plus les voix cedar, marin et verse

Ce sont les tarifs publics ; certains modèles bénéficient en ce moment d'une remise, et la page de chaque modèle affiche le prix facturé du moment. Retrouve les trois sur leurs pages : tts-1, tts-1-hd et gpt-4o-mini-tts.

Mon conseil pour démarrer : tts-1 pour tester, gpt-4o-mini-tts dès que tu veux régler le ton. Je n'ai pas de mesure objective de la qualité d'accent en français, donc je ne vais pas prétendre qu'une voix est meilleure qu'une autre. Fais l'essai avec une de tes vraies phrases, en changeant seulement la voix, et écoute-la sur le téléphone de ton client type, pas sur tes écouteurs.

Les voix cedar, marin et verse ne marchent qu'avec gpt-4o-mini-tts. J'ai envoyé marin à tts-1 : l'API a répondu 502 provider_error, un message générique qui ne dit pas que la voix est en cause. Si tu vois un 502 sur une voix qui n'est pas dans la liste de tts-1, c'est probablement ça.

Régler le ton avec instructions

gpt-4o-mini-tts accepte un champ instructions, en langage naturel :

{
  "model": "gpt-4o-mini-tts",
  "voice": "coral",
  "input": "Bonjour Awa, ta commande est partie de Cotonou.",
  "instructions": "Voix chaleureuse de service client, rythme posé, accent français neutre."
}

Avec cette consigne, le clip de 131 caractères a duré environ 9,8 secondes, contre 8,1 secondes pour tts-1 avec la voix nova. L'écart est réel, mais je ne peux pas dire qu'il vient des instructions : le modèle et la voix étaient différents. Compare à modèle et voix identiques avant d'en tirer une règle.

Si tu envoies instructions à tts-1 ou tts-1-hd, tu reçois une erreur claire :

{
  "error": "bad_request",
  "message": "instructions parameter is only supported with steerable TTS models (gpt-4o-mini-tts)",
  "statusCode": 400
}

Le format pour WhatsApp et le web

Le choix du format change la taille du fichier. Sur le texte « Bonjour Awa » (11 caractères, tts-1), j'ai obtenu :

response_formatcontent-typeOctets
mp3audio/mpeg11 520
opusaudio/opus5 438
aacaudio/aac5 460
flacaudio/flac24 517
wavaudio/wav30 044
pcmaudio/pcm31 800

Les six ont coûté le même prix : 0,352 crédit, puisque la facture suit les caractères, pas le format. Le fichier opus est un conteneur Ogg avec le codec Opus (la commande file l'identifie ainsi), à peu près deux fois plus léger que le MP3 sur cet exemple. C'est le format que les messageries utilisent pour les notes vocales, mais vérifie les exigences de l'API de ton canal (type MIME exact, durée maximale) avant de brancher. Pour construire le bot lui-même, lis le guide du chatbot WhatsApp.

ogg n'est pas une valeur acceptée pour response_format : j'ai reçu un 502 en l'envoyant. Utilise opus.

Ce que ça coûte : la facturation au caractère

Le prix est donné par 1 000 caractères, calculé au prorata, et arrondi une seule fois au millième de crédit supérieur. Mes mesures, sur 131 caractères :

ModèleCalculMesuré (x-credits-used)En F (3 crédits = 1 F)
tts-1131 × 32 / 1 0004,192environ 1,4 F
gpt-4o-mini-tts131 × 40 / 1 0005,24environ 1,7 F
tts-1-hd131 × 64 / 1 0008,384environ 2,8 F

Le calcul tombe juste à chaque fois. Pour un bot, voici un ordre de grandeur calculé à partir de ces tarifs : une réponse de 300 caractères avec tts-1 coûte 9,6 crédits (3,2 F). Mille réponses de cette taille : 9 600 crédits, soit 3 200 F. Ce sont les crédits qui te limitent, pas l'abonnement : il n'y en a pas, et les crédits achetés n'expirent pas.

Un garde-fou utile :

  • Plafonne la longueur côté code avant d'appeler. Un input de 2 001 caractères sur gpt-4o-mini-tts renvoie 400 (« input exceeds 2000 characters ») et ne coûte rien, mais mieux vaut découper toi-même aux phrases.

Les erreurs que j'ai rencontrées

CasRéponse
input absent400 bad_request, « input is required »
instructions sur tts-1400 bad_request
Texte trop long pour gpt-4o-mini-tts400 bad_request
Clé invalide401 invalid_api_key
Voix ou format non pris en charge par tts-1502 provider_error
Trop de requêtes429 rate_limit_exceeded, avec Retry-After
Solde insuffisant402 insufficient_credits

Je n'ai pas provoqué le 402 pour cet article ; il vient de la page des erreurs. Les erreurs 400 et 401 que j'ai provoquées n'ont rien débité.

FAQ

Quelle est la limite de caractères ?

4 096 caractères par requête pour tts-1 et tts-1-hd, 2 000 pour gpt-4o-mini-tts. Au-delà, découpe le texte aux fins de phrases et assemble les fichiers, ou envoie plusieurs messages vocaux.

Est-ce que l'audio arrive en streaming ?

Dans mes tests, non : le fichier complet arrive d'un coup, en 1,8 à 2,3 secondes pour une dizaine de secondes d'audio. Je n'ai pas testé la lecture progressive, donc je ne promets rien là-dessus.

Quelle est la différence entre tts-1 et tts-1-hd ?

Le HD est facturé 64 crédits pour 1 000 caractères, le double de tts-1, pour une qualité audio supérieure d'après la documentation. Écoute les deux sur ta phrase avant de payer le double.

Les voix parlent-elles bien français ?

Elles lisent le français. Je ne mesure pas l'accent, c'est subjectif : teste sur un texte réel, avec les noms de lieux et de personnes de ta clientèle.

Combien de temps dure l'audio pour un texte donné ?

Sur mes essais, 131 caractères ont donné environ 8 à 10 secondes selon la voix et le modèle (durée estimée à partir du flux MP3).

Peut-on cloner une voix ou créer sa propre voix ?

Pas avec ces trois modèles : tu choisis parmi les voix de la liste.

Comment payer sans carte bancaire ?

En mobile money : tu recharges à partir de 1 000 F, 3 crédits valent 1 F, et il n'y a ni abonnement ni crédits gratuits à l'inscription. Ta première recharge ajoute 150 crédits de bonus.

crée ton compte et recharge 1 000 F

Cet article fait partie de la série « Construire un SaaS IA depuis l'Afrique francophone ». Tchavi est une passerelle d'API IA compatible OpenAI : une seule clé donne accès à plus de 100 modèles de texte, d'image, d'audio et de vidéo, et tu la paies en mobile money, sans carte bancaire (pays et opérateurs). Plus de guides sur le blog. Pour suivre les prochains : LinkedIn et X.

Partager

Ton premier appel d'API, payé en mobile money

Sans carte bancaire. Recharge à partir de 1 000 F ; ta première recharge ajoute 150 crédits de bonus, et tes crédits n'expirent pas.