Skip to content

Video Generation

Generate high-quality AI videos from text prompts or source images. FOTOhub provides access to 7 video models from 6 leading providers, supporting both text-to-video and image-to-video workflows. Generate clips from 5 to 60 seconds in length, with configurable aspect ratios and resolutions up to 4K.

Models7 models from 6 providers
Duration5-60 seconds, configurable
Resolution720p, 1080p, 4K
ModesText-to-video, Image-to-video

Endpoint

POST /v1/ai/generate/video

Authentication: Bearer token (API key)
Billing: 8-15 credits per 5-second clip (scales with duration)

Request Parameters

ParameterTypeRequiredDefaultDescription
promptstringYesDetailed description of the video to generate. Include subject, action, style, camera movement, and lighting for best results.
modelstringNo"veo-2"Video generation model to use. Options: "veo-2", "veo-3", "wan", "kling", "hailuo", "seedance", "sora-2".
durationintegerNo5Video duration in seconds. Accepted values: 5, 10, 15, 30, 60. Longer durations consume proportionally more credits.
aspect_ratiostringNo"16:9"Output aspect ratio. Options: "16:9" (landscape), "9:16" (portrait/vertical), "1:1" (square).
image_urlstringNoURL of a source image for image-to-video generation. When provided, the video will animate from this starting frame. Must be a publicly accessible URL or a FOTOhub storage URL.
resolutionstringNo"1080p"Output video resolution. Options: "720p" (1280x720), "1080p" (1920x1080), "4k" (3840x2160). Higher resolutions may increase generation time.

Response Format

Completed Response (200)

json
{
  "model": "veo-2",
  "credits_used": 10,
  "billing": {
    "method": "credits",
    "credits_used": 10,
    "pln_charged": 3.75
  },
  "video_url": "https://s1.fotohub.app/storage/v1/object/public/generations/videos/vj_abc123.mp4",
  "job_id": "vj_abc123",
  "status": "completed",
  "duration": 5
}

Processing Response (202)

json
{
  "job_id": "vj_abc123def456",
  "status": "processing",
  "model": "veo-3",
  "estimated_seconds": 120,
  "poll_url": "https://apis.fotohub.app/v1/ai/jobs/vj_abc123def456",
  "webhook_supported": true
}

Asynchronous Processing

Video generation can take 30 seconds to several minutes depending on the model and duration. When the video is still processing, the response will include "status": "processing" and a job_id. Use this ID to poll for completion or configure a webhook to receive notifications.

Model Pricing

Base price per 5-second clip:

ModelIDCredits (5s)Price (PLN)Provider
Wan Videowan80.45Alibaba
Hailuo (MiniMax)hailuo80.525MiniMax
Kling AIkling100.60Kuaishou
Seedanceseedance100.675ByteDance
Google Veo 2veo-2100.75Google
OpenAI Sora 2sora-2120.90OpenAI
Google Veo 3veo-3151.20Google
Grok Imagine Videogrok-imagine-videoper-second$0.05-0.07/sxAI
Grok Imagine Video 1.5grok-imagine-video-1.5per-second$0.08-0.25/sxAI

xAI Grok Video — Per-Second Pricing

Grok Video models use per-second billing (not credits). Cost depends on resolution:

Model480p720p1080p
grok-imagine-video$0.05/s$0.07/s
grok-imagine-video-1.5$0.08/s$0.14/s$0.25/s

Grok Video Capabilities

Featuregrok-imagine-videogrok-imagine-video-1.5
Text-to-Video (T2V)Yes
Image-to-Video (I2V)YesYes
Video EditingYesYes
Video ExtensionYesYes
Reference-to-VideoYes
Virtual Try-On (Video)Yes
Lip Sync (UGC)Yes
Max Resolution720p1080p

Recommended Model

Veo 2 offers the best balance of quality, speed, and cost for most use cases. Use Veo 3 for maximum quality when budget allows, or Wan for budget-conscious batch processing. Grok Video excels at advanced modes like virtual try-on, lip sync UGC, and video editing.

