HiAPI
  • Models
  • Pricing
Search

Search HiAPI models, tools, and resources.

  • Models
  • Pricing
HiAPI

One API, All AI Models

Generate images, video, and audio with leading models through one production-ready API.

Get a free API key

AI Image API

  • All image models
  • GPT Image 2
  • Nano Banana 2
  • Seedream 5.0 Pro
  • Qwen Image 2.0 Pro
  • FLUX 1.1 Pro

AI Video API

  • All video models
  • Seedance 2.5
  • FLUX.3 Video
  • Seedance 2.0
  • Veo 3.1
  • Kling 3.0

AI Audio API

  • All audio models
  • MiniMax Music 2.6
  • MiniMax Music 1.5
  • ElevenLabs v3
  • Text to music
  • Text to speech

Product

  • Model marketplace
  • Playground
  • Pricing
  • Image API Cost Calculator
  • Free GPT Image 2 Generator
  • Free Nano Banana Image Generator
  • Outfit Preview
  • Product Photo Lab

Developers

  • Documentation
  • API Reference
  • Agent Skills
  • LLM integration index
  • Blog

Company

  • About
  • Contact support
  • Terms of Service
  • Privacy Policy

© 2026 hiapi. All rights reserved.

Open source on GitHubPython SDK on PyPI
  • What you need before you start
  • Smallest working request (curl)
  • Python: poll until success
  • Production: use a callback instead of polling
  • Error messages you will hit
  • Tuning the output
  • FAQ
TutorialJun 27, 2026

Happyhorse Image to Video API: Working curl and Python Examples (hiapi)

hiapivideotutorialhappyhorse

Latest models

Explore models

Contents
  • What you need before you start
  • Smallest working request (curl)
  • Python: poll until success
  • Production: use a callback instead of polling
  • Error messages you will hit
  • Tuning the output
  • FAQ

Generate it with HiAPI

Choose a model, enter your prompt, and see the result.

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

You want to turn one still image into a short, coherent video clip from your own code. The happyhorse-1.1/image-to-video model on hiapi does exactly that: hand it one image URL plus an optional motion prompt, and it returns a 720p or 1080p MP4 in seconds. This recipe is the shortest working path — real request bodies, real error messages, both curl and Python — so you can ship today instead of fighting field names.

What you need before you start

  • A hiapi API key. Grab one from the hiapi dashboard — it looks like sk-... and goes in the Authorization: Bearer ... header.
  • An accessible image URL (public HTTPS). Local files do not work; the model fetches the URL itself.
  • A motion intent in words (optional but recommended). The clearer the verb, the better the motion.

Model pricing per video second is listed on the hiapi pricing page; the rest of the catalogue lives at hiapi models — check both before turning up batch volume.

Smallest working request (curl)

Every video on hiapi goes through the asynchronous /v1/tasks endpoint: you POST a creation request, get back a taskId, then either poll GET /v1/tasks/{taskId} or receive a callback when it finishes.

Create the task:

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/image-to-video",
    "input": {
      "image_urls": ["https://example.com/your-still.jpg"],
      "prompt": "the cat slowly turns its head toward the camera and blinks",
      "resolution": "1080p",
      "duration": 5
    }
  }'

A successful response looks like:

{
  "code": 200,
  "data": { "taskId": "tk-hiapi-01KW3D..." },
  "message": "success"
}

Now poll for the result (every 5 seconds is plenty — most clips finish inside two minutes):

curl "https://api.hiapi.ai/v1/tasks/tk-hiapi-01KW3D..." \
  -H "Authorization: Bearer sk-your-key"

While it is running you get "status": "handling". When it finishes you get:

{
  "code": 200,
  "data": {
    "status": "success",
    "model": "happyhorse-1.1/image-to-video",
    "output": [
      {
        "type": "video",
        "url": "https://temp.hiapi.ai/.../01KW....mp4",
        "expireAt": 1783131245
      }
    ],
    "taskId": "tk-hiapi-01KW3D..."
  }
}

