API pour développeurs

Lumavo expose une API REST pour intégrer la génération directement dans vos applications, vos automatisations ou vos outils internes — sans passer par l'interface.

Disponibilité

L'API suit la mise à disposition progressive des capacités de Lumavo :

Base

https://api.getlumavo.com/v1

Toutes les requêtes sont en HTTPS et échangent du JSON (Content-Type: application/json).

Authentification

Chaque requête doit porter votre clé d'API dans l'en-tête X-LUMA-API-KEY :

X-LUMA-API-KEY: votre_clé

Créez et gérez vos clés depuis votre compte, section Clés API. Une clé porte des permissions (voix, vidéo, avatar, script) : elle n'a accès qu'aux capacités que vous lui accordez. Gardez vos clés secrètes ; en cas de fuite, révoquez-les et recréez-en une.

Démarrage rapide (client)

Clients sans dépendance, prêts à copier. Ils créent une voix et attendent le résultat.

Node.js (18+)

const KEY = process.env.LUMAVO_API_KEY, BASE = 'https://api.getlumavo.com';
const call = (p, o = {}) => fetch(BASE + p, { ...o,
  headers: { 'X-LUMA-API-KEY': KEY, 'Content-Type': 'application/json', ...(o.headers || {}) },
}).then((r) => r.ok ? r.json() : Promise.reject(r.status));

const job = await call('/v1/tts', { method: 'POST', body: JSON.stringify({ text: 'Bonjour !', voice: 'narrator' }) });
let res;
do { await new Promise((r) => setTimeout(r, 1500)); res = await call(`/v1/jobs/${job.id}`); }
while (res.status !== 'done' && res.status !== 'failed');
console.log(res.resultUrl);   // → WAV téléchargeable

Python (3.8+)

import os, time, json, urllib.request
KEY, BASE = os.environ["LUMAVO_API_KEY"], "https://api.getlumavo.com"
def call(path, method="GET", body=None):
    req = urllib.request.Request(BASE + path, data=json.dumps(body).encode() if body else None,
        method=method, headers={"X-LUMA-API-KEY": KEY, "Content-Type": "application/json"})
    return json.load(urllib.request.urlopen(req))

job = call("/v1/tts", "POST", {"text": "Bonjour !", "voice": "narrator"})
res = job
while res["status"] not in ("done", "failed"):
    time.sleep(1.5); res = call(f"/v1/jobs/{job['id']}")
print(res["resultUrl"])   # → WAV téléchargeable

Créer une synthèse vocale

curl -X POST https://api.getlumavo.com/v1/tts \
  -H "X-LUMA-API-KEY: votre_clé" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Bonjour, ceci est ma voix générée par Lumavo.",
    "voice": "calm",
    "speed": 1.0
  }'

La réponse (202 Accepted) contient l'identifiant de la tâche :