Credit Scaling by Duration

Credits scale linearly with video duration. The base credit cost shown above is for a 5-second clip. Longer durations multiply accordingly:

DurationMultiplierExample (Veo 2)
5 seconds1x10 credits (0.75 PLN)
10 seconds2x20 credits (1.50 PLN)
15 seconds3x30 credits (2.25 PLN)
30 seconds5x50 credits (3.75 PLN)
60 seconds10x100 credits (7.50 PLN)

Formula

total_credits = base_credits x (duration / 5)

For example, a 30-second Kling video costs: 10 x (30 / 5) = 60 credits

Code Examples

Text-to-Video

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "A golden retriever running through a sunlit meadow, "
                  "cinematic slow motion, shallow depth of field, "
                  "warm afternoon light, shot on 35mm film",
        "model": "veo-2",
        "duration": 5,
        "aspect_ratio": "16:9",
        "resolution": "1080p"
    }
)

result = response.json()
print(f"Video URL: {result['video_url']}")
print(f"Credits used: {result['credits_used']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/video",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "A golden retriever running through a sunlit meadow, " +
              "cinematic slow motion, shallow depth of field, " +
              "warm afternoon light, shot on 35mm film",
      model: "veo-2",
      duration: 5,
      aspect_ratio: "16:9",
      resolution: "1080p",
    }),
  }
);

const result = await response.json();
console.log("Video URL:", result.video_url);
console.log("Credits used:", result.credits_used);
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A golden retriever running through a sunlit meadow, cinematic slow motion, shallow depth of field, warm afternoon light, shot on 35mm film",
    "model": "veo-2",
    "duration": 5,
    "aspect_ratio": "16:9",
    "resolution": "1080p"
  }'

Image-to-Video

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "The subject slowly turns their head and smiles, "
                  "gentle breeze moves their hair, soft natural lighting",
        "model": "kling",
        "duration": 5,
        "aspect_ratio": "9:16",
        "image_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/portrait.jpg"
    }
)

result = response.json()
if result["status"] == "processing":
    print(f"Job queued: {result['job_id']}")
    print("Poll GET /v1/ai/jobs/{job_id} for completion")
else:
    print(f"Video ready: {result['video_url']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/video",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "The subject slowly turns their head and smiles, " +
              "gentle breeze moves their hair, soft natural lighting",
      model: "kling",
      duration: 5,
      aspect_ratio: "9:16",
      image_url: "https://s1.fotohub.app/storage/v1/object/public/uploads/portrait.jpg",
    }),
  }
);

const result = await response.json();
if (result.status === "processing") {
  console.log(`Job queued: ${result.job_id}`);
  console.log("Poll GET /v1/ai/jobs/{job_id} for completion");
} else {
  console.log(`Video ready: ${result.video_url}`);
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "The subject slowly turns their head and smiles, gentle breeze moves their hair, soft natural lighting",
    "model": "kling",
    "duration": 5,
    "aspect_ratio": "9:16",
    "image_url": "https://s1.fotohub.app/storage/v1/object/public/uploads/portrait.jpg"
  }'

High-Resolution (4K)

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Aerial drone shot of a coastal city at sunset, "
                  "golden hour lighting, waves crashing against cliffs, "
                  "smooth camera pan from left to right, hyperrealistic",
        "model": "veo-3",
        "duration": 10,
        "aspect_ratio": "16:9",
        "resolution": "4k"
    }
)

result = response.json()
# 4K generations may take longer; check status
if result["status"] == "processing":
    print(f"Processing job: {result['job_id']}")
    print(f"Estimated wait: 2-5 minutes for 4K")
else:
    print(f"Video URL: {result['video_url']}")
    print(f"Credits used: {result['credits_used']}")
