Skip to main content

Overview

The Video Studio API enables you to convert static avatar images into dynamic video clips with natural motion, facial animations, and optional audio synchronization. Perfect for creating engaging content, animated presentations, and character-driven media.

Base URL

https://api.percify.io/v1

Core Endpoints

MethodEndpointDescription
POST/videos/from-imageGenerate video from avatar image
GET/videos/{videoId}Get video generation status
GET/videosList your videos
POST/videos/{videoId}/add-audioAdd audio track with lip-sync
PATCH/videos/{videoId}Update video metadata
DELETE/videos/{videoId}Delete video

Video Object

{
  "id": "video_xyz789",
  "userId": "user_abc123",
  "avatarId": "avatar_def456",
  "status": "completed",
  "videoUrl": "https://cdn.percify.io/videos/video_xyz789.mp4",
  "thumbnailUrl": "https://cdn.percify.io/videos/video_xyz789_thumb.jpg",
  "durationSeconds": 8,
  "resolution": "720p",
  "fps": 30,
  "fileSize": 3456789,
  "format": "mp4",
  "studioTier": "basic",
  "motionStyle": "moderate",
  "creditCost": 48,
  "hasAudio": false,
  "audioId": null,
  "metadata": {
    "processingTime": 45.2,
    "renderEngine": "video-studio-v3"
  },
  "createdAt": "2025-11-25T06:15:00Z",
  "completedAt": "2025-11-25T06:15:45Z"
}

Pricing

Basic Video Studio

  • Base: 30 credits (includes first 5 seconds)
  • Additional: +6 credits per second after 5s
  • Quality: 720p, 30fps
  • Max Duration: 10 seconds

Reality Lab

  • Base: 20 credits (includes first 5 seconds)
  • Additional: +4 credits per second after 5s
  • Quality: 1080p, 30/60fps
  • Max Duration: 30 seconds

Quick Start

const response = await fetch('https://api.percify.io/v1/videos/from-image', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PERCIFY_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    imageId: 'avatar_abc123',
    durationSeconds: 5,
    studioTier: 'basic',
    motionStyle: 'moderate'
  })
});

const video = await response.json();
console.log(`Video ID: ${video.id}, Status: ${video.status}`);

Processing Times

DurationTierTypical Processing
3-5sBasic20-35 seconds
6-10sBasic40-75 seconds
3-5sReality Lab35-60 seconds
10-15sReality Lab90-150 seconds
15-30sReality Lab3-5 minutes

Motion Styles

StyleDescriptionBest For
subtleGentle breathing, soft blinksProfessional portraits, calm scenes
moderateNatural head movements, expressionsConversations, introductions
dynamicFull range motion, dramatic expressionsAction content, music videos

Video Formats

  • MP4 (H.264)
  • WebM (VP9)
  • MOV (ProRes)
Best compatibility - Recommended for most uses
  • Codec: H.264
  • Container: MP4
  • Compatibility: All browsers, mobile devices
  • File size: Medium

Error Responses

{
  "error": {
    "code": "insufficient_credits",
    "message": "Not enough credits for 8-second video. Required: 48, Available: 30",
    "details": {
      "required": 48,
      "available": 30,
      "calculation": {
        "base": 30,
        "additional": 18,
        "total": 48
      }
    }
  }
}
Common error codes:
  • invalid_image - Avatar image not found or inaccessible
  • invalid_duration - Duration out of allowed range
  • insufficient_credits - Not enough credits
  • processing_failed - Video generation failed
  • avatar_not_completed - Source avatar still processing

Polling for Completion

async function waitForVideo(videoId) {
  const maxAttempts = 120; // 10 minutes max
  const pollInterval = 5000; // 5 seconds
  
  for (let i = 0; i < maxAttempts; i++) {
    const response = await fetch(
      `https://api.percify.io/v1/videos/${videoId}`,
      {
        headers: {
          'Authorization': `Bearer ${process.env.PERCIFY_API_KEY}`
        }
      }
    );
    
    const video = await response.json();
    
    if (video.status === 'completed') {
      return video;
    } else if (video.status === 'failed') {
      throw new Error(`Video generation failed: ${video.error}`);
    }
    
    await new Promise(resolve => setTimeout(resolve, pollInterval));
  }
  
  throw new Error('Video generation timed out');
}

Adding Audio with Lip-Sync

// Generate video
const video = await client.videos.fromImage({
  imageId: 'avatar_abc123',
  durationSeconds: 8
});

// Generate audio
const audio = await client.audio.generate({
  text: 'Welcome to Percify! Create amazing AI content.',
  voiceId: 'voice_default'
});

// Add audio with automatic lip-sync
const syncedVideo = await client.videos.addAudio({
  videoId: video.id,
  audioId: audio.id,
  enableLipSync: true
});

console.log(`Video with audio: ${syncedVideo.videoUrl}`);

Webhooks

Subscribe to video completion events:
{
  "event": "video.completed",
  "data": {
    "videoId": "video_xyz789",
    "status": "completed",
    "videoUrl": "https://cdn.percify.io/videos/video_xyz789.mp4",
    "durationSeconds": 8,
    "creditCost": 48
  },
  "timestamp": "2025-11-25T06:15:45Z"
}
Available events:
  • video.processing - Video generation started
  • video.completed - Video ready for download
  • video.failed - Generation failed

Best Practices

  • Keep videos under 5 seconds to avoid per-second charges
  • Use Basic tier for testing, Reality Lab for production
  • Batch similar videos for workflow efficiency
  • Reuse successful configurations
  • Use high-resolution avatars (1024x1024+)
  • Ensure clean, well-lit images
  • Center subject in frame
  • Avoid heavily cropped faces
  • Generate during off-peak hours for faster processing
  • Use webhooks instead of polling for long videos
  • Download and cache completed videos
  • Compress for web delivery if needed

Rate Limits

TierConcurrent GenerationsDaily Limit
Free110 videos
Pro3100 videos
Enterprise10Unlimited

Next Steps