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.
L'API suit la mise à disposition progressive des capacités de Lumavo :
/v1/tts) — disponible dès maintenant./v1/jobs/:id) et gestion des clés — disponibles./v1/render), avatar parlant (/v1/lipsync) et génération de
script (/v1/script) — bientôt, activés au fur et à mesure.https://api.getlumavo.com/v1
Toutes les requêtes sont en HTTPS et échangent du JSON
(Content-Type: application/json).
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.
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
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) |
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).
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" }'
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.
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).
| 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é |
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 |
Ces points de terminaison existent et seront activés progressivement :
POST /v1/script — génère un script à partir d'un sujet.POST /v1/render — produit une vidéo complète.POST /v1/lipsync — crée un avatar parlant.Ils suivent le même principe : la requête renvoie une tâche, dont vous suivez le
statut via /v1/jobs/:id.
| 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é) |
429.X-RateLimit-Limit et X-RateLimit-Remaining
(requêtes restantes dans la fenêtre courante). Un 429 renvoie Retry-After (secondes).GET /v1/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 } }