Une vidéo prend plusieurs minutes. Le lancement répond tout de suite avec une tâche ; vous suivez ensuite la tâche, puis téléchargez la vidéo une fois terminée. Les points d’accès suivent l’API vidéo d’OpenAI.
| Méthode | Chemin | Rôle |
|---|---|---|
POST | /v1/videos | Lancer une vidéo |
GET | / | Suivre une vidéo |
GET | / | Télécharger la vidéo |
GET | /v1/videos | Lister vos vidéos |
Une tâche passe par les statuts queued (en file), in_progress (en cours), puis completed (terminée) ou failed (en échec). Elle appartient au workspace de la clé qui l’a lancée : toute clé de ce workspace peut la suivre et la télécharger.
Exemple completLien vers la section Exemple complet
# 1. Lancer la vidéo
curl https://api.realmoon.ai/v1/videos \
-H "Authorization: Bearer $MOONAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "alibaba/wan-2.6", "prompt": "Une vague au coucher du soleil", "seconds": "5"}'
# => {"id": "video_3c9e…", "status": "queued", …}
# 2. Suivre la tâche (toutes les 10 secondes environ)
curl https://api.realmoon.ai/v1/videos/video_3c9e... \
-H "Authorization: Bearer $MOONAI_API_KEY"
# 3. Télécharger la vidéo une fois "completed"
curl https://api.realmoon.ai/v1/videos/video_3c9e.../content \
-H "Authorization: Bearer $MOONAI_API_KEY" -o vague.mp4import os
import time
from openai import OpenAI
client = OpenAI(base_url="https://api.realmoon.ai/v1", api_key=os.environ["MOONAI_API_KEY"])
job = client.videos.create(
model="alibaba/wan-2.6",
prompt="Une vague au coucher du soleil",
seconds="5",
extra_body={"resolution": "720p", "aspect_ratio": "16:9"},
)
while job.status in ("queued", "in_progress"):
time.sleep(10)
job = client.videos.retrieve(job.id)
if job.status == "completed":
client.videos.download_content(job.id).write_to_file("vague.mp4")
else:
print("Échec :", job.error)import fs from 'node:fs';
import OpenAI from 'openai';
const client = new OpenAI({ baseURL: 'https://api.realmoon.ai/v1', apiKey: process.env.MOONAI_API_KEY });
let job = await client.videos.create({
model: 'alibaba/wan-2.6',
prompt: 'Une vague au coucher du soleil',
seconds: '5',
resolution: '720p', // paramètre propre à Moon AI, envoyé tel quel
});
while (job.status === 'queued' || job.status === 'in_progress') {
await new Promise((r) => setTimeout(r, 10_000));
job = await client.videos.retrieve(job.id);
}
if (job.status === 'completed') {
const content = await client.videos.downloadContent(job.id);
fs.writeFileSync('vague.mp4', Buffer.from(await content.arrayBuffer()));
} else {
console.error('Échec :', job.error);
}Lancer une vidéoLien vers la section Lancer une vidéo
POST https://api.realmoon.ai/v1/videos- Authentification : clé
sk-moon-…avec la portéeinference(voir Authentification). - Corps : JSON, ou
multipart/(avec l’en-têteform-data Content-Length) pour envoyer les images de départ et de fin comme fichiers. 60 Mo au plus. - Réponse : l’objet vidéo de la tâche, au statut
queued, avec l’en-têteX-Moon-Request-Idqui sert à lire le coût sur/.v1/ generation
ParamètresLien vers la section Paramètres
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
model | chaîne | oui | Un modèle de type video de GET /. |
prompt | chaîne | oui | Description de la vidéo, 4 000 caractères au plus. |
seconds (ou duration) | entier ou chaîne | non | Durée en secondes, parmi les durations du modèle. Par défaut : la première durée d’au moins 5 secondes, sinon la plus longue. |
resolution | chaîne | non | Parmi les resolutions du modèle (480p, 720p, 1080p, 4K…). Par défaut 720p quand le modèle le propose, sinon sa première résolution. |
size | chaîne | non | LARGEURxHAUTEUR, par exemple 1280x720 : la résolution et le format les plus proches en sont déduits, si vous ne les donnez pas. |
aspect_ratio | chaîne | non | Parmi les aspect_ratios du modèle (16:9, 9:16…). Par défaut, le premier de la liste. |
generate_audio | booléen | non | Avec ou sans son, pour les modèles qui font du son (audio: true). Par défaut, avec son si le modèle en fait. true sur un modèle muet : 400 . |
seed | entier | non | Graine, de 0 à 2 147 483 647. |
input_reference, image ou first_frame | image | non | Image de départ : adresse https://, adresse data: en base64, base64 seul, ou fichier en multipart. Pour les modèles où first_frame vaut true. |
last_frame | image | non | Image de fin, avec une image de départ, pour les modèles où last_frame vaut true. |
user | chaîne | non | Accepté, sans effet. |
Tout autre paramètre est refusé avec 400 . Une image fait 20 Mo au plus (PNG, JPEG, WebP ou GIF). Une image à une adresse https:// est lue par le fournisseur du modèle, pas par Moon AI.
ExempleLien vers la section Exemple
curl https://api.realmoon.ai/v1/videos \
-H "Authorization: Bearer $MOONAI_API_KEY" \
-F model=kwaivgi/kling-v3.0-std \
-F prompt="La photo s’anime : les nuages défilent" \
-F seconds=5 \
-F generate_audio=false \
-F first_frame=@paysage.pngjob = client.videos.create(
model="kwaivgi/kling-v3.0-std",
prompt="La photo s’anime : les nuages défilent",
seconds="5",
input_reference=open("paysage.png", "rb"),
extra_body={"generate_audio": False},
)
print(job.id, job.status)const job = await client.videos.create({
model: 'kwaivgi/kling-v3.0-std',
prompt: 'La photo s’anime : les nuages défilent',
seconds: '5',
input_reference: fs.createReadStream('paysage.png'),
generate_audio: false, // paramètre propre à Moon AI, envoyé tel quel
});
console.log(job.id, job.status);L’objet vidéoLien vers la section L’objet vidéo
POST /, GET / et GET / renvoient des objets vidéo.
{
"id": "video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b",
"object": "video",
"model": "alibaba/wan-2.6",
"status": "completed",
"progress": 100,
"created_at": 1793577600,
"completed_at": 1793577780,
"seconds": "5",
"size": "1280x720",
"resolution": "720p",
"aspect_ratio": "16:9",
"generate_audio": true,
"remixed_from_video_id": null,
"error": null,
"content_url": "/v1/videos/video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b/content",
"expires_at": 1793581380,
"usage": { "seconds": 5, "credits": 2800 }
}| Champ | Type | Description |
|---|---|---|
id | chaîne | Identifiant de la tâche : video_ suivi de 32 caractères. |
object | chaîne | Toujours video. |
model | chaîne | Le modèle appelé. |
status | chaîne | queued, in_progress, completed ou failed. |
progress | entier | Avancement de 0 à 100, quand le fournisseur le donne ; 100 une fois terminée. |
created_at, completed_at | entier | Dates en secondes Unix. completed_at vaut null avant la fin. |
seconds | chaîne | Durée demandée au modèle. |
size | chaîne | Dimensions qui correspondent à la résolution et au format, par exemple 1280x720. |
resolution, aspect_ratio, generate_audio | chaîne, chaîne, booléen | Ce qui a été demandé au modèle. |
remixed_from_video_id | null | Toujours null, gardé pour la compatibilité. |
content_url | chaîne | Une fois terminée : l’adresse de téléchargement. |
expires_at | entier | Une fois terminée : la date jusqu’à laquelle la vidéo reste disponible (environ une heure après la fin). |
error | objet ou null | En cas d’échec : {"code", . |
usage | objet | Une fois la tâche réglée : seconds (durée) et credits (crédits facturés). |
Codes de error.code d’une tâche en échec, toujours sans frais :
code | Cause |
|---|---|
generation_failed | Le modèle n’a pas pu faire la vidéo. |
content_policy_violation | Le système de sécurité du modèle a refusé la demande. |
timeout | La vidéo n’était pas finie au bout de 6 heures et a été abandonnée. |
not_found | Le fournisseur ne connaît plus la tâche. |
Suivre une vidéoLien vers la section Suivre une vidéo
GET https://api.realmoon.ai/v1/videos/{id}Renvoie l’objet vidéo à jour.
- Authentification : clé
sk-moon-…du workspace qui a lancé la vidéo, avec la portéeinference. - Paramètre de chemin :
id, l’identifiantvideo_…de la tâche. - Interrogez la tâche toutes les 10 secondes environ : Moon AI ne demande pas l’état au fournisseur plus d’une fois toutes les 5 secondes.
- La lecture n’est pas facturée.
curl https://api.realmoon.ai/v1/videos/video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b \
-H "Authorization: Bearer $MOONAI_API_KEY"job = client.videos.retrieve("video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b")
print(job.status, job.progress)const job = await client.videos.retrieve('video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b');
console.log(job.status, job.progress);Télécharger la vidéoLien vers la section Télécharger la vidéo
GET https://api.realmoon.ai/v1/videos/{id}/contentEnvoie le fichier vidéo, en général video/mp4, avec l’en-tête Content-Disposition qui propose le nom <id>.mp4.
- Authentification : clé
sk-moon-…du workspace qui a lancé la vidéo, avec la portéeinference. - Avant la fin :
409.video_not_ready - Moon AI ne garde pas la vidéo : elle est lue chez le fournisseur au moment du téléchargement. Téléchargez-la dans l’heure qui suit la fin et gardez votre copie. Quand le fournisseur ne l’a plus :
410.video_expired - Au plus 4 téléchargements à la fois par workspace (au-delà :
429).too_many_concurrent - Le téléchargement n’est pas facturé.
curl https://api.realmoon.ai/v1/videos/video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b/content \
-H "Authorization: Bearer $MOONAI_API_KEY" -o vague.mp4client.videos.download_content("video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b").write_to_file("vague.mp4")const content = await client.videos.downloadContent('video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b');
fs.writeFileSync('vague.mp4', Buffer.from(await content.arrayBuffer()));Lister vos vidéosLien vers la section Lister vos vidéos
GET https://api.realmoon.ai/v1/videosListe les vidéos du workspace, les plus récentes d’abord.
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
limit | entier | non | Nombre de vidéos par page, ramené entre 1 et 100. 20 par défaut. |
after | chaîne | non | Identifiant d’une vidéo du workspace : la page commence après elle. |
curl "https://api.realmoon.ai/v1/videos?limit=10" \
-H "Authorization: Bearer $MOONAI_API_KEY"# Le SDK charge les pages suivantes au fil de l'itération.
for video in client.videos.list(limit=10):
print(video.id, video.status)// Le SDK charge les pages suivantes au fil de l'itération.
for await (const video of client.videos.list({ limit: 10 })) {
console.log(video.id, video.status);
}{
"object": "list",
"data": [{ "id": "video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b", "object": "video", "status": "completed" }],
"first_id": "video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b",
"last_id": "video_3c9e2f6a8b1d4e7f9a0b2c4d6e8f1a3b",
"has_more": false
}| Champ | Type | Description |
|---|---|---|
object | chaîne | Toujours list. |
data | tableau | Les objets vidéo de la page (raccourcis dans l’exemple). |
first_id, last_id | chaîne ou null | Premier et dernier identifiant de la page. |
has_more | booléen | true s’il reste des vidéos : passez last_id dans after pour la page suivante. |
ModèlesLien vers la section Modèles
Liste au 5 novembre 2026 ; la liste à jour, avec les prix par seconde, vient de GET /.
| Modèle | Durées (s) | Résolutions | Formats | Son | Image de départ / de fin |
|---|---|---|---|---|---|
alibaba/ | 5, 10 | 480p, 720p, 1080p | 16:9, 9:16 | oui | oui / non |
alibaba/ | 2 à 10 | 720p, 1080p | 16:9, 9:16, 1:1, 4:3, 3:4 | oui | oui / oui |
alibaba/ | 2 à 15 | 480p, 720p, 1080p | 16:9, 9:16, 1:1, 4:3, 3:4 | oui | oui / oui |
kwaivgi/, kling-v3.0-pro | 3 à 15 | 720p, 1080p | 16:9, 9:16, 1:1 | oui, ou sans (moins cher) | oui / oui |
google/ | 4, 6, 8 | 720p, 1080p | 16:9, 9:16 | oui, ou sans (moins cher) | oui / oui |
google/, google/ | 4, 6, 8 | 720p, 1080p, 4K | 16:9, 9:16 | oui, ou sans (moins cher) | oui / oui |
minimax/ | 6, 10 | 1080p | 16:9 | non | oui / non |
x-ai/ | 1 à 15 | 480p, 720p | 16:9, 9:16, 1:1, 4:3, 3:4, 3:2, 2:3 | non | oui / non |
runway/ | 2 à 10 | 720p | 16:9, 9:16 | non | oui / non |
CoûtsLien vers la section Coûts
- Au lancement, la tâche retient le prix de la durée demandée, avec une petite marge, plus les images de départ et de fin pour les modèles qui les facturent.
- Une vidéo terminée est facturée au coût réel annoncé par le fournisseur (à défaut, au prix de la liste), et le reste de la retenue est rendu.
- Une vidéo en échec, refusée, abandonnée après 6 heures, ou dont le lancement a été coupé par notre délai, ne coûte rien.
- La retenue d’une tâche en cours compte dans le solde et les plafonds de dépense jusqu’à sa fin.
Voir Coûts et porte-monnaie.
LimitesLien vers la section Limites
- Au plus 20 vidéos en cours à la fois par workspace (au-delà :
429,too_many_concurrent Retry-After:).30 - Le lancement répond en une minute environ au plus.
- Moon AI garde l’état de la tâche (statut, durée, résolution, format, coût), pas votre description ni la vidéo.
ErreursLien vers la section Erreurs
| HTTP | code | Point d’accès | Signification |
|---|---|---|---|
| 400 | missing_required_parameter | lancement | model ou prompt absent. |
| 400 | unknown_parameter | lancement | Paramètre inconnu. |
| 400 | unsupported_value | lancement | Durée, résolution, format, size ou generate_audio hors de ce que le modèle accepte. |
| 400 | unsupported_parameter | lancement | Image de départ ou de fin sur un modèle qui ne l’accepte pas, ou paramètre refusé par le modèle (avec une indication). |
| 400 | string_above_max_length | lancement | Description de plus de 4 000 caractères. |
| 400 | invalid_image | lancement | Image illisible, d’un autre type ou trop grande. |
| 400 | content_policy_violation | lancement | Le système de sécurité du modèle a refusé la demande. |
| 400 | null | lancement, liste | seed ou generate_audio invalide, image de fin sans image de départ, base64 invalide, after inconnu. |
| 403 | org_policy | lancement | Les règles de votre organisation refusent ce modèle. |
| 404 | model_not_found | lancement | Modèle inconnu ou qui ne sert pas ce point d’accès. |
| 404 | video_not_found | suivi, téléchargement | Aucune vidéo de ce workspace ne porte cet identifiant. |
| 409 | video_not_ready | téléchargement | La vidéo n’est pas encore terminée. |
| 410 | video_expired | téléchargement | La vidéo n’est plus disponible chez le fournisseur. |
| 411 | length_required | lancement | Envoi multipart sans en-tête Content-Length. |
| 413 | request_too_large, file_too_large | lancement | Corps ou image trop volumineux. |
| 429 | too_many_concurrent | lancement, téléchargement | Trop de vidéos en cours, ou de téléchargements, dans le workspace. |
| 429 | upstream_rate_limited | lancement | Le modèle est surchargé : réessayez après Retry-After (10 secondes). |
| 502 | upstream_error | lancement, téléchargement | Le modèle a échoué, ou la vidéo n’a pas pu être lue : réessayez dans un instant. |
| 503 | job_not_recorded | lancement | La vidéo a été lancée mais n’a pas pu être enregistrée : contactez le support. |
| 504 | upstream_timeout | lancement | Le modèle n’a pas répondu à temps au lancement. Rien n’est facturé. |
Les erreurs de clé, de solde et de plafonds sont dans Erreurs.