Aller au contenu principal
Leçon 13 sur 14 · Text-to-Speech API

Erreurs HTTP et sécurité de la clé API

Leçon 13 sur 14 Mis à jour le 3 novembre 2026 Développeur
Sur cette page
  1. Gérer les erreurs et protéger vos credentials
  2. Codes d’erreur HTTP
  3. Ne jamais exposer la clé API côté client
  4. Modération fail-open
  5. Points clés à retenir

Leçon corrigée le 3 novembre 2026 d’après la page Text to Speech et la page Rate limits de xAI : texte limité à 60 000 caractères et non 15 000, erreur 404 (voix inconnue) ajoutée, limites de débit par palier ; les « tags mal formés » ne figurent pas parmi les causes d’erreur 400 documentées. Sources : Text to Speech · Rate limits.

Gérer les erreurs et protéger vos credentials

En production, votre application doit gérer élégamment les erreurs de l’API TTS et surtout ne jamais exposer votre clé API côté client. Cette leçon couvre les codes d’erreur, les stratégies de retry, et l’architecture de proxy backend.

Codes d’erreur HTTP

L’API TTS retourne les codes d’erreur standard HTTP. Voici comment réagir à chacun.

400 - Bad Request

Le serveur n’a pas pu traiter votre requête. Causes fréquentes :

  • Texte vide ou dépassant 60 000 caractères
  • Codec invalide (faute de frappe dans le nom)
  • Sample rate non supporté
if response.status_code == 400:
    error = response.json()
    print(f"Requête invalide: {error}")
    # Corriger les paramètres et réessayer

Ne réessayez pas automatiquement une erreur 400 : le problème vient de votre requête, pas du serveur. Corrigez d’abord les paramètres.

401 - Unauthorized

La clé API est invalide, expirée ou absente :

if response.status_code == 401:
    raise AuthenticationError("Clé API invalide ou expirée")

Vérifiez que :

  • L’en-tête Authorization est présent
  • Le format est Bearer xai-... (avec l’espace après Bearer)
  • La clé n’a pas été révoquée dans la console xAI

404 - Not Found

L’identifiant de voix est inconnu : vérifiez-le avec GET /v1/tts/voices pour une voix intégrée, ou GET /v1/custom-voices pour une voix personnalisée. Comme une 400, une 404 ne se règle pas en réessayant.

429 - Too Many Requests

Vous avez dépassé une limite de débit : au palier d’entrée, 50 requêtes par seconde et 100 sessions simultanées pour le TTS d’après la page Rate limits, et 50 sessions WebSocket simultanées par équipe d’après la page Text to Speech. xAI recommande de réessayer avec un délai exponentiel :

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 5))
    await asyncio.sleep(retry_after)
    # Reessayer

Implémentez un backoff exponentiel pour les erreurs 429 :

async def request_with_backoff(url, payload, headers, max_retries=5):
    for attempt in range(max_retries):
        response = requests.post(url, json=payload, headers=headers)

        if response.status_code == 200:
            return response

        if response.status_code == 429:
            wait = min(2 ** attempt + random.random(), 60)
            print(f"Rate limited. Attente de {wait:.1f}s")
            await asyncio.sleep(wait)
            continue

        if response.status_code >= 500:
            wait = min(2 ** attempt + random.random(), 30)
            await asyncio.sleep(wait)
            continue

        # Erreur client (400, 401) : ne pas réessayer
        response.raise_for_status()

    raise Exception("Echec apres 5 tentatives")

500 / 503 - Server Error

Le serveur rencontre un problème temporaire. Réessayez avec backoff :

if response.status_code in (500, 503):
    # Réessayer avec backoff exponentiel
    pass

Les erreurs 503 sont souvent liées à une surcharge temporaire. Elles se résolvent généralement en quelques secondes.

Ne jamais exposer la clé API côté client

C’est la règle de sécurité la plus importante. Si votre clé API est visible dans le code JavaScript du navigateur, n’importe qui peut :

  • Utiliser votre quota gratuitement
  • Accumuler des frais sur votre compte
  • Accéder à tous les endpoints de l’API xAI avec votre clé

Architecture de proxy backend

La solution est de proxier les appels TTS via votre propre backend :

Navigateur -> Votre backend -> API xAI
  (pas de cle)   (cle API)     (TTS)

Exemple Express.js

const express = require("express");
const app = express();

app.post("/api/tts", async (req, res) => {
  const { text, voice_id, language } = req.body;

  // Validation cote serveur
  if (!text || text.length > 15000) {
    return res.status(400).json({ error: "Texte invalide" });
  }

  const response = await fetch("https://api.x.ai/v1/tts", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.XAI_API_KEY}`,
      "Content-Type": "application/json"
    },
    body: JSON.stringify({ text, voice_id, language })
  });

  if (!response.ok) {
    return res.status(response.status).json({
      error: "Erreur TTS"
    });
  }

  // Transmettre l'audio au client
  res.set("Content-Type", response.headers.get("Content-Type"));
  const buffer = await response.arrayBuffer();
  res.send(Buffer.from(buffer));
});

Exemple FastAPI (Python)

from fastapi import FastAPI, HTTPException
from fastapi.responses import Response
import httpx

app = FastAPI()

@app.post("/api/tts")
async def proxy_tts(text: str, voice_id: str = "eve", language: str = "fr"):
    if len(text) > 15000:
        raise HTTPException(400, "Texte trop long")

    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.x.ai/v1/tts",
            headers={"Authorization": f"Bearer {os.environ['XAI_API_KEY']}"},
            json={"text": text, "voice_id": voice_id, "language": language}
        )

    if response.status_code != 200:
        raise HTTPException(response.status_code, "Erreur TTS")

    return Response(
        content=response.content,
        media_type=response.headers["content-type"]
    )

Proxy WebSocket

Pour le WebSocket TTS, votre backend doit relayer les messages entre le client et l’API xAI :

const WebSocket = require("ws");

wss.on("connection", (clientWs) => {
  const xaiWs = new WebSocket(
    "wss://api.x.ai/v1/tts?language=fr&voice=eve",
    { headers: { Authorization: `Bearer ${process.env.XAI_API_KEY}` } }
  );

  // Relayer client -> xAI
  clientWs.on("message", (msg) => xaiWs.send(msg));

  // Relayer xAI -> client
  xaiWs.on("message", (msg) => clientWs.send(msg));

  // Gerer les fermetures
  clientWs.on("close", () => xaiWs.close());
  xaiWs.on("close", () => clientWs.close());
});

Modération fail-open

L’API TTS exécute une modération du contenu de manière asynchrone. Cela signifie que la requête n’est pas bloquée par la modération : l’audio est généré et retourne même si la modération n’a pas encore terminé son analyse.

En cas de contenu détecté comme inapproprié, le signalement arrive après coup. Votre application doit donc implémenter sa propre modération en amont si nécessaire.

Points clés à retenir

  • 400 = erreur de paramètres (ne pas réessayer, corriger la requête)
  • 401 = clé API invalide (vérifier l’en-tête Authorization)
  • 429 = rate limited (backoff exponentiel)
  • 500/503 = erreur serveur temporaire (réessayer avec backoff)
  • Ne jamais exposer la clé API dans le code client
  • Proxier tous les appels TTS via votre backend
  • La modération est fail-open : implémentez votre propre filtrage si nécessaire