Documentation/Video Generation
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

Video Generation

Video Generation

The unified asynchronous video API supports Google Veo/Gemini Omni and xAI Grok Imagine. Start a job, poll or wait for completion, then download through the same high-level surface. OpenAI's Videos API is retired; see OpenAI Sora for compatibility and migration behavior.

Basic Usage

typescript
import { Connector, VideoGeneration, Vendor } from 'oneringai';
import * as fs from 'fs/promises';

// Setup connector
Connector.create({
  name: 'google-video',
  vendor: Vendor.Google,
  auth: { type: 'api_key', apiKey: process.env.GOOGLE_API_KEY! },
});

// Create video generator
const videoGen = VideoGeneration.create({ connector: 'google-video' });

// Start video generation (returns immediately with job ID)
const job = await videoGen.generate({
  prompt: 'A cinematic shot of a sunrise over mountains with clouds rolling',
  model: 'veo-3.1-lite-generate-preview',
  duration: 8,           // 8 seconds
});

console.log('Job started:', job.jobId);
console.log('Status:', job.status);  // 'pending'

// Wait for completion (polls every 10 seconds, default 10-minute timeout)
const result = await videoGen.waitForCompletion(job.jobId);

// Download the completed video
const videoBuffer = await videoGen.download(job.jobId);
await fs.writeFile('./output.mp4', videoBuffer);

Understanding the Async Model

Video generation takes significant time (often minutes). The API uses an async job model:

typescript
// 1. Start generation - returns immediately
const job = await videoGen.generate({ prompt: '...', duration: 8 });
// job.status = 'pending'

// 2. Poll for status (optional - if you want progress updates)
const status = await videoGen.getStatus(job.jobId);
// status.status = 'processing', status.progress = 45

// 3. Wait for completion (blocks until done or timeout)
const result = await videoGen.waitForCompletion(job.jobId);
// result.status = 'completed'

// 4. Download the video
const buffer = await videoGen.download(job.jobId);

Or use the convenience method:

typescript
// Generate and wait in one call
const result = await videoGen.generateAndWait({
  prompt: 'A butterfly flying through a garden',
  duration: 4,
});

const buffer = await videoGen.download(result.jobId);

Video Response Structure

The API returns a VideoResponse object:

typescript
interface VideoResponse {
  jobId: string;              // Unique job identifier
  status: 'pending' | 'processing' | 'completed' | 'failed';
  created: number;            // Unix timestamp
  progress?: number;          // 0-100 percentage (when processing)
  video?: {
    url?: string;             // Download URL (if available)
    b64_json?: string;        // Base64-encoded video data (if provider returns inline)
    duration?: number;        // Actual duration in seconds
    resolution?: string;      // Actual resolution
    format?: string;          // 'mp4' typically
  };
  audio?: {                   // Separate audio track (if provider returns one)
    url?: string;
    b64_json?: string;
  };
  error?: string;             // Error message if failed
}

Viewing Your Generated Video

After downloading, the video is a standard MP4 file that can be:

typescript
// Save to file
await fs.writeFile('./output.mp4', videoBuffer);

// Open with default player (Node.js)
import { exec } from 'child_process';
exec('open ./output.mp4');  // macOS
exec('xdg-open ./output.mp4');  // Linux
exec('start ./output.mp4');  // Windows

// Serve via web server
import express from 'express';
const app = express();
app.get('/video', (req, res) => {
  res.setHeader('Content-Type', 'video/mp4');
  res.send(videoBuffer);
});

// Convert to base64 for embedding
const base64 = videoBuffer.toString('base64');
const dataUrl = `data:video/mp4;base64,${base64}`;

OpenAI Sora

OpenAI shut down the Videos API, sora-2, sora-2-pro, and their snapshots on 2026-09-24, with no replacement listed. See the official retirement notice.