That url is what you download — and you should download it immediately, because expireAt is a Unix timestamp marking when temp storage drops it.

Python: poll until success

This is a complete, runnable script — drop in your key and image URL.

import os
import time
import requests

API = "https://api.hiapi.ai/v1/tasks"
TOKEN = os.environ["HIAPI_KEY"]  # sk-...

def create_video(image_url: str, prompt: str, duration: int = 5,
                 resolution: str = "1080p") -> str:
    """Submit an image-to-video task. Returns the taskId."""
    r = requests.post(
        API,
        headers={"Authorization": f"Bearer {TOKEN}",
                 "Content-Type": "application/json"},
        json={
            "model": "happyhorse-1.1/image-to-video",
            "input": {
                "image_urls": [image_url],          # exactly one URL
                "prompt": prompt,                   # optional
                "resolution": resolution,           # "720p" or "1080p"
                "duration": duration,               # int, 3..15
            },
        },
        timeout=60,
    )
    body = r.json()
    if body.get("code") != 200:
        raise RuntimeError(f"create failed: {body}")
    return body["data"]["taskId"]

def wait_for_video(task_id: str, timeout_s: int = 600,
                   poll_s: int = 5) -> str:
    """Block until the task succeeds, fails, or times out. Returns the MP4 URL."""
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(
            f"{API}/{task_id}",
            headers={"Authorization": f"Bearer {TOKEN}"},
            timeout=30,
        )
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(poll_s)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")

def download(url: str, path: str) -> None:
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        with open(path, "wb") as f:
            for chunk in r.iter_content(1 << 16):
                f.write(chunk)

if __name__ == "__main__":
    task_id = create_video(
        image_url="https://example.com/your-still.jpg",
        prompt="the dancer spins once and ends in a pose",
        duration=5,
        resolution="1080p",
    )
    print("submitted:", task_id)
    mp4_url = wait_for_video(task_id)
    download(mp4_url, "out.mp4")
    print("saved out.mp4")

The whole thing is ~50 lines and it is the entire production-ready surface — no SDK, no background queue, no streaming protocol. Run it with HIAPI_KEY=sk-... python video.py.

Production: use a callback instead of polling

Polling is fine for one-offs and tests. For server workloads you want the platform to call you back when the clip is ready — saves the loop, scales with no extra work, and the request flow returns instantly.

Add a callback object at the root of the request body (not inside input):

curl -X POST "https://api.hiapi.ai/v1/tasks" \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/image-to-video",
    "input": {
      "image_urls": ["https://example.com/still.jpg"],
      "prompt": "slow zoom out from the subject",
      "resolution": "1080p",
      "duration": 6
    },
    "callback": {
      "url": "https://your-app.example.com/webhooks/hiapi",
      "when": "final"
    }
  }'

When the task reaches a terminal state, hiapi POSTs the same task object you would have polled (status, output[].url, error, etc.) to your URL. when: "final" means you only get the success-or-failure callback — no progress noise.

A few rules that save real debugging hours:

  • Make the webhook idempotent. The same taskId may arrive twice (network retries are real). Look up the task in your DB before processing.
  • Re-host the MP4 inside your handler. The URL hiapi gives you points at temporary storage with an expireAt field; stream it into your own bucket on first receipt or you will lose it.
  • Acknowledge fast. Return 2xx quickly, then do heavy work async. Slow webhooks risk retries.
  • Use polling as a fallback. Wrap the taskId in a delayed job that polls 10 minutes later, in case the webhook gets lost. If you keep hitting this, see why hiapi task callbacks may not fire for the common causes.

Error messages you will hit

These are the exact strings the API returns; matching them in your code is more reliable than guessing.

SituationHTTPBody shape
Wrong or revoked key401{"error":{"code":"permission_denied","message":"This API key cannot use the selected model...","type":"hiapi_error"}}
Missing required field400{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: image_urls: missing required field \"image_urls\""}
Bad resolution400... resolution: value must be one of '720p', '1080p'
Duration out of range400... duration: minimum: got 2, want 3 / duration: maximum: got 30, want 15
Wrong image_urls length400... image_urls: maxItems: got 2, want 1 (or minItems: got 0, want 1)
Unknown field at root or in input400... additional properties 'identity_preserving' not allowed
Task itself failed after submission200 (task GET) with data.status == "fail" and data.error.{code,message}

