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-hdetgpt-4o-mini-ttsle 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çaisefr_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 labaseURLet la clé. - Trois modèles de synthèse vocale :
tts-1(32 crédits pour 1 000 caractères),tts-1-hd(64) etgpt-4o-mini-tts(40), le seul qui accepte desinstructionsde 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ètre | Rôle |
|---|---|
model | tts-1, tts-1-hd ou gpt-4o-mini-tts |
input | Le texte à dire : 4 096 caractères au maximum, 2 000 pour gpt-4o-mini-tts |
voice | alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer, et cedar, marin, verse en plus pour gpt-4o-mini-tts |
instructions | gpt-4o-mini-tts seulement : comment parler |
response_format | mp3 (par défaut), opus, aac, flac, wav, pcm |
speed | De 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èle | Crédits pour 1 000 caractères | Entrée max | Ce qu'il apporte |
|---|---|---|---|
tts-1 | 32 | 4 096 | Le moins cher des trois, le plus simple |
tts-1-hd | 64 | 4 096 | Une qualité audio supérieure, au double du prix |
gpt-4o-mini-tts | 40 | 2 000 | instructions, 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_format | content-type | Octets |
|---|---|---|
| mp3 | audio/mpeg | 11 520 |
| opus | audio/opus | 5 438 |
| aac | audio/aac | 5 460 |
| flac | audio/flac | 24 517 |
| wav | audio/wav | 30 044 |
| pcm | audio/pcm | 31 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èle | Calcul | Mesuré (x-credits-used) | En F (3 crédits = 1 F) |
|---|---|---|---|
tts-1 | 131 × 32 / 1 000 | 4,192 | environ 1,4 F |
gpt-4o-mini-tts | 131 × 40 / 1 000 | 5,24 | environ 1,7 F |
tts-1-hd | 131 × 64 / 1 000 | 8,384 | environ 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
inputde 2 001 caractères surgpt-4o-mini-ttsrenvoie400(« 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
| Cas | Réponse |
|---|---|
input absent | 400 bad_request, « input is required » |
instructions sur tts-1 | 400 bad_request |
Texte trop long pour gpt-4o-mini-tts | 400 bad_request |
| Clé invalide | 401 invalid_api_key |
Voix ou format non pris en charge par tts-1 | 502 provider_error |
| Trop de requêtes | 429 rate_limit_exceeded, avec Retry-After |
| Solde insuffisant | 402 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.