Intégration d'une API de génération vidéo : tâches, polling et contenu
Intégrez la génération vidéo avec création, polling et contenu, en tenant compte des éditions, extensions, personnages, webhooks, limites de durée et livraison autorisée.
L'intégration d'une API de génération vidéo est un workflow média asynchrone : vous créez une tâche, attendez qu'elle se termine ou échoue, puis téléchargez les octets via une URL de contenu qui peut expirer et doit être autorisée. Dans les passerelles compatibles OpenAI qui suivent la surface Videos, les routes centrales sont POST /v1/videos, GET /v1/videos/{task_id} et GET /v1/videos/{task_id}/content. La documentation officielle OpenAI met désormais en avant les éditions, extensions, personnages, webhooks et le Batch avec create/retrieve, tandis que l'ancien endpoint remix est déprécié pour les nouveaux développements. Cet article montre comment intégrer ces flux en toute sécurité à partir du comportement visible du dépôt et des sources officielles, sans inventer de latence ni de prix.
Contexte de date (2026-07-15) : OpenAI a annoncé la dépréciation de l'API Videos et des alias Sora 2, avec arrêt le 2026-09-24 (dépréciations OpenAI). Ne démarrez pas un produit durable reposant uniquement sur Sora 2. Si vous exploitez encore du trafic Sora via une passerelle, traitez cette période comme une fenêtre de migration : maintenez create/poll/content, évitez de construire une nouvelle UX autour de flux remix uniquement et préparez dès maintenant des alias vers deux fournisseurs.
Réponse directe : traitez la vidéo comme une tâche, pas comme une chat completion
# 1) create
curl -sS https://YOUR_GATEWAY/v1/videos \
-H "Authorization: Bearer $GATEWAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_VIDEO_MODEL_ALIAS",
"prompt": "Slow aerial push-in over a misty cedar forest at dawn",
"seconds": "4",
"size": "1280x720"
}'
# 2) poll (prefer webhooks when the upstream supports them; see below)
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID \
-H "Authorization: Bearer $GATEWAY_KEY"
# 3) download when status=completed
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID/content \
-H "Authorization: Bearer $GATEWAY_KEY" \
-o forest.mp4
Les statuts à gérer explicitement, tels qu'ils sont modélisés dans le DTO vidéo de ce code, comprennent queued, in_progress, completed et failed. L'objet de tâche contient généralement id, model, status, progress, created_at, completed_at, expires_at, seconds, size, un champ error facultatif et des champs de lignée comme remixed_from_video_id lorsqu'une tâche dérivée existe.
Revérifiez toujours les matrices de paramètres dans la documentation actuelle du fournisseur : guide OpenAI de génération vidéo et référence de l'API Videos. Les autres fournisseurs, comme Google Veo / les surfaces vidéo Gemini, Runway, Luma, Kling et ByteDance/Volcengine, publient des références propriétaires qui peuvent utiliser des formes de tâche différentes. Selon les adaptateurs de canaux, une passerelle peut aussi exposer des routes spécifiques comme /v1/video/generations ou /kling/v1/videos/*. Dans le code applicatif, préférez l'API de tâches au format OpenAI normalisée lorsque la passerelle la prend en charge.
Surface officielle OpenAI et routes enregistrées aujourd'hui par cette passerelle
| Capacité (documentation OpenAI, 2026-07-15) | Route / événement officiel | Réalité de la passerelle dans ce dépôt |
|---|---|---|
| Créer une vidéo | POST /v1/videos | Pris en charge comme chemin principal de soumission pour les adaptateurs au format OpenAI |
| Récupérer / poller | GET /v1/videos/{id} | Pris en charge |
| Télécharger le contenu | GET /v1/videos/{id}/content | Pris en charge avec vérifications de propriété |
| Éditer une vidéo existante | POST /v1/videos/edits (préféré ; remix déprécié) | Pas normalisé aujourd'hui comme ensemble de routes de première classe |
| Étendre une vidéo | POST /v1/videos/extensions | Pas normalisé aujourd'hui |
| Personnages | POST /v1/videos/characters + characters lors de la création | Pas normalisé aujourd'hui |
| Ancien remix | POST /v1/videos/{id}/remix (déprécié pour les nouvelles intégrations) | Toujours détecté et enregistré sur les routes de type remix pour les adaptateurs Sora existants |
| Webhooks | video.completed, video.failed | Fonction upstream OpenAI ; les clients de passerelle doivent toujours prévoir un fallback par polling |
| Batch | Lignes Batch API vers POST /v1/videos | Fonction upstream ; ne remplace pas les tables de tâches du produit |
Mentionnez explicitement cet écart dans les revues d'architecture : un code produit qui connaît seulement create/poll/content survivra au routage multi-fournisseurs ; un code qui dépend de remix comme bouton « éditer » se heurtera à la fois à la dépréciation OpenAI et à la normalisation incomplète des éditions, extensions et personnages dans la passerelle.
Pourquoi la vidéo est plus difficile à intégrer que l'image
| Sujet | Images, en général | Vidéos, en général |
|---|---|---|
| Latence | secondes | dizaines de secondes à plusieurs minutes |
| Forme API | souvent une réponse unique | créer + attendre + contenu |
| Taille de charge utile | Ko à Mo | facilement plusieurs Mo |
| Modes d'échec | modération / mauvaise taille | longs timeouts, progression partielle, contenu expiré |
| Risque de coût | n et résolution | durée, résolution, chaînes d'édition / extension |
| AuthZ après création | facultative | obligatoire au téléchargement du contenu |
Si vous appliquez les timeouts d'une chat completion, par exemple une annulation stricte à 60 s sans polling, l'intégration vidéo semblera « cassée » même lorsque les tâches réussissent ensuite. Concevez une table de tâches dans l'application dès le premier jour.
Modèle de données applicatif recommandé
video_jobs
id (your id)
provider_task_id
model
prompt_hash / prompt_text (policy-dependent)
status
progress
seconds
size
billing_owner_type / billing_owner_id
team_id / project_id (nullable)
content_expires_at
storage_key (nullable until persisted)
source_task_id (edit/extension/remix lineage)
last_error
created_at / updated_at
Les workers mettent à jour status et progress à partir du polling ou du webhook. Lorsque la tâche est completed, un worker télécharge /content une fois, l'enregistre dans l'object storage et renseigne storage_key. En cas de failed, exposez error.message / error.code sans retries infinis.
Limites de durée et de facturation
La durée est un multiplicateur de facturation. Ce dépôt plafonne la durée fournie par l'utilisateur avec MaxTaskDurationSeconds = 3600 et refuse les valeurs seconds hors limites lors de la validation. Le produit doit imposer un maximum UX plus strict, par exemple 4 à 12 secondes pour les aperçus, même si la plateforme permet davantage. Les exemples officiels OpenAI utilisent généralement des paliers de secondes discrets, y compris des variantes plus longues de 16/20 secondes dans la documentation Sora actuelle ; n'inventez jamais de durées libres.
Règles d'intégration :
- analysez
secondsavec soin ; le DTO peut le transporter comme chaîne - ne faites jamais confiance à la durée envoyée par le client pour afficher un prix sans revalidation serveur
- pré-consommez le quota du propriétaire de facturation, utilisateur ou équipe, pas seulement de l'acteur
- réglez ou remboursez lorsque la tâche échoue après pré-consommation
- appliquez la même discipline aux chaînes edit/extension/remix afin que les utilisateurs n'amplifient pas le coût accidentellement
Consultez architecture de passerelle LLM multi-locataires pour la séparation propriétaire/acteur et journaux d'usage et suivi des coûts LLM pour les champs d'attribution.
Stratégie d'attente : webhooks d'abord, polling en fallback
Le guide vidéo d'OpenAI recommande un polling environ toutes les 10 à 20 secondes avec backoff, et préfère les webhooks (video.completed / video.failed) lorsqu'ils sont disponibles. Les URL de téléchargement sont décrites comme de courte durée, environ 1 heure après la génération dans le guide OpenAI ; copiez rapidement les octets dans votre stockage.
Valeurs pratiques pour les workers produit :
- Enregistrez des webhooks lorsque le fournisseur et le chemin d'exploitation de la passerelle prennent en charge une livraison signée.
- Gardez le polling comme filet de sécurité : commencez près de 10 s, ajoutez du jitter et reculez vers 20–30 s sous charge ou après plusieurs
in_progress. - Respectez
Retry-Afterlorsqu'il est présent. - Limitez l'attente totale par un timeout strict et un état local terminal
expired/failed. - Ne pollez jamais toutes les quelques centaines de millisecondes depuis chaque onglet du navigateur.
type VideoTask = {
id: string;
status: "queued" | "in_progress" | "completed" | "failed" | string;
progress?: number;
expires_at?: number;
error?: { message?: string; code?: string };
};
async function sleep(ms: number) {
await new Promise((r) => setTimeout(r, ms));
}
async function pollVideo(taskId: string, timeoutMs = 15 * 60_000): Promise<VideoTask> {
const started = Date.now();
let interval = 10_000;
while (Date.now() - started < timeoutMs) {
const res = await fetch(`${process.env.GATEWAY_BASE}/v1/videos/${taskId}`, {
headers: { Authorization: `Bearer ${process.env.GATEWAY_KEY}` },
});
if (res.status === 429) {
const ra = Number(res.headers.get("retry-after"));
await sleep(Number.isFinite(ra) ? ra * 1000 : interval);
interval = Math.min(interval + 5_000, 30_000);
continue;
}
if (!res.ok) throw new Error(await res.text());
const task = (await res.json()) as VideoTask;
if (task.status === "completed" || task.status === "failed") return task;
const jitter = Math.floor(Math.random() * 2_000);
await sleep(interval + jitter);
interval = Math.min(Math.floor(interval * 1.2), 30_000);
}
throw new Error("video poll timeout");
}
Ajustez ces valeurs selon les temps de complétion mesurés pour vos modèles et votre région, pas selon le billet d'une autre équipe.
AuthZ du téléchargement de contenu et portée de l'atelier
Créer une tâche ne signifie pas être autorisé à lire ses octets plus tard. Dans une passerelle multi-locataires, /v1/videos/{id}/content doit imposer la propriété : le même utilisateur, la même équipe et le même projet que lors de la création, sauf politique de partage explicite. La devinette d'un ID de tâche inter-locataires doit échouer de manière fermée.
Chemins de l'atelier dans ce dépôt :
- UI : atelier vidéo
- API personnelles sous
/api/user/video-workbench - API d'équipe sous
/api/teams/:team_id/video-workbench, avec actions limitées au projet - droits distincts, par exemple générer des vidéos ou gérer les ressources vidéo
C'est différent de l'atelier image, personnel uniquement. Si l'object storage est requis pour une lecture durable dans l'atelier, configurez-le avant de promettre un historique permanent. Les URL de lecture de fallback qui pointent vers /v1/videos/{id}/content nécessitent toujours une AuthZ active et peuvent être soumises à expires_at.
Éditions, extensions, personnages et ancien remix
Recommandations officielles OpenAI pour les nouvelles intégrations :
- Éditions :
POST /v1/videos/editsavec un prompt et lavideosource pour les changements ciblés ; remix est déprécié pour ce rôle. - Extensions :
POST /v1/videos/extensionspour prolonger un clip terminé ; la durée totale est assemblée et les personnages ne sont pas pris en charge dans les extensions selon le guide OpenAI. - Personnages :
POST /v1/videos/characters, puis référence aux ID de personnages lors de la création pour conserver la cohérence. - Batch : files hors ligne de lignes JSON
POST /v1/videos; les sorties Batch ont leur propre fenêtre de rétention dans la documentation OpenAI.
Conseils qui restent valables pour toute tâche dérivée, y compris l'ancien remix toujours présent dans cette passerelle :
- n'autorisez une tâche dérivée que si l'appelant peut lire la tâche source
- copiez les champs de tenancy depuis la source ; ne laissez pas un dérivé orphelin sous le mauvais projet
- indiquez qu'une édition, extension ou remix est une nouvelle tâche facturable, pas une modification gratuite
- persistez la lignée pour le support et la modération
- placez tout bag de métadonnées propre à un fournisseur derrière un feature flag ; validez durée et taille avec les limites globales
Tant que la passerelle ne normalise pas les éditions, extensions et personnages, gardez ces appels derrière des flags d'adaptateur explicites ou des clients upstream natifs. Ne présentez pas remix comme le chemin OpenAI moderne.
Politique de persistance
Supposez que :
- les URL de contenu upstream et même les proxys temporaires de la passerelle peuvent expirer ;
expires_atest un champ de première classe et OpenAI documente environ 1 heure pour les téléchargements interactifs - les pages produit ont besoin de vos clés d'objet
- les miniatures sont dérivées après téléchargement, pas récupérées à la volée depuis les CDN fournisseurs
- la suppression doit être possible lorsqu'une équipe part ou qu'un utilisateur exerce ses droits de rétention
Pipeline sûr :
completed → récupération de contenu autorisée → détection virus/type si nécessaire → écriture dans l'object storage → storage_key en base → service via votre CDN avec authentification applicative.
Repousser le stockage « jusqu'à ce qu'il soit nécessaire » transforme les démonstrations en tickets d'incident, surtout lorsque l'API Videos upstream elle-même arrive en fin de vie.
Observabilité et support
Journalisez au minimum l'ID de requête / tâche de la passerelle, l'alias du modèle, les secondes, la taille, les transitions de statut, le propriétaire de facturation et l'acteur, le chemin webhook ou poll, et le code d'erreur final. Les dashboards doivent séparer les classes d'échec vidéo des échecs chat. Les outils de support doivent ouvrir la tâche et le journal d'usage sans télécharger le MP4 complet dans le système de tickets.
Routes alternatives possibles
Selon les adaptateurs de canaux, les opérateurs peuvent aussi activer :
- des endpoint de type
/v1/video/generations - Kling
/kling/v1/videos/* - des adaptateurs de tâches Gemini/Vertex Veo
- d'autres API de tâches fournisseurs derrière Jimeng ou des routes similaires
Les équipes applicatives ne doivent pas coder en dur chaque chemin fournisseur. Préférez un client normalisé (/v1/videos + alias stables) et laissez la passerelle mapper les canaux. Lorsqu'une fonction n'existe que sur une route fournisseur, par exemple motion brushes ou presets cinéma, isolez-la derrière un feature flag et documentez le contrat non portable.
Lectures associées
- Comparaison des API de génération vidéo en 2026
- Intégration d'une API de génération d'images
- Passerelle LLM API auto-hébergée
Sources
- Guide OpenAI de génération vidéo
- Référence OpenAI Videos API
- Dépréciations OpenAI, Videos API / Sora 2 → 2026-09-24
- Guide OpenAI des webhooks
- Génération vidéo Google Gemini
- Documentation développeur Runway
- Documentation de l'API Luma AI
- OWASP Top 10 for LLM Applications
Questions opérationnelles
Peut-on bloquer la requête HTTP jusqu'à la fin de la vidéo ?
Uniquement pour de petits outils internes. Les UI produit doivent créer un enregistrement de tâche et utiliser des webhooks ou le polling. Les longues requêtes synchrones amplifient les timeouts de la passerelle et du load balancer.
Quel intervalle de polling utiliser ?
Commencez près de 10 secondes avec jitter, reculez vers 20–30 secondes, respectez Retry-After et préférez les webhooks video.completed / video.failed lorsqu'ils sont disponibles. Le guide OpenAI indique environ 10 à 20 secondes.
Pourquoi le téléchargement a-t-il échoué après le statut completed ?
Causes fréquentes : contenu expiré, mauvaise portée d'authentification, tâche appartenant à un autre projet ou mauvaise configuration du stockage/proxy. Vérifiez expires_at et les champs de tenancy avant de relancer une génération.
Les nouveaux produits doivent-ils utiliser remix ?
Non comme chemin principal d'édition. La documentation officielle OpenAI oriente les nouvelles éditions vers POST /v1/videos/edits ; remix est déprécié. Cette passerelle peut encore accepter les routes de type remix pour compatibilité : traitez-les comme une transition historique, pas comme un design greenfield.
L'atelier vidéo est-il nécessaire si j'appelle déjà /v1/videos ?
Non pour les pipelines backend purs. Oui lorsque des humains ont besoin d'un historique partagé, de presets ou d'une gestion des ressources limitée à l'équipe dans l'UI.
Premier worker à livrer
Implémentez un worker unique qui crée une courte vidéo via un alias stable non limité à Sora, si vous en avez un, ou via un alias Sora explicitement temporaire avec une date de migration écrite avant le 2026-09-24. Pollez avec 10 s + jitter, avec webhook facultatif, téléchargez /content une seule fois, uploadez dans l'object storage et prouvez que la clé d'une deuxième équipe ne peut pas télécharger l'ID de tâche. Ensuite seulement, branchez le happy path dans l'UI produit.