HiAPI
Blog

Tutorial

How to Use LTX 2.5 Fast Image-to-Video API: Animate Your Stills

First frame (plus optional last frame) into 2–20 second video: examples and parameters.

Oct 23, 2026 4
How to Use LTX 2.5 Fast Image-to-Video API: Animate Your Stills
Per s (720p)
$0.043
Inputs
1–2 images
Duration
2–20 s

TL;DR

  • LTX 2.5 Fast Image to Video (ltx-2.5-fast/image-to-video) animates stills: upload one first frame (optionally a last frame) and get a 2–20 second 720p / 1080p video with native audio. Try it on the model page; new accounts get 200 free credits.
  • Pricing matches text-to-video: $0.043/s at 720p and $0.086/s at 1080p, billed by duration; the audio switch never changes the price.
  • Everything runs on HiAPI /v1/tasks: pass 1–2 images in image_urls (first frame / first + last), then take the video from output.

What it does

  • First frame comes alive: one still plus a motion line — the subject stays put while motion, camera, and sound move in.
  • First + last frame: pass two images and the model fills the transition between them (a day cabin becomes a starry-night cabin).
  • Aspect follows your setting: output is 16:9 or 9:16 via aspect_ratio; match the first frame to avoid crops or bars.
  • Sibling text-to-video: generate from scratch with the text-to-video guide — identical pricing.

Here's a real clip (still lighthouse photo → 6-second sounding shot):

Waves crash against the rocks below the lighthouse, seagulls glide across the golden sky, the camera slowly pushes in, sound of surf and gulls

→

ltx-2.5-fast/image-to-video, 720p, 6 s, 16:9, 1280×720, audio, $0.258. Watch the full clip →

Try this prompt →

Passing frames

Input image_urls Result
One image ["first-frame"] Motion starts from that image; the subject holds
Two images ["first-frame", "last-frame"] The model fills the transition from first to last

Images are public JPG / PNG / WebP URLs; keep both frames at the same aspect and set aspect_ratio to match the first.

Two ways to start

Browser, 3 steps: open the model page → upload the first frame, write the motion line → generate.

API, 3 steps: POST /v1/tasks to submit → take the taskId → poll to success.

curl: your first clip (single frame)

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: your-unique-key-001" \
  -d '{
  "model": "ltx-2.5-fast/image-to-video",
  "input": {
    "prompt": "Waves crash against the rocks below the lighthouse, seagulls glide across the golden sky, the camera slowly pushes in, sound of surf and gulls",
    "image_urls": ["https://static.hiapi.ai/gallery/2026/10/0ca26560398eae72.jpg"],
    "resolution": "720p",
    "duration": 6,
    "aspect_ratio": "16:9"
  }
}'

First + last frame (day cabin → starry night) changes only image_urls:

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "ltx-2.5-fast/image-to-video",
  "input": {
    "prompt": "Time passes from bright winter day to starry night, the sky darkens, the cabin windows light up warmly and smoke rises from the chimney, an aurora appears, fixed camera",
    "image_urls": [
      "https://static.hiapi.ai/gallery/2026/10/7756ea1a228b0b88.jpg",
      "https://static.hiapi.ai/gallery/2026/10/16e267619aa1b003.jpg"
    ],
    "resolution": "720p",
    "duration": 5,
    "aspect_ratio": "16:9"
  }
}'

Python: submit, poll, download

import time, uuid, requests

BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
}

payload = {
    "model": "ltx-2.5-fast/image-to-video",
    "input": {
        "prompt": "Waves crash against the rocks below the lighthouse, seagulls glide across the golden sky, the camera slowly pushes in, sound of surf and gulls",
        "image_urls": ["https://example.com/your-first-frame.jpg"],
        "resolution": "720p",
        "duration": 6,
        "aspect_ratio": "16:9",
    },
}

resp = requests.post(
    BASE,
    headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
    json=payload,
    timeout=30,
)
resp.raise_for_status()
task_id = resp.json()["taskId"]

while True:
    task = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30).json()
    print(task["status"])
    if task["status"] in ("success", "fail"):
        break
    time.sleep(5)

if task["status"] == "success":
    video = next(o for o in task["output"] if o.get("type") == "video")
    mp4 = requests.get(video["url"], timeout=120)   # temporary URL — save promptly
    with open("output.mp4", "wb") as f:
        f.write(mp4.content)
    print("saved output.mp4")

Parameters

Field Required Values Notes
image_urls yes 1–2 public URLs First frame; add a second as the last frame (JPG/PNG/WebP)
prompt yes 1–5,000 chars Motion, camera, and sound; don't re-describe what's already in the frame
resolution no 720p / 1080p, default 720p 1080p is about twice the per-second rate
duration no 2/3/4/5/6/8/10/12/14/16/18/20, default 6 Enumerated values
aspect_ratio no 16:9 / 9:16, default 16:9 Match the first frame to avoid crops
generate_audio no default true Native audio; turn off for clean footage at the same price

Any field outside the table returns a 400.

Errors you'll actually hit

Status Meaning What to do
400 INVALID_REQUEST Malformed body (missing image_urls or prompt, 3 images, non-enum duration) Fix the payload against the table
402 INSUFFICIENT_QUOTA Out of credits (no charge) Top up and retry
429 RATE_LIMITED Rate limited Slow your submissions
409 / 422 IDEMPOTENCY_KEY_* Same idempotency key resubmitted Generate a fresh key

Terminal failures use CONTENT_POLICY_VIOLATION, TASK_FAILED, and TASK_TIMEOUT; failed tasks refund in full.

Before you ship

  • Callbacks: video tasks run long — pass "callback": {"url": "https://..."} and skip the polling.
  • Persist outputs: the video URL in output is temporary; download immediately.
  • Match frame aspects: widely different first/last aspects warp the transition; set aspect_ratio to the first frame.
  • Scoring in post: pass generate_audio: false for clean footage at the same price.

FAQ

  • Yes, two images max: one first frame, or first plus last; the third returns a 400.
  • Yes, the output aspect follows aspect_ratio, not the image — set it to match the first frame.
  • Yes, pricing matches text-to-video: $0.043/s at 720p, $0.258 for a 6-second clip.
  • Yes, first+last suits time lapses: day to night, empty to furnished — two frames and one line.
  • Yes, product shots are its strength: use a product hero image as the first frame, then describe the camera move (orbit, push in) and accent elements — one clip gives you a showcase video.
  • Yes, pair vertical photos with 9:16: output is 720×1280, ready for short-video feeds; keep 16:9 for landscape photos.

Next: take one of your product shots and bring it to life; four scenes are in the image-to-video prompt guide.

Related articles

View all articles →

Start building with persistent AI artifacts

Get your API key and call image, video and audio models through one task-based API.

Read the API docs