Skip to Content
FeaturesVideo Generation

Video Generation

Learn how to make API calls to generate video from text or generate video from an image

Overview

This guide covers generating videos on AI.ML with video generation models, including request/response formats, polling, and downloading the final file.

Base URL: <https://api.ai.ml>
Auth: Bearer token via Authorization: Bearer <AIML_API_KEY>
Model: video-gen.pro-1.0

Core workflow (all tasks):

  1. Create taskPOST /v1/generation/tasks/video Returns a task UUID.

  2. Poll taskGET /v1/generation/tasks/video/{task-uuid}
    When status === "succeeded", response includes a backend media URL in videoUrl (e.g., /v1/media/videos/orgs%2F64%2Fvideos%2F...).

  3. Resolve media URL → Authorized GET to the backend media URL returns { "url": "<presigned-download-url>" }.

  4. Download videoGET the presigned URL (no auth) to save video.mp4.

Typical inline directives (inside your text prompt):

  • --resolution 720p|1080p|...

  • --duration <seconds>

  • --camerafixed true|false

Video API

Endpoints

  • POST /v1/generation/tasks/video — Create a text-to-video or image-to-video task.
  • GET /v1/generation/tasks/video/{task-uuid} — Poll task status & get backend media URL when ready.
  • GET /v1/media/videos/{path-encoded} — Resolve backend media URL to presigned download URL.

Request (JSON)POST /v1/generation/tasks/video

FieldTypeRequiredExampleNotes
modelstring"video-gen.pro-1.0"Model identifier
contentarraySee belowOrdered list of inputs
content[].typestring"text" or "image_url"Input item type
content[].textstringif type = text"A serene forest ... --resolution 720p --duration 5"Text prompt + inline directives
content[].image_url.urlstringif type = image_urlhttps://example.com/still.jpgPublicly accessible image URL

Response (create task)

{ "data": { "uuid": "9b9f1e2c-1a23-45b6-8c9d-1234567890ab", "status": "queued" } }

PollingGET /v1/generation/tasks/video/{task-uuid}

Successful (ready) example

{ "data": { "uuid": "9b9f1e2c-1a23-45b6-8c9d-1234567890ab", "status": "succeeded", "videoUrl": "/v1/media/videos/orgs%2F64%2Fvideos%2F2025%2F10%2Fabc123.mp4" } }

Statuses you may see

  • queued / running — keep polling

  • succeededvideoUrl present

  • failed — check error object if present

  • canceled — task canceled server-side

Error example

{ "error": { "code": "invalid_request", "message": "Text content is required." } }

Resolve & Download

  1. Resolve backend media URL (authorized):
GET /v1/media/videos/orgs%2F64%2Fvideos%2F2025%2F10%2Fabc123.mp4 Authorization: Bearer <AIML_API_KEY>

Response:

{ "url": "https://presigned.cdn.ai.ml/..." } 2. Download (no auth):
GET <https://presigned.cdn.ai.ml/...> → bytes (video/mp4)

Text-to-Video Generation

import fs from 'node:fs';
import fetch from 'node-fetch';

const API = 'https://api.ai.ml';
const API_KEY = process.env.AIML_API_KEY || 'AIML_API_KEY';

(async () => {
// 1) Create task
const createRes = await fetch(`${API}/v1/generation/tasks/video`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'video-gen.pro-1.0',
    content: [
      {
        type: 'text',
        text: 'A serene forest scene with a flowing stream and dappled sunlight --resolution 720p --duration 5'
      }
    ]
  })
});
if (!createRes.ok) throw new Error(`HTTP ${createRes.status}: ${await createRes.text()}`);
const { data: { uuid } } = await createRes.json();

// 2) Poll for status
let backendUrl;
while (!backendUrl) {
  const sRes = await fetch(`${API}/v1/generation/tasks/video/${uuid}`, {
    headers: { Authorization: `Bearer ${API_KEY}` }
  });
  const s = await sRes.json();
  if (s?.data?.status === 'failed') throw new Error('Task failed');
  backendUrl = s?.data?.videoUrl;
  if (!backendUrl) await new Promise(r => setTimeout(r, 3000));
}

// 3) Resolve presigned URL
const resRes = await fetch(backendUrl.startsWith('http') ? backendUrl : `${API}${backendUrl}`, {
  headers: { Authorization: `Bearer ${API_KEY}` }
});
const { url: presignedUrl } = await resRes.json();

// 4) Download video
const fileRes = await fetch(presignedUrl);
const buf = Buffer.from(await fileRes.arrayBuffer());
fs.writeFileSync('video.mp4', buf);
console.log('Saved video.mp4');
})().catch(console.error);

Image-to-Video Generation

Attach an image plus a text instruction by adding an image_url item after your text item in content.

import fs from 'node:fs';
import fetch from 'node-fetch';

const API = 'https://api.ai.ml';
const API_KEY = process.env.AIML_API_KEY || 'AIML_API_KEY';

(async () => {
const createRes = await fetch(`${API}/v1/generation/tasks/video`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'video-gen.pro-1.0',
    content: [
      {
        type: 'text',
        text: 'In the sky, soft cotton-like clouds drift... --resolution 720p --duration 5 --camerafixed false'
      },
      {
        type: 'image_url',
        image_url: { url: 'https://google.com/sample' }
      }
    ]
  })
});
const { data: { uuid } } = await createRes.json();

let backendUrl;
while (!backendUrl) {
  const sRes = await fetch(`${API}/v1/generation/tasks/video/${uuid}`, {
    headers: { Authorization: `Bearer ${API_KEY}` }
  });
  const s = await sRes.json();
  if (s?.data?.status === 'failed') throw new Error('Task failed');
  backendUrl = s?.data?.videoUrl;
  if (!backendUrl) await new Promise(r => setTimeout(r, 3000));
}

const resRes = await fetch(backendUrl.startsWith('http') ? backendUrl : `${API}${backendUrl}`, {
  headers: { Authorization: `Bearer ${API_KEY}` }
});
const { url: presignedUrl } = await resRes.json();

const fileRes = await fetch(presignedUrl);
fs.writeFileSync('video.mp4', Buffer.from(await fileRes.arrayBuffer()));
console.log('Saved video.mp4');
})().catch(console.error);

Poll & resolve exactly as in the Text-to-Video flow.

Implementation Notes & Best Practices

  • Prompt design: Keep cinematic directions concise; use inline flags for resolution/duration/camera.
  • Polling cadence: 2–5 seconds is a good balance; include a timeout or retry limit.
  • Error handling: Check HTTP codes and data.status.
  • Security: Never expose API keys in client apps.
  • Presigned URLs: They expire quickly—resolve right before downloading.
  • File sizes: Prefer streaming and chunked writes for large outputs.
Last updated on