The auth and validation errors mean you should not retry; everything else (5xx from the platform, network timeouts mid-poll, transient task fail with retryable codes) is fair game for a small backoff.

Tuning the output

You have four knobs that actually matter — anything else (seed, aspect_ratio, fps, cfg_scale, negative_prompt) is rejected as an unknown field today. Stay inside this set:

  • image_urls — one HTTPS URL. The aspect ratio and framing of the output follow this image.
  • prompt — a short motion description ("she smiles and tilts her head"). Cinematic and verb-driven prompts beat adjective lists.
  • resolution — "720p" for prototyping and thumbnails, "1080p" for delivery.
  • duration — integer seconds, 3 to 15. Longer clips cost more time and money; pick the shortest that tells the story.

For projects that need a starting and ending frame, see happyhorse-1.1 reference-to-video. For pure text-to-video without a source still, happyhorse-1.1 text-to-video is the sibling recipe. Browse the rest at the hiapi models catalogue or in the recipes section of the blog.

FAQ

Can I pass two images for first-frame + last-frame control? Not on happyhorse-1.1/image-to-video — image_urls is capped at one element (maxItems: 1). Use happyhorse-1.1/reference-to-video if you need that, or build with happyhorse-1.1 reference-to-video.

What MP4 resolution do I actually get back? The output respects the aspect ratio of your input image and the resolution flag you set. "1080p" gives you the higher of the two; "720p" is faster and cheaper for tests.

Why does my key get 401 permission_denied even though it works on other models? Some models are gated per key. Check the model's page on the hiapi dashboard — if happyhorse-1.1/image-to-video is not in your allowlist, generate a new key or contact support with the request_id in the error.

Is there a streaming/SSE response? No. Every video model uses the asynchronous task pattern in this article. Pick polling or callback based on whether you control the server.

Where do I see the actual cost per clip? On the hiapi pricing page. Costs are per video second, so the duration you pass directly drives spend — keep dev/test clips at duration: 3 to save budget.

The output URL stopped working after a day. That is expected — the URL is temp storage and the response includes an expireAt Unix timestamp. Always download the MP4 (or stream it through your own CDN) the moment the task succeeds.

Latest models

View all models
  • GPT Image 2From $0.007/image
  • Nano Banana 2From $0.051/image
  • Seedream 5.0 ProFrom $0.050/image
  • Seedance 2.5From $0.121/s

Explore models

TextImageVideoAudio
Back to blog
GPT Image 2From $0.007/image
Nano Banana 2From $0.051/image
Seedream 5.0 ProFrom $0.050/image
Seedance 2.5From $0.121/s
View all models
TextChat and reasoning
ImageGenerate and edit
VideoText and image to video
AudioSpeech and music
Start generating
View model pricing
View all articles
How to Use the flux-3 API for Text-to-Video, Audio, and Continuation

How to Use the flux-3 API for Text-to-Video, Audio, and Continuation

minimax-music-3 API: curl & Python Guide

minimax-music-3 API: curl & Python Guide

How to use grok-imagine-image-2.0/image-to-image via the hiapi API: curl, Python, and a working request

How to use grok-imagine-image-2.0/image-to-image via the hiapi API: curl, Python, and a working request

How to Use grok-imagine-image-2.0/text-to-image via the hiapi API: curl, Python, and a Working Request

How to Use grok-imagine-image-2.0/text-to-image via the hiapi API: curl, Python, and a Working Request

How to Use the qwen-image-3.0 API: curl, Python, and a Working Request

How to Use the qwen-image-3.0 API: curl, Python, and a Working Request

How to Use qwen-image-3.0-pro via the hiapi API: curl, Python, and a Working Request

How to Use qwen-image-3.0-pro via the hiapi API: curl, Python, and a Working Request

Start generating