typescript
const response = await fetch(
  "https://apis.fotohub.app/v1/ai/generate/video",
  {
    method: "POST",
    headers: {
      "Authorization": "Bearer fh_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt: "Aerial drone shot of a coastal city at sunset, " +
              "golden hour lighting, waves crashing against cliffs, " +
              "smooth camera pan from left to right, hyperrealistic",
      model: "veo-3",
      duration: 10,
      aspect_ratio: "16:9",
      resolution: "4k",
    }),
  }
);

const result = await response.json();
// 4K generations may take longer; check status
if (result.status === "processing") {
  console.log(`Processing job: ${result.job_id}`);
  console.log("Estimated wait: 2-5 minutes for 4K");
} else {
  console.log(`Video URL: ${result.video_url}`);
  console.log(`Credits used: ${result.credits_used}`);
}
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Aerial drone shot of a coastal city at sunset, golden hour lighting, waves crashing against cliffs, smooth camera pan from left to right, hyperrealistic",
    "model": "veo-3",
    "duration": 10,
    "aspect_ratio": "16:9",
    "resolution": "4k"
  }'

xAI Grok Video — Advanced Modes

Grok Video models support 6 distinct generation modes. Use the mode parameter to select the operation.

Text-to-Video (Promotional Video)

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Cinematic product reveal of a luxury watch, dramatic slow motion, "
                  "lens flare, dark moody background, camera orbiting around product",
        "model": "grok-imagine-video",
        "mode": "t2v",
        "duration": 5,
        "aspect_ratio": "16:9",
        "resolution": "720p"
    }
)

result = response.json()
print(f"Job ID: {result['job_id']}")
# Cost: 5s × $0.07/s (720p) = $0.35
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Cinematic product reveal of a luxury watch, dramatic slow motion, lens flare, dark moody background",
    "model": "grok-imagine-video",
    "mode": "t2v",
    "duration": 5,
    "aspect_ratio": "16:9",
    "resolution": "720p"
  }'

Image-to-Video (Bring Characters to Life)

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Character slowly turns head, blinks, and smiles warmly at camera, "
                  "subtle hair movement from gentle breeze, cinematic depth of field",
        "model": "grok-imagine-video-1.5",
        "mode": "i2v",
        "duration": 5,
        "aspect_ratio": "9:16",
        "resolution": "1080p",
        "image_url": "https://your-storage.com/character-portrait.jpg"
    }
)

result = response.json()
# Cost: 5s × $0.25/s (1080p, v1.5) = $1.25
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Character slowly turns head, blinks, and smiles warmly at camera",
    "model": "grok-imagine-video-1.5",
    "mode": "i2v",
    "duration": 5,
    "aspect_ratio": "9:16",
    "resolution": "1080p",
    "image_url": "https://your-storage.com/character-portrait.jpg"
  }'

Video Editing (Precision Edits)

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Change the background to a futuristic neon cityscape at night, "
                  "keep the subject and their movements exactly the same",
        "model": "grok-imagine-video",
        "mode": "edit",
        "duration": 5,
        "aspect_ratio": "16:9",
        "resolution": "720p",
        "video_url": "https://your-storage.com/original-clip.mp4"
    }
)
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Change the background to a futuristic neon cityscape at night, keep subject movements",
    "model": "grok-imagine-video",
    "mode": "edit",
    "video_url": "https://your-storage.com/original-clip.mp4"
  }'

Video Extension (Continue a Clip)

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Continue the scene naturally, camera keeps moving forward, "
                  "maintain consistent style and lighting",
        "model": "grok-imagine-video-1.5",
        "mode": "extend",
        "duration": 5,
        "resolution": "720p",
        "video_url": "https://your-storage.com/short-clip.mp4"
    }
)
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Continue the scene naturally, camera keeps moving forward, maintain style",
    "model": "grok-imagine-video-1.5",
    "mode": "extend",
    "video_url": "https://your-storage.com/short-clip.mp4"
  }'

Lip Sync UGC (User-Generated Content)

