curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
Gemini Omni 1.2 Flash
Génération vidéo Gemini Omni 1.2 Flash
Vidéo à partir de texte ou d’images, références de sujets, interpolation entre images initiale et finale, montage et prolongation. Jusqu’à 4K, 24fps, avec audio.
POST
/
v1
/
videos
/
generations
curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
La génération à partir de texte ou d’images accepte un entier de 3 à 15 secondes, avec 10 par défaut. L’interpolation entre images initiale et finale et le segment ajouté lors d’une prolongation sont limités à 10 secondes. Le montage ignore
duration et conserve la durée de la vidéo source. Une vidéo en entrée est modifiée par défaut ; la prolongation exige "omni_reference_task_type": "extend".curl --request POST \
--url https://api.apimart.ai/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15
}'
import time
import requests
base_url = "https://api.apimart.ai"
headers = {"Authorization": "Bearer <token>"}
payload = {
"model": "gemini-omni-1.2-flash",
"prompt": "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
"aspect_ratio": "16:9",
"resolution": "720p",
"duration": 15,
}
response = requests.post(
f"{base_url}/v1/videos/generations",
headers=headers, json=payload, timeout=30,
)
response.raise_for_status()
task_id = response.json()["data"][0]["task_id"]
print(task_id)
deadline = time.monotonic() + 600
while time.monotonic() < deadline:
response = requests.get(
f"{base_url}/v1/tasks/{task_id}", headers=headers, timeout=30,
)
response.raise_for_status()
task = response.json()["data"]
if task["status"] == "completed":
print(task["result"]["videos"][0]["url"][0])
break
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
time.sleep(5)
else:
raise TimeoutError(f"Continue polling task {task_id}")
const baseUrl = "https://api.apimart.ai";
const headers = {
Authorization: "Bearer <token>",
"Content-Type": "application/json",
};
const response = await fetch(`${baseUrl}/v1/videos/generations`, {
method: "POST",
headers,
signal: AbortSignal.timeout(30_000),
body: JSON.stringify({
model: "gemini-omni-1.2-flash",
prompt: "A marble rolling fast on a chain reaction style track, continuous smooth shot.",
aspect_ratio: "16:9",
resolution: "720p",
duration: 15,
}),
});
if (!response.ok) throw new Error(await response.text());
const taskId = (await response.json()).data[0].task_id;
console.log(taskId);
async function waitForTask(taskId) {
const deadline = Date.now() + 600_000;
while (Date.now() < deadline) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, {
headers,
signal: AbortSignal.timeout(30_000),
});
if (!response.ok) throw new Error(await response.text());
const task = (await response.json()).data;
if (task.status === "completed") return task.result.videos[0].url[0];
if (task.status === "failed") throw new Error(task.error.message);
await new Promise(resolve => setTimeout(resolve, 5000));
}
throw new Error(`Continue polling task ${taskId}`);
}
console.log(await waitForTask(taskId));
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01EXAMPLE"
}
]
}
Authentification
string
requis
Utilisez un jeton Bearer. Obtenez une clé sur la page de gestion des clés API et envoyez les requêtes avec
Content-Type: application/json.Paramètres de requête
string
requis
Doit être
gemini-omni-1.2-flash.string
requis
Instructions textuelles obligatoires : décrivez la scène pour le texte vers vidéo, ou les mouvements, le style et les modifications pour les autres modes.
prompt est obligatoire même avec des images de référence, des images initiale/finale, une vidéo ou extend_from_task_id. Son absence renvoie HTTP 400.integer
défaut:"10"
Durée de sortie pour la génération à partir de texte ou d’images, entier de
3 à 15, avec 10 par défaut. L’interpolation initiale/finale et la prolongation acceptent uniquement 3–10 secondes. Pour une prolongation, il s’agit de la durée ajoutée ; la vidéo renvoyée contient l’original et le segment ajouté. Le montage ignore duration et conserve la durée de la vidéo source. Une valeur de paramètre hors plage fait échouer la tâche avec invalid_duration.string
défaut:"720p"
360p / 720p / 1080p / 4k, sans distinction de casse ; 2160p équivaut à 4k. Les sorties 1080p et 4k sont suréchantillonnées. La résolution influe sur les tokens de sortie et le montant réservé. Les autres valeurs font échouer la tâche avec invalid_resolution.string
défaut:"16:9"
Uniquement
16:9 (paysage, par défaut) et 9:16 (portrait). Les autres valeurs sont traitées comme 16:9.string[]
Images de référence uniquement sous forme d’URL HTTP(S) directes et accessibles publiquement. Les Data URL et Base64 ne sont pas pris en charge. Une image sert de départ ; plusieurs images servent de références de sujets. Maximum 10 images au total, images initiale/finale comprises. Pour les personnages, privilégiez au plus 2 personnages et 3 images chacun, soit 6 images au maximum.
string
Image initiale. Seule, elle sert de point de départ ; avec
last_frame_image, elle active l’interpolation entre les deux images. Seules les URL HTTP(S) directes et accessibles publiquement vers une image sont acceptées.string
Image finale ; exige
first_frame_image, sinon la tâche échoue avec invalid_frame_images. Utilisez le même ratio pour les deux images, correspondant à aspect_ratio. Seules les URL HTTP(S) directes et accessibles publiquement vers une image sont acceptées.object[]
Tableau d’images avec rôles, équivalent aux champs directs des images initiale/finale. Choisissez une seule méthode. Toutes les images utilisées comptent dans la limite totale de 10.
string[]
Vidéo à modifier ou prolonger : 1 clip maximum, de 15 secondes au plus. Seules les URL HTTP(S) directes et accessibles publiquement vers la vidéo sont acceptées. Les Data URL et Base64 ne sont pas pris en charge. Le mode par défaut est le montage.
string
défaut:"auto"
Type de tâche :
auto (par défaut, déduit des entrées) / edit (montage) / extend (prolongation) / reference (plusieurs images de référence). Accepte aussi text_to_video / image_to_video / reference_to_video. Sans valeur ou avec auto, video_urls et extend_from_task_id déclenchent un montage par défaut. Pour prolonger, indiquez explicitement extend.string
Référencez l’ID de votre précédente tâche de génération pour réutiliser la vidéo sans la téléverser. Le mode par défaut est le montage. Avec
"omni_reference_task_type": "extend", un segment de 10 secondes au maximum est ajouté à la fin.Fonctionnalités et limites
- La sortie est à 24fps, avec dialogues, musique ou effets sonores. Décrivez l’audio souhaité dans
prompt. - L’entrée audio, les system prompts,
temperatureet les paramètres de prompt négatif ne sont pas pris en charge. Écrivez les exclusions directement dansprompt. - Restrictions régionales du fournisseur : dans l’EEE, en Suisse et au Royaume-Uni, le montage ou la prolongation de vidéos téléversées et la modification d’images contenant des mineurs ne sont pas pris en charge.
- Toutes les sorties comportent un filigrane invisible SynthID.
Exemples
Envoyez chaque corps JSON àPOST /v1/videos/generations. Remplacez les URL et ID d’exemple par vos propres médias et tâches utilisables.
Vidéo portrait de 15 secondes en 4K
{
"model": "gemini-omni-1.2-flash",
"prompt": "Aerial shot over a misty mountain lake at sunrise, birds flying, slow forward camera move.",
"aspect_ratio": "9:16",
"resolution": "4k",
"duration": 15
}
Image vers vidéo et références de sujets
{
"model": "gemini-omni-1.2-flash",
"prompt": "The cat playfully bats at the ball of yarn.",
"image_urls": [
"https://example.com/cat.png",
"https://example.com/yarn.png"
],
"duration": 12
}
Interpolation entre images initiale et finale
{
"model": "gemini-omni-1.2-flash",
"prompt": "Smooth transition, camera slowly pushes in.",
"first_frame_image": "https://example.com/start.jpg",
"last_frame_image": "https://example.com/end.jpg",
"aspect_ratio": "16:9",
"duration": 8
}
Déclaration des images avec des rôles
{
"model": "gemini-omni-1.2-flash",
"prompt": "A smooth cinematic transition from sunrise to a starry night.",
"image_with_roles": [
{
"url": "https://example.com/sunrise.jpg",
"role": "first_frame"
},
{
"url": "https://example.com/night.jpg",
"role": "last_frame"
}
],
"duration": 8
}
Montage vidéo
{
"model": "gemini-omni-1.2-flash",
"prompt": "Make the violin invisible. Keep everything else the same.",
"video_urls": [
"https://example.com/clip.mp4"
]
}
duration est sans effet.
Utilisez des instructions de montage courtes et précises. Pour une modification locale, ajoutez Keep everything else the same.
Prolongation d’une tâche existante
{
"model": "gemini-omni-1.2-flash",
"prompt": "The camera continues panning across the mountains.",
"extend_from_task_id": "task_01PREVIOUS",
"omni_reference_task_type": "extend",
"duration": 8
}
extend_from_task_id par video_urls et conservez "omni_reference_task_type": "extend". La vidéo renvoyée contient l’original suivi du segment ajouté. duration contrôle uniquement la durée ajoutée, limitée à 10 secondes ; seules les secondes ajoutées sont facturées. Par exemple, une source de 5 secondes avec duration: 4 produit une vidéo d’environ 9 secondes.
Réponse de soumission et suivi de tâche
Une soumission réussie renvoie HTTP 200 ; récupérezdata[0].task_id. Interrogez le statut de la tâche toutes les 5–10 secondes jusqu’à completed ou failed. Prévoyez une attente globale de 10 minutes. Si le client expire, continuez à interroger la tâche initiale sans la soumettre à nouveau.
curl --request GET \
--url https://api.apimart.ai/v1/tasks/task_01EXAMPLE \
--header 'Authorization: Bearer <token>'
{
"code": 200,
"data": {
"id": "task_01EXAMPLE",
"status": "completed",
"progress": 100,
"result": {
"videos": [
{
"url": [
"https://cdn.example.com/gemini_omni_video.mp4"
]
}
]
}
}
}
data dans la réponse de suivi est l’objet tâche. data.result.videos[0].url est un tableau ; la première URL est data.result.videos[0].url[0]. Elle permet la lecture ou le téléchargement. Archivez le fichier pour le conserver durablement. data.cost est le montant final en USD.
| Statut | Action |
|---|---|
pending / processing | Continuez le suivi ; consultez data.progress. |
completed | Récupérez l’URL et enregistrez la vidéo. |
failed | Consultez data.error.message. Les tâches échouées ne sont pas facturées. |
Facturation et solde réservé
Facturation par tokens : la résolution détermine les tokens de sortie vidéo par seconde. Pour la génération à partir de texte ou d’images,duration définit la durée de sortie. Le montage ignore ce paramètre et conserve la durée de la source ; la prolongation l’utilise uniquement pour le segment ajouté. Consultez les tarifs APIMart.
À la soumission, le solde réservé dépend de la résolution et de max(10, duration) secondes ; une vidéo en entrée entraîne une estimation de 15 secondes. La réserve n’est pas le montant final. Après réussite, elle est ajustée à l’utilisation réelle ; le résultat figure dans data.cost.
La prolongation est facturée uniquement sur les secondes ajoutées. Un échec n’est pas facturé. Un solde insuffisant pour la réserve renvoie HTTP 402.
Gestion des erreurs
Les erreurs de paramètres (invalid_* / unsupported_*) font immédiatement passer la tâche à failed, sans facturation. Vérifiez le statut même après une soumission réussie.
| Erreur / statut | Cause et action |
|---|---|
invalid_duration | duration hors de 3–15, ou interpolation / prolongation dépassant 10 secondes. Utilisez un entier autorisé. |
invalid_task_type | Valeur non prise en charge pour omni_reference_task_type. Utilisez auto / edit / extend / reference ; text_to_video / image_to_video / reference_to_video sont aussi acceptés. |
invalid_resolution | Utilisez 360p / 720p / 1080p / 4k ; 2160p est également accepté. |
invalid_frame_images | Seule une image finale a été fournie. Ajoutez l’image initiale. |
unsupported_image_count | Plus de 10 images, images initiale/finale comprises. Réduisez leur nombre. |
unsupported_video_count | Plus d’une vidéo en entrée. Conservez un seul clip de 15 secondes au maximum. |
HTTP 400 | Le paramètre obligatoire prompt est absent. Fournissez des instructions textuelles même avec un média. |
HTTP 401 | Clé invalide. Vérifiez Authorization. |
HTTP 402 | Solde insuffisant pour la réserve. Rechargez ou réduisez la résolution. |
HTTP 429 | Limite de requêtes atteinte. Réessayez avec un délai croissant. |
status: failed | Erreur du fournisseur ou rejet lié au contenu. Lisez data.error.message et ajustez la requête. |
Questions fréquentes
prompt est-il obligatoire avec des images ou une vidéo ?
Oui. Tous les modes exigent prompt, y compris la génération depuis des images, l’interpolation initiale/finale, le montage, la prolongation et la réutilisation d’une vidéo via extend_from_task_id. Son absence renvoie HTTP 400.
Puis-je envoyer directement des images ou une vidéo en Base64 ?
Non.image_urls, first_frame_image, last_frame_image, image_with_roles[].url et video_urls acceptent uniquement des URL HTTP(S) directes et accessibles publiquement. N’envoyez pas de data:image/..., de data:video/... ni de chaînes Base64 brutes.