{ "id": "b1f2…", "status": "pending" }
Champ Type Obligatoire Détail
text string oui Le texte à lire (jusqu'à 8000 car.)
voice string non Voix/style — voir GET /v1/voices
emotion string non Ton (ex. calme, dynamique)
speed number non Vitesse, entre 0.5 et 2 (défaut 1)

Voix disponibles

curl https://api.getlumavo.com/v1/voices -H "X-LUMA-API-KEY: votre_clé"

Renvoie la liste des voix pour le champ voice : calm (calme), narrator (narrateur), cinematic (cinématique), ad (publicité), tiktok (réseaux sociaux).

Éviter les doublons (idempotence)

Ajoutez un en-tête Idempotency-Key (un identifiant unique que vous générez) à POST /v1/tts · /render · /lipsync. Si vous rejouez la même requête (timeout réseau, retry), Lumavo renvoie la tâche déjà créée au lieu d'en créer — et ne débite pas deux fois.

curl -X POST https://api.getlumavo.com/v1/tts \
  -H "X-LUMA-API-KEY: votre_clé" \
  -H "Idempotency-Key: 3f8c1e2a-…" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Bonjour", "voice": "calm" }'

Récupérer le résultat

La génération est asynchrone : interrogez le statut de la tâche jusqu'à ce qu'elle soit terminée, puis récupérez l'URL du fichier.

curl https://api.getlumavo.com/v1/jobs/b1f2… \
  -H "X-LUMA-API-KEY: votre_clé"
{ "id": "b1f2…", "type": "tts_only", "status": "done", "progress": 100, "resultUrl": "https://…/audio.wav" }

Chaque tâche a une forme stable : { id, type, status, progress, resultUrl, error, duration, createdAt }. Interrogez ce point de terminaison toutes les 1–2 secondes jusqu'à status: "done" (ou "failed"). L'URL renvoyée est directement téléchargeable.

Lister ses tâches

curl "https://api.getlumavo.com/v1/jobs?limit=20" \
  -H "X-LUMA-API-KEY: votre_clé"

Renvoie vos tâches les plus récentes, de la plus récente à la plus ancienne (paramètre limit optionnel, max 100).

Gérer ses clés par l'API

Méthode & route Rôle
POST /v1/keys Créer une clé
GET /v1/keys Lister ses clés
POST /v1/keys/:id/revoke Révoquer une clé

Webhooks (recommandé)

Au lieu de sonder /v1/jobs/:id, enregistrez une URL de callback : Lumavo vous notifie dès qu'une tâche se termine (job.completed) ou échoue (job.failed).

curl -X POST https://api.getlumavo.com/v1/webhooks \
  -H "X-LUMA-API-KEY: votre_clé" -H "Content-Type: application/json" \
  -d '{"url":"https://votre-app.com/lumavo/callback"}'
{ "id": "…", "url": "https://votre-app.com/lumavo/callback", "secret": "whsec_…", "active": true }

Conservez le secret (affiché une seule fois). Chaque livraison est signée : l'en-tête X-LUMA-Signature contient HMAC-SHA256(corps, secret) — recalculez-le côté serveur pour vérifier l'authenticité. Corps reçu :

{ "event": "job.completed", "data": { "jobId": "…", "status": "done", "resultUrl": "https://…" }, "timestamp": 1720000000000 }

Vérifier la signature (indispensable) — recalculez le HMAC sur le corps brut (pas le JSON re-sérialisé) et comparez à temps constant :

// Express
import { createHmac, timingSafeEqual } from 'node:crypto';
app.post('/callback', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.header('X-LUMA-Signature') || '';
  const expected = createHmac('sha256', SECRET).update(req.body).digest('hex');
  const ok = sig.length === expected.length && timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
  if (!ok) return res.sendStatus(401);
  const { event, data } = JSON.parse(req.body);   // data = { jobId, status, resultUrl }
  res.sendStatus(200);
});
# Flask
import hmac, hashlib
@app.post("/callback")
def callback():
    sig = request.headers.get("X-LUMA-Signature", "")
    expected = hmac.new(SECRET.encode(), request.data, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, sig):
        abort(401)
    event = request.get_json()   # { event, data: { jobId, status, resultUrl }, timestamp }
    return "", 200
Méthode & route Rôle
POST /v1/webhooks Enregistrer une URL
GET /v1/webhooks Lister ses webhooks
POST /v1/webhooks/:id/test Envoyer un événement de test
DELETE /v1/webhooks/:id Supprimer

Bientôt

Ces points de terminaison existent et seront activés progressivement :

Ils suivent le même principe : la requête renvoie une tâche, dont vous suivez le statut via /v1/jobs/:id.

Codes de réponse

Code Signification
202 Tâche acceptée et mise en file
200 Requête réussie (statut, listes)
401 Clé d'API absente ou invalide
403 La clé n'a pas la permission requise
402 Crédits insuffisants
429 Trop de requêtes — ralentissez (limite de débit par clé)

Limites & bon usage

curl https://api.getlumavo.com/v1/usage -H "X-LUMA-API-KEY: votre_clé"
{ "rateLimit": { "limit": 60, "remaining": 58, "windowSeconds": 60, "resetSeconds": 42 },
  "dailyQuota": { "limit": 2000, "used": 12, "remaining": 1988 } }