Generate a video of a person speaking text with synchronized lip movements. Only available with grok-imagine-video-1.5.

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Person speaking enthusiastically to camera, natural expressions, "
                  "warm lighting, professional UGC style",
        "model": "grok-imagine-video-1.5",
        "mode": "lip_sync",
        "duration": 10,
        "aspect_ratio": "9:16",
        "resolution": "1080p",
        "image_url": "https://your-storage.com/speaker-photo.jpg",
        "lip_sync_text": "Hey everyone! Check out this amazing new product that just launched. "
                         "It's going to change how you work every day."
    }
)

result = response.json()
# Cost: 10s × $0.25/s (1080p) = $2.50
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Person speaking enthusiastically to camera, natural expressions, UGC style",
    "model": "grok-imagine-video-1.5",
    "mode": "lip_sync",
    "duration": 10,
    "aspect_ratio": "9:16",
    "resolution": "1080p",
    "image_url": "https://your-storage.com/speaker-photo.jpg",
    "lip_sync_text": "Hey everyone! Check out this amazing new product."
  }'

Lip Sync Notes

  • Only available with grok-imagine-video-1.5
  • Requires image_url (face photo as starting frame)
  • lip_sync_text — the text the person will appear to speak
  • Best with front-facing, well-lit face photos
  • Max text length: ~500 characters per 10s clip

Virtual Try-On Video (Reference-to-Video)

Generate a video showing a person wearing/using a product from reference images. Only available with grok-imagine-video.

python
import requests

response = requests.post(
    "https://apis.fotohub.app/v1/ai/generate/video",
    headers={
        "Authorization": "Bearer fh_live_your_api_key",
        "Content-Type": "application/json"
    },
    json={
        "prompt": "Model walks confidently in the outfit, turns to show details, "
                  "runway-style lighting, slow motion fabric movement",
        "model": "grok-imagine-video",
        "mode": "reference",
        "duration": 5,
        "aspect_ratio": "9:16",
        "resolution": "720p",
        "image_url": "https://your-storage.com/model-photo.jpg",
        "reference_image_urls": [
            "https://your-storage.com/dress-front.jpg",
            "https://your-storage.com/dress-back.jpg"
        ]
    }
)

result = response.json()
# Cost: 5s × $0.07/s (720p) = $0.35
bash
curl -X POST "https://apis.fotohub.app/v1/ai/generate/video" \
  -H "Authorization: Bearer fh_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Model walks confidently in the outfit, turns to show details, runway lighting",
    "model": "grok-imagine-video",
    "mode": "reference",
    "aspect_ratio": "9:16",
    "resolution": "720p",
    "image_url": "https://your-storage.com/model-photo.jpg",
    "reference_image_urls": [
      "https://your-storage.com/dress-front.jpg",
      "https://your-storage.com/dress-back.jpg"
    ]
  }'

Grok Video Mode Selection Guide

Use CaseModeModel
Promotional ad from textt2vgrok-imagine-video
Animate product/character photoi2veither
Restyle or change scene in clipediteither
Continue existing videoextendeither
Person speaking your textlip_syncgrok-imagine-video-1.5
Virtual try-on / style guidereferencegrok-imagine-video

Asynchronous Jobs

Video generation is computationally intensive and may take 30 seconds to several minutes depending on model, duration, and resolution. When a generation is still in progress, the API returns a job_id with status "processing". You can either poll for completion or use webhooks.

Poll Endpoint

GET /v1/ai/jobs/{job_id}

Poll for Completion

python
import requests
import time

job_id = "vj_abc123def456"

while True:
    status_response = requests.get(
        f"https://apis.fotohub.app/v1/ai/jobs/{job_id}",
        headers={"Authorization": "Bearer fh_live_your_api_key"}
    )
    job = status_response.json()

    if job["status"] == "completed":
        print(f"Video ready: {job['video_url']}")
        break
    elif job["status"] == "failed":
        print(f"Generation failed: {job['error']}")
        break
    else:
        print(f"Still processing... ({job.get('progress', 0)}%)")
        time.sleep(5)
typescript
const jobId = "vj_abc123def456";