The provider class, model constants, and high-level methods remain exported for source compatibility. Generation (including an omitted model), polling, download, extension, remix, edit, and character operations reject locally with ProviderError (status 410), without SDK requests, uploads, or file reads. listModels() returns [], the provider advertises no video capabilities, and cancel() / cancelJob() return false because no remote cancellation occurs. Constructing a video generator with an OpenAI connector still permits discovery.

Sora registry records report isActive: false and lifecycle: 'retired'. They retain historical capabilities/pricing for saved configuration and cost lookup; active, deprecated, feature, and audio selectors exclude them. There is no OpenAI video default or automatic cross-vendor fallback. Configure a named Google or Grok connector explicitly to generate new videos. Existing OpenAI job IDs and credentials cannot be transferred to these providers.

Google Veo

typescript
// Setup Google connector
Connector.create({
  name: 'google',
  vendor: Vendor.Google,
  auth: { type: 'api_key', apiKey: process.env.GOOGLE_API_KEY! },
});

const googleVideo = VideoGeneration.create({ connector: 'google' });

// Veo 3.1 Lite is the current high-level Google default.
const lite = await googleVideo.generate({
  prompt: 'A colorful butterfly landing on a flower',
  model: 'veo-3.1-lite-generate-preview',
  duration: 6,
  resolution: '1080p',
  vendorOptions: {
    negativePrompt: 'blurry, low quality',  // What to avoid
  },
});

// Veo 3.1 Fast (with audio support)
const veo3 = await googleVideo.generate({
  prompt: 'A thunderstorm over a city with lightning',
  model: 'veo-3.1-fast-generate-preview',
  duration: 8,
  vendorOptions: {
    personGeneration: 'dont_allow',  // Safety setting
  },
});

// Veo 3.1 (full feature set and 4K support)
const veo31 = await googleVideo.generate({
  prompt: 'A drone shot flying over mountains',
  model: 'veo-3.1-generate-preview',
  duration: 8,
  resolution: '4k',
});

// Gemini Omni uses the Interactions API for conversational video editing.
const omni = await googleVideo.generate({
  prompt: 'Animate this storyboard with a gentle dolly movement',
  model: 'gemini-omni-1.1-flash',
  image: './storyboard.png',
  duration: 6,
});

For Omni image-to-video, local paths, buffers, data URIs, and HTTP(S) source images are normalized to inline image blocks with their detected PNG or JPEG MIME type. The public duration option is serialized as response_format.duration (for example, "6s"); it is not placed in generation_config.video_config, whose public control is the generation task.

veo-2.0-generate-001 is retired and remains only as a registry migration record.

xAI Grok Imagine Video

typescript
Connector.create({
  name: 'xai',
  vendor: Vendor.Grok,
  auth: { type: 'api_key', apiKey: process.env.XAI_API_KEY! },
});

const grokVideo = VideoGeneration.create({ connector: 'xai' });

// Current text-to-video default.
const textJob = await grokVideo.generate({
  prompt: 'A paper sculpture unfolding into a city skyline',
  model: 'grok-imagine-video',
  duration: 8,
  resolution: '720p',
});

// Grok Imagine Video 1.5 is preferred for higher-fidelity image-to-video.
const imageJob = await grokVideo.generate({
  prompt: 'Slow cinematic push-in with moving clouds',
  model: 'grok-imagine-video-1.5',
  image: './keyframe.png',
  duration: 8,
  resolution: '1080p',
});

Video Extension

Use extend() with a provider/model that supports extension, such as the Google Veo provider. Its default extension model remains veo-3.1-generate-preview. Supply the video reference expected by that provider. OpenAI Sora extension, remix, editing, and reusable-character endpoints are retired and reject locally as described above; the public method signatures remain available.

Available Models

Prices below are historical or checked-in registry estimates, not live quotes. The video registry retains retired Sora and Veo 2 records for historical lookup. Use the active-model selectors for new work.

OpenAI Sora Models

Model Features Durations Resolutions Price/Second
sora-2 Retired 2026-09-24; historical metadata only 4-20s 720p $0.10 ($0.05 batch)
sora-2-pro Retired 2026-09-24; historical metadata only 4-20s 720p-1080p $0.30-$0.70 ($0.15-$0.35 batch)

Google Veo Models

Model Features Durations Resolutions Price/Second
veo-3.1-lite-generate-preview Preferred low-cost preview, native audio 4-8s 720p-1080p $0.05-$0.08
veo-3.1-fast-generate-preview Fast inference, audio 4-8s 720p-4K $0.10-$0.30
veo-3.1-generate-preview Full features, 4K 4-8s 720p-4K $0.40
gemini-omni-1.1-flash Active, preferred conversational generation/editing 3-10s 360p-4K ~$0.10 at 720p
gemini-omni-flash-preview Historical migration entry; inspect lifecycle before use 3-10s 720p $0.10

xAI Grok Imagine Models

Model Features Durations Resolutions Price/Second
grok-imagine-video Text/image-to-video with audio 1-15s 480p-720p $0.05-$0.07
grok-imagine-video-1.5 Preferred text/image/reference-to-video 1-15s 480p-1080p $0.08-$0.25 plus $0.01 input image

Model Introspection

typescript
// List available models
const models = await videoGen.listModels();
console.log('Available models:', models);

// Historical metadata is still available for retired models.
const info = videoGen.getModelInfo('sora-2');
console.log('Durations:', info.capabilities.durations);       // [4, 8, 12, 16, 20]
console.log('Resolutions:', info.capabilities.resolutions);   // ['720x1280', ...]
console.log('Has audio:', info.capabilities.audio);           // true
console.log('Image-to-video:', info.capabilities.imageToVideo); // true
console.log('Style control:', info.capabilities.features.styleControl); // false
console.log('Lifecycle:', info.lifecycle);                      // retired
console.log('Callable:', info.isActive);                         // false

Cost Estimation

typescript
import { calculateVideoCost } from 'oneringai';

// Historical Sora 2 pricing: $0.10/second (generation is retired)
const soraCost = calculateVideoCost('sora-2', 8);  // 8 seconds
console.log(`Sora 2 (8s): $${soraCost}`);  // $0.80

// Historical Sora 2 Pro pricing: $0.30/second (generation is retired)
const proCost = calculateVideoCost('sora-2-pro', 12);  // 12 seconds
console.log(`Sora 2 Pro (12s): $${proCost}`);  // $3.60

// Veo 3.1 Lite at 1080p: $0.08/second
const veoCost = calculateVideoCost('veo-3.1-lite-generate-preview', 8, {
  resolution: '1080p',
});
console.log(`Veo 3.1 Lite (8s, 1080p): $${veoCost}`); // $0.64

// Grok 1.5 at 1080p plus one image input.
const grokCost = calculateVideoCost('grok-imagine-video-1.5', 8, {
  resolution: '1080p',
  inputImages: 1,
});
console.log(`Grok Imagine 1.5 (8s, 1080p): $${grokCost}`); // $2.01

Error Handling

typescript
try {
  const job = await videoGen.generate({
    prompt: 'A video',
    duration: 8,
  });

  const result = await videoGen.waitForCompletion(job.jobId, 300000); // 5 min timeout

  if (result.status === 'completed') {
    const buffer = await videoGen.download(result.jobId);
    await fs.writeFile('./output.mp4', buffer);
  }
} catch (error) {
  if (error.message.includes('timed out')) {
    console.error('Video generation took too long');
  } else if (error.message.includes('failed')) {
    console.error('Video generation failed:', error.message);
  } else if (error.message.includes('policy')) {
    console.error('Content policy violation');
  } else {
    console.error('Error:', error.message);
  }
}

Job Management

typescript
// Cancel a pending job
const job = await videoGen.generate({ prompt: '...', duration: 8 });

// Changed your mind? Cancel it
const cancelled = await videoGen.cancel(job.jobId);
console.log('Cancelled:', cancelled);  // true

Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.