Skip to main content

Overview

Creates a new video project that will generate an AI-powered property tour video from a collection of images. The video project orchestrates multiple 5-second clips with smooth transitions and optional background music.

Authentication

Requires an authenticated user session. The video project is created in the user’s workspace.

Request Body

name
string
required
Name of the video projectExample: "123 Main St Property Tour"
description
string
Optional description of the video project
aspectRatio
string
default:"16:9"
Video aspect ratio. Options: 16:9, 9:16, 1:1
  • 16:9 - Landscape (YouTube, desktop)
  • 9:16 - Portrait (TikTok, Instagram Stories)
  • 1:1 - Square (Instagram Feed)
musicTrackId
string
ID of the background music track. Set to null for no music.
musicVolume
number
default:"50"
Music volume (0-100). Only applies if musicTrackId is set.
generateNativeAudio
boolean
default:"true"
Whether to generate ambient audio for clips using AI
clips
array
required
Array of clip configurations. Each clip represents a 5-second segment.

Response

id
string
Unique video project ID
workspaceId
string
Workspace ID
userId
string
Creator’s user ID
name
string
Video project name
status
string
Current status: draft, generating, compiling, completed, failed
clipCount
number
Total number of clips
estimatedCost
number
Estimated cost in cents. Formula: clips × $0.35 × 100
triggerRunId
string
Trigger.dev run ID for progress tracking
createdAt
string
ISO 8601 timestamp

Example Request

{
  "name": "Luxury Penthouse Tour",
  "description": "Downtown property showcase",
  "aspectRatio": "16:9",
  "musicTrackId": "track_modern_upbeat",
  "musicVolume": 60,
  "generateNativeAudio": true,
  "clips": [
    {
      "sourceImageUrl": "https://storage.supabase.co/images/living-room.jpg",
      "endImageUrl": "https://storage.supabase.co/images/living-room-alt.jpg",
      "roomType": "living-room",
      "roomLabel": "Main Living Area",
      "sequenceOrder": 0,
      "motionPrompt": "slow dolly forward, revealing city skyline",
      "transitionType": "seamless"
    },
    {
      "sourceImageUrl": "https://storage.supabase.co/images/kitchen.jpg",
      "roomType": "kitchen",
      "roomLabel": "Gourmet Kitchen",
      "sequenceOrder": 1,
      "motionPrompt": "pan across marble countertops",
      "transitionType": "seamless"
    }
  ]
}

Example Response

{
  "id": "vp_abc123def456",
  "workspaceId": "ws_xyz789",
  "userId": "user_123",
  "name": "Luxury Penthouse Tour",
  "description": "Downtown property showcase",
  "aspectRatio": "16:9",
  "musicTrackId": "track_modern_upbeat",
  "musicVolume": 60,
  "generateNativeAudio": true,
  "status": "draft",
  "clipCount": 2,
  "completedClipCount": 0,
  "estimatedCost": 70,
  "finalVideoUrl": null,
  "thumbnailUrl": null,
  "durationSeconds": null,
  "triggerRunId": null,
  "triggerAccessToken": null,
  "errorMessage": null,
  "createdAt": "2024-02-28T10:30:00Z",
  "updatedAt": "2024-02-28T10:30:00Z"
}

Next Steps

After creating the video project:
  1. Trigger generation - Call the video generation endpoint to start processing
  2. Track progress - Use the triggerRunId to monitor real-time progress
  3. Download video - Once status is completed, download from finalVideoUrl

Compile Video

Start video generation

Check Status

Monitor progress

Video Generation Pipeline

Once generation starts, the system:
  1. Generates clips - Creates 5-second AI videos in parallel (up to 3 at a time)
  2. Creates transitions - Generates seamless transitions between clips
  3. Compiles video - Uses FFmpeg to merge clips with audio
  4. Uploads final video - Stores in Supabase Storage
Video generation takes approximately 2-5 minutes per clip. A 10-clip video takes about 20-30 minutes total.

Cost Calculation

// From source: lib/video/video-constants.ts
const CLIP_COST = 0.35; // USD per 5-second clip
const estimatedCost = clips.length × CLIP_COST × 100; // in cents
Example: 8 clips = 8 × 0.35=0.35 = 2.80 (280 cents)

Database Schema

// From source: lib/db/schema.ts:247-302
export const videoProject = pgTable("video_project", {
  id: text("id").primaryKey(),
  workspaceId: text("workspace_id").notNull(),
  userId: text("user_id").notNull(),
  name: text("name").notNull(),
  description: text("description"),
  aspectRatio: text("aspect_ratio").notNull().default("16:9"),
  musicTrackId: text("music_track_id"),
  musicVolume: integer("music_volume").notNull().default(50),
  generateNativeAudio: boolean("generate_native_audio").notNull().default(true),
  status: text("status").notNull().default("draft"),
  clipCount: integer("clip_count").notNull().default(0),
  estimatedCost: integer("estimated_cost").notNull().default(0),
  triggerRunId: text("trigger_run_id"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

Build docs developers (and LLMs) love