async function pollJob(id: string): Promise<string> {
  while (true) {
    const res = await fetch(
      `https://apis.fotohub.app/v1/ai/jobs/${id}`,
      { headers: { "Authorization": "Bearer fh_live_your_api_key" } }
    );
    const job = await res.json();

    if (job.status === "completed") {
      return job.video_url;
    } else if (job.status === "failed") {
      throw new Error(job.error);
    }

    console.log(`Processing... ${job.progress ?? 0}%`);
    await new Promise((r) => setTimeout(r, 5000));
  }
}

const videoUrl = await pollJob(jobId);
console.log("Video ready:", videoUrl);
bash
# Poll for job completion
curl -X GET "https://apis.fotohub.app/v1/ai/jobs/vj_abc123def456" \
  -H "Authorization: Bearer fh_live_your_api_key"

# Response when completed:
# {
#   "job_id": "vj_abc123def456",
#   "status": "completed",
#   "video_url": "https://s1.fotohub.app/storage/v1/object/public/...",
#   "duration": 10,
#   "credits_used": 30
# }

Job Status Values

StatusDescription
processingVideo is being generated. Poll again in 5 seconds.
completedVideo is ready. The video_url field contains the download link.
failedGeneration failed. The error field contains the reason.

Webhook Notifications

Instead of polling, configure a webhook URL in your account settings. FOTOhub will send a POST request to your endpoint when the video is ready. The webhook payload includes the full job response with the video_url. Subscribe to the generation.completed event.

Error Responses

StatusCodeDescription
400bad_requestInvalid parameters. Check that duration is one of the accepted values (5, 10, 15, 30, 60), model is a valid model ID, and aspect_ratio is a supported format.
401unauthorizedMissing or invalid API key. Ensure your Authorization header contains a valid Bearer fh_live_... token.
402insufficient_creditsYour account does not have enough credits for this generation. Video generation requires 8-100+ credits depending on model and duration. Top up your account or reduce the duration/resolution.
429rate_limit_exceededVideo generation is limited to 5 requests per minute per API key. Wait for current generations to complete before submitting new ones. The response includes a Retry-After header indicating when you can retry.
504gateway_timeoutThe generation exceeded the maximum wait time. This typically occurs with long durations (30-60s) or 4K resolution. For these cases, the API automatically returns a job_id for async polling rather than timing out. If you receive this error, retry with a shorter duration or lower resolution.

Error Response Example

json
{
  "error": {
    "code": "insufficient_credits",
    "message": "Your account has 5 credits remaining but this generation requires 30 credits.",
    "required_credits": 30,
    "available_credits": 5
  }
}

Rate Limits

Video generation is rate-limited to 5 requests per minute per API key. This limit applies across all video models. For higher throughput, contact sales for enterprise tier access with dedicated GPU capacity.

Tips and Best Practices

Prompt Engineering for Video

For best results, include these elements in your prompt:

  • Subject - What appears in the video (person, animal, landscape)
  • Action - What is happening (running, flying, dissolving)
  • Style - Visual aesthetic (cinematic, anime, documentary)
  • Camera - Movement and framing (dolly zoom, aerial pan, close-up)
  • Lighting - Time of day and mood (golden hour, neon-lit, overcast)

Image-to-Video Best Practices

When using image_url for image-to-video generation:

  • Use high-resolution source images (at least 1024x1024)
  • Ensure the image is publicly accessible or hosted on FOTOhub storage
  • Keep the prompt consistent with what is visible in the source image
  • Kling and Hailuo models tend to produce the most natural animations from still images

Credit Consumption

Video generation is the most credit-intensive operation in the API. A single 60-second Veo 3 clip costs 150 credits. Always check billing.credits_used in the response to track consumption. Consider starting with short 5-second test clips before generating longer videos.

Output Format

All generated videos are delivered in MP4 format (H.264 codec) with AAC audio track (silent). Videos are stored for 30 days and accessible via the returned video_url. Download and save videos to your own storage for permanent retention.