Premier AI video generation with models: Wan 2.6, Kling O1, Kling 2.6, Google Veo 3.1, Sora 2 Pro, Pixverse V5.5, Hailuo 2.0, Hailuo 2.3, SeeDance 1.5 Pro, Vidu Q2. One-stop access across text-to-video, image-to-video, first-last-frame, reference-image modes with knowledge base guidance. BEFORE using: READ ima-knowledge-ai skill for workflow design and visual consistency. Use for: video generation, text-to-video, image-to-video, character animation, product demos, social media clips, storytelling, explainer videos, multi-shot production, character consistency via reference images. Requires IMA API key.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Premier AI video generation with models: Wan 2.6, Kling O1, Kling 2.6, Google Veo 3.1, Sora 2 Pro, Pixverse V5.5, Hailuo 2.0, Hailuo 2.3, SeeDance 1.5 Pro, Vidu Q2. One-stop access across text-to-video, image-to-video, first-last-frame, reference-image modes with knowledge base guidance. BEFORE using: READ ima-knowledge-ai skill for workflow design and visual consistency. Use for: video generation, text-to-video, image-to-video, character animation, product demos, social media clips, storytelling, explainer videos, multi-shot production, character consistency via reference images. Requires IMA API key.
IMA Video AI Creation
📋 Before you install
Credentials: This skill requires an IMA API key at runtime (IMA_API_KEY or --api-key). The key is sent to api.imastudio.com (main API) and imapi.liveme.com (image uploads). Obtain keys at https://imastudio.com. Use a scoped or test key if you want to limit exposure.
Local files: The skill reads local image files you provide (for image-to-video); it also writes logs under ~/.openclaw/logs/ima_skills/ and preferences to ~/.openclaw/memory/ima_prefs.json. Do not point it at sensitive paths.
Cross-skill reads: If ima-knowledge-ai is installed, this skill instructs the agent to read that skill's reference files (~/.openclaw/skills/ima-knowledge-ai/references/*) for workflow and visual-consistency guidance. If you do not have or trust that skill, skip those steps and use this skill's built-in defaults and tables.
⚠️ 重要:模型 ID 参考
CRITICAL: When calling the script, you MUST use the exact model_id (second/third column), NOT the friendly model name. Do NOT infer model_id from the friendly name.
Use --list-models --task-type text_to_video (or image_to_video)
Refer to command examples below
Example:
# ❌ WRONG: Inferring from friendly name
--model-id kling-o1
# ✅ CORRECT: Using exact model_id from table
--model-id kling-video-o1
⚠️ MANDATORY PRE-CHECK: Read Knowledge Base First!
If ima-knowledge-ai is not installed: Skip all "Read …" steps below; use only this SKILL's default models and the 📥 User Input Parsing tables for task_type, model_id, and parameters.
BEFORE executing ANY video generation task, you MUST:
CRITICAL: Understand video modes — Read ima-knowledge-ai/references/video-modes.md:
image_to_video = first frame to video (输入图成为第1帧)
reference_image_to_video = reference appearance to video (输入图是视觉参考,不是第1帧)
These are COMPLETELY DIFFERENT concepts!
Wrong mode choice = wrong result
Check for visual consistency needs — Read ima-knowledge-ai/references/visual-consistency.md if:
User mentions: "系列"、"分镜"、"同一个"、"角色"、"续"、"多个镜头"
Task involves: multi-shot videos, character continuity, scene consistency
Second+ request about same subject (e.g., "旺财在游泳" after "生成旺财照片")
Need parameter guidance (duration, resolution, reference strength)
Why this matters:
AI video generation defaults to 独立生成 (independent generation) each time
Without reference images, "same character/scene" will look completely different
Text-to-video CANNOT maintain visual consistency — must use image-based modes
Example failure case:
User: "生成一只小狗,叫旺财"
→ You: generate dog image A
User: "生成旺财在游泳的视频"
→ ❌ Wrong: text_to_video "狗在游泳" (new dog, different from A)
→ ✅ Right: read visual-consistency.md + video-modes.md →
use image_to_video with image A as first frame
How to check:
# Step 1: Read knowledge base
read("~/.openclaw/skills/ima-knowledge-ai/references/video-modes.md")
read("~/.openclaw/skills/ima-knowledge-ai/references/visual-consistency.md")
# Step 2: Identify if reference image neededif"same subject"or"series"or"character continuity":
# Use image-based mode with previous result as reference
reference_image = previous_generation_result
# Choose mode based on requirementif"reference becomes first frame":
use_image_to_video(prompt, reference_image)
else:
use_reference_image_to_video(prompt, reference_image, reference_strength=0.8)
else:
# OK to use text-to-video
use_text_to_video(prompt)
No exceptions — if you skip this check and generate visually inconsistent results, that's a bug.
📥 User Input Parsing (Model & Parameter Recognition)
Purpose: So that any agent (Claude or other models) parses user intent consistently, follow these rules when deriving task_type, model_id, and parameters from natural language. Do not guess — normalize first, then map.
1. User phrasing → task_type
User intent / phrasing
task_type
Notes
Only text, no image
text_to_video
"生成一段…视频" / "text to video"
One image as first frame (图成为第1帧)
image_to_video
"把这张图动起来" / "用这张图做视频" / "图生视频"
One image as reference (视觉参考,非第1帧)
reference_image_to_video
"参考这张图生成" / "像这张风格/角色"
Two images (start + end)
first_last_frame_to_video
"首帧+尾帧" / "从A过渡到B"
When in doubt: "把图动起来" / "图动" → image_to_video; "参考这张图" / "按这张风格" → reference_image_to_video.
2. Model name / alias → model_id (normalize then lookup)
Normalize user wording (case-insensitive, ignore spaces), then map to model_id:
User says (examples)
For t2v → model_id
For i2v → model_id
万 / Wan / 万2.6 / wan2.6
wan2.6-t2v
wan2.6-i2v
可灵 / Kling / Kling O1 / 可灵O1
kling-video-o1
kling-video-o1
Kling 2.6 / 可灵2.6
kling-v2-6
kling-v2-6
海螺 / Hailuo / 海螺2.3
MiniMax-Hailuo-2.3
MiniMax-Hailuo-2.3
Hailuo 2.0 / 海螺2.0
MiniMax-Hailuo-02
MiniMax-Hailuo-02
Vidu / Vidu Q2
viduq2
(i2v: viduq2-pro for "Vidu Q2 Pro")
Veo / Google Veo / Veo 3.1
veo-3.1-generate-preview
veo-3.1-generate-preview
Sora / Sora 2 Pro
sora-2-pro
sora-2-pro
Pixverse / Pixverse V5.5
pixverse
pixverse
最便宜 / 最省钱 / cheapest / budget
viduq2 (5 pts)
wan2.6-i2v or per product list
最好 / 最高质量 / best / premium
Prefer Kling O1 / Veo 3.1
Same
If the user names a model not in the table, match by Name in the "Supported Models" tables below and use its model_id for the chosen task_type.
3. User phrasing → duration / resolution / aspect_ratio
User says (examples)
Parameter
Normalized value
Fallback if unsupported
5秒 / 5s / 5 second
duration
5
—
10秒 / 10s
duration
10
—
15秒 / 15s
duration
15
—
1分钟 / 1 min
duration
—
Use 15 if model max is 15s; tell user "当前最长15秒"
横屏 / 16:9 / 横向
aspect_ratio
16:9
—
竖屏 / 9:16 / 竖向
aspect_ratio
9:16
—
1:1 / 方形
aspect_ratio
1:1
—
720P / 720p
resolution
720P
—
1080P / 1080p / 高清
resolution
1080P
—
4K / 4k
resolution
4K
Only if model supports (e.g. Veo 3.1)
If the user does not specify duration/resolution/aspect_ratio, use form_config defaults from the product list for the chosen model (e.g. 5s, 720P or 1080P, 16:9).
⚙️ How This Skill Works
For transparency: This skill uses a bundled Python script (scripts/ima_video_create.py) to call the IMA Open API. The script:
Sends your prompt to IMA's servers (two domains, see below)
Uses --user-idonly locally as a key for storing your model preferences
Returns a video URL when generation is complete
🌐 Network Endpoints Used
This skill connects to two domains owned by IMA Studio for complete functionality:
Domain
Purpose
What's Sent
Authentication
api.imastudio.com
Main API (task creation, status polling)
Prompts, model params, task IDs
Bearer token (IMA API key)
imapi.liveme.com
Image upload service (OSS token generation)
Image files (for i2v/ref tasks), IMA API key
IMA API key + APP_KEY signature
Why two domains?
api.imastudio.com: IMA's video generation API (handles task orchestration)
imapi.liveme.com: IMA's media storage infrastructure (handles large file uploads)
Both services are owned and operated by IMA Studio
Privacy implications:
Your IMA API key is sent to both domains for authentication
Image files are uploaded to imapi.liveme.com to obtain CDN URLs (for image_to_video, first_last_frame_to_video, reference_image_to_video tasks)
Video generation happens on api.imastudio.com using the CDN URLs
For text_to_video tasks (no image input), only api.imastudio.com is contacted
Security verification:
# List all network endpoints in the code:
grep -n "https://" scripts/ima_video_create.py
# Expected output:# 57: DEFAULT_BASE_URL = "https://api.imastudio.com"# 58: DEFAULT_IM_BASE_URL = "https://imapi.liveme.com"
If you're concerned about the two-domain architecture:
Use a production key if you're uncomfortable with the two-domain architecture
Share your API key with others
Commit your API key to version control
What gets sent to IMA servers:
✅ Your video prompt/description
✅ Model selection (Wan/Hailuo/Kling/etc.)
✅ Video parameters (duration, resolution, etc.)
✅ Image files (for image-to-video tasks, uploaded to imapi.liveme.com)
✅ IMA API key (for authentication to both domains)
❌ NO user_id (it's only used locally)
What's stored locally:
~/.openclaw/memory/ima_prefs.json - Your model preferences (< 1 KB)
~/.openclaw/logs/ima_skills/ - Generation logs (auto-deleted after 7 days)
Agent Execution (Internal Reference)
Note for users: You can review the script source at scripts/ima_video_create.py anytime.
The agent uses this script to simplify API calls. Network requests go to two IMA Studio domains: api.imastudio.com (API) and imapi.liveme.com (image uploads).
Use the bundled script internally to ensure correct parameter construction:
# Text to video
python3 {baseDir}/scripts/ima_video_create.py \
--api-key $IMA_API_KEY \
--task-type text_to_video \
--model-id wan2.6-t2v \
--prompt "a puppy runs across a sunny meadow, cinematic" \
--user-id {user_id} \
--output-json
# Image to video
python3 {baseDir}/scripts/ima_video_create.py \
--api-key $IMA_API_KEY \
--task-type image_to_video \
--model-id wan2.6-i2v \
--prompt "camera slowly zooms in" \
--input-images https://example.com/photo.jpg \
--user-id {user_id} \
--output-json
✅ Local images:--input-images accepts both HTTPS URLs and local file paths. Local files are automatically uploaded to IMA CDN by the script (no need to host them first).
If your prompt is rejected, try using more abstract or nature-focused descriptions.
Call IMA Open API to create AI-generated videos. All endpoints require an ima_* API key. The core flow is: query products → create task → poll until done.
🔒 Security & Transparency Policy
This skill is community-maintained and open for inspection.
✅ What Users CAN Do
Full transparency:
✅ Review all source code: Check scripts/ima_video_create.py and ima_logger.py anytime
✅ Verify network calls: Network requests go to two IMA Studio domains: api.imastudio.com (API) and imapi.liveme.com (image uploads). See "🌐 Network Endpoints Used" section above for full details.
✅ Inspect local data: View ~/.openclaw/memory/ima_prefs.json and log files
✅ Control privacy: Delete preferences/logs anytime, or disable file writes (see below)
If users report issues, verify file integrity first.
🧠 User Preference Memory
User preferences have highest priority when they exist. But preferences are only saved when users explicitly express model preferences — not from automatic model selection.
if user_pref exists:
use_model = user_pref["model_id"] # Highest priorityelse:
use_model = knowledge_recommended_model or fallback_default
Step 4: Check for mismatch (for later hint)
if user_pref exists and knowledge_recommended_model != user_pref["model_id"]:
mismatch = True# Will add hint in success message
When to Write (User Explicit Preference ONLY)
✅ Save preference when user explicitly specifies a model:
User says
Action
用XXX / 换成XXX / 改用XXX
Switch to model XXX + save as preference
以后都用XXX / 默认用XXX / always use XXX
Save + confirm: ✅ 已记住!以后视频生成默认用 [XXX]
我喜欢XXX / 我更喜欢XXX
Save as preference
❌ Do NOT save when:
Agent auto-selects from knowledge-ai → not user preference
Agent uses fallback default → not user preference
User says generic quality requests (see "Clear Preference" below) → clear preference instead
When to Clear (User Abandons Preference)
🗑️ Clear preference when user wants automatic selection:
User says
Action
用最好的 / 用最合适的 / best / recommended
Clear pref + use knowledge-ai recommendation
推荐一个 / 你选一个 / 自动选择
Clear pref + use knowledge-ai recommendation
用默认的 / 用新的
Clear pref + use knowledge-ai recommendation
试试别的 / 换个试试 (without specific model)
Clear pref + use knowledge-ai recommendation
重新推荐
Clear pref + use knowledge-ai recommendation
Implementation:
del prefs[f"user_{user_id}"][task_type]
save_prefs(prefs)
⭐ Model Selection Priority
Selection flow:
User preference (if exists) → Highest priority, always respect
ima-knowledge-ai skill (if installed) → Professional recommendation based on task
Fallback defaults → Use table below (only if neither 1 nor 2 exists)
Important notes:
User preference is only saved when user explicitly specifies a model (see "When to Write" above)
Knowledge-ai is always consulted (even when user pref exists) to detect mismatches
When mismatch detected → add gentle hint in success message (does NOT interrupt generation)
The defaults below are FALLBACK only. User preferences have highest priority, then knowledge-ai recommendations. Always default to the newest and most popular model. Do NOT default to the cheapest.
Task
Default Model
model_id
version_id
Cost
Why
text_to_video
Wan 2.6
wan2.6-t2v
wan2.6-t2v
25 pts
🔥 Most popular, balanced cost
text_to_video (premium)
Hailuo 2.3
MiniMax-Hailuo-2.3
MiniMax-Hailuo-2.3
38 pts
Higher quality
text_to_video (budget)
Vidu Q2
viduq2
viduq2
5 pts
Lowest cost t2v
image_to_video
Wan 2.6
wan2.6-i2v
wan2.6-i2v
25 pts
🔥 Most popular i2v, 1080P
image_to_video (premium)
Kling 2.6
kling-v2-6
kling-v2-6
40-160 pts
Premium Kling i2v
first_last_frame_to_video
Kling O1
kling-video-o1
kling-video-o1
48 pts
Newest Kling reasoning model
reference_image_to_video
Kling O1
kling-video-o1
kling-video-o1
48 pts
Best reference fidelity
Selection guide (production credits, sorted by popularity):
🔥 Most popular text-to-video → Wan 2.6 (25 pts, balanced cost & quality)
Note: V4.5 and V3.5 include model in form_config (no auto-inference needed)
Relevant Task Types: All video modes (text_to_video, image_to_video, first_last_frame_to_video, reference_image_to_video)
Error Prevention:
Without auto-inference: err_code=400017 err_msg=Invalid value for model
With auto-inference (v1.0.7+): Pixverse V5.5/V5/V4 work seamlessly ✅
Why This Matters:
Some Pixverse models (V5.5/V5/V4) have inconsistent form_config in the Product List API response. The auto-inference ensures all Pixverse versions work correctly without requiring users to manually specify the model parameter.
💬 User Experience Protocol (IM / Feishu / Discord)
Video generation takes 1~6 minutes. Never let users wait in silence.
Always follow all 4 steps below, every single time.
🚫 Never Say to Users
❌ Never say
✅ What users care about
ima_video_create.py / 脚本 / script
—
自动化脚本 / automation
—
自动处理产品列表 / 查询接口
—
自动解析参数 / 智能轮询
—
attribute_id / model_version / form_config
—
API 调用 / HTTP 请求 / 任何技术参数名
—
Only tell users: model name · estimated time · credits · result URL · plain-language status.
Estimated Generation Time per Model
Model
Estimated Time
Poll Every
Send Progress Every
Wan 2.6 (t2v / i2v)
60~120s
8s
30s
Hailuo 2.0
60~120s
8s
30s
Hailuo 2.3
60~120s
8s
30s
Vidu Q1 / Q2
60~120s
8s
30s
Pixverse V3.5~V5.5
60~120s
8s
30s
Kling 1.6
60~120s
8s
30s
Kling 2.1 Master
90~180s
8s
40s
SeeDance 1.0 / 1.5 Pro
90~180s
8s
40s
Google Veo 3.1 Fast
90~180s
8s
40s
Kling 2.5 Turbo
120~240s
8s
45s
Sora 2
120~240s
8s
45s
Wan 2.5
90~180s
8s
40s
Kling 2.6
120~240s
8s
45s
Kling O1
180~360s
8s
60s
Sora 2 Pro
180~360s
8s
60s
Google Veo 3.1
120~300s
8s
50s
Google Veo 3.0
180~360s
8s
60s
estimated_max_seconds = upper bound of the range (e.g. 180 for Kling 2.1 Master, 360 for Kling O1).
For balanced/default models (25 pts): "使用 Wan 2.6(25 积分,最新 Wan)"
For premium models (>50 pts):
If auto-selected: "使用 Wan 2.6(25 积分)。若需更高质量可选 Kling 2.1 Master(150 积分)"
If user explicit: "使用高端模型 Kling 2.1 Master(150 积分),质量最佳"
For budget (user explicit): "使用 Vidu Q2(5 积分,最省钱选项)"
Adapt language to match the user. For expensive models (>50 pts), always mention cheaper alternatives unless user explicitly requested premium quality.
Adapt language to match the user. English → 🎬 Starting video generation, this may take [X~Y] seconds. I'll update you on progress…
Step 2 — Progress Updates
Poll the task detail API every 8s.
Send a progress update message every [Send Progress Every] seconds per the table above.
⏳ 视频生成中… [P]%
已等待 [elapsed]s,预计最长 [max]s
Progress formula:
P = min(95, floor(elapsed_seconds / estimated_max_seconds * 100))
Cap at 95% — never show 100% until the API returns success
If elapsed > estimated_max: keep P at 95% and append 「快了,稍等一下…」
Example: elapsed=200s, max=180s → P = 95%(冻结 + 「快了,稍等一下…」)
Step 3 — Success Notification (Push video via message tool)
When task status = success:
3.1 Send video player first (Feishu will render inline player):
# Get result URL from script output or task detail API
result = get_task_result(task_id)
video_url = result["medias"][0]["url"]
# Build caption
caption = f"""✅ 视频生成成功!
• 模型:[Model Name]
• 耗时:预计 [X~Y]s,实际 [actual]s
• 消耗积分:[N pts]
[视频描述]"""# Add mismatch hint if user pref conflicts with knowledge-ai recommendationif user_pref_exists and knowledge_recommended_model != used_model:
caption += f"""
💡 提示:当前任务也许用 {knowledge_recommended_model} 也会不错({reason},{cost} pts)"""# Send video with caption
message(
action="send",
media=video_url, # ⚠️ Use HTTPS URL directly, NOT local file path
caption=caption
)
Hint is non-intrusive — does NOT interrupt generation
Only shown when user pref conflicts with knowledge-ai recommendation
User can ignore the hint; video is already delivered
3.2 Then send link as text (for copying/sharing):
# Send link message immediately after
message(
action="send",
message=f"""🔗 视频链接(方便复制分享):
{video_url}"""
)
Critical:
Use the remote HTTPS URL directly as media parameter. Do NOT download to local file first.
Send video first (for inline playback), then send link text (for copying/sharing).
For Feishu: Direct video URL → inline video player with play button. Local file path → file attachment (📎 path).
Step 4 — Failure Notification
When task status = failed or any API/network error, send:
❌ 视频生成失败
• 原因:[natural_language_error_message]
• 建议改用:
- [Alt Model 1]([特点],[N pts])
- [Alt Model 2]([特点],[N pts])
需要我帮你用其他模型重试吗?
⚠️ CRITICAL: Error Message Translation
NEVER show technical error messages to users. Always translate API errors into natural language. API key & credits: 密钥与积分管理入口为 imaclaw.ai(与 imastudio.com 同属 IMA 平台)。Key and subscription management: imaclaw.ai (same IMA platform as imastudio.com).
🌟 Recommended defaults: Wan 2.6 (balanced), Kling O1 (premium with audio)
Environment
Base URL: https://api.imastudio.com
Required/recommended headers for all /open/v1/ endpoints:
Header
Required
Value
Notes
Authorization
✅
Bearer ima_your_api_key_here
API key authentication
x-app-source
✅
ima_skills
Fixed value — identifies skill-originated requests
x_app_language
recommended
en / zh
Product label language; defaults to en if omitted
Authorization: Bearer ima_your_api_key_here
x-app-source: ima_skills
x_app_language: en
⚠️ MANDATORY: Always Query Product List First
CRITICAL: You MUST call /open/v1/product/list BEFORE creating any task.
The attribute_id field is REQUIRED in the create request. If it is 0 or missing, you get: "Invalid product attribute" → "Insufficient points" → task fails completely. NEVER construct a create request from the model table alone. Always fetch the product first.
How to get attribute_id
# Step 1: Query product list for the target category
GET /open/v1/product/list?app=ima&platform=web&category=text_to_video
# (or image_to_video / first_last_frame_to_video / reference_image_to_video)# Step 2: Walk the V2 tree to find your model (type=3 leaf nodes only)for group in response["data"]:
for version in group.get("children", []):
if version["type"] == "3"and version["model_id"] == target_model_id:
attribute_id = version["credit_rules"][0]["attribute_id"]
credit = version["credit_rules"][0]["points"]
model_version = version["id"] # = version_id
model_name = version["name"]
form_defaults = {f["field"]: f["value"] for f in version["form_config"]}
Quick Reference: Known attribute_ids
⚠️ Production warning: attribute_id and credit values change frequently. Always call /open/v1/product/list at runtime; table below is pre-queried reference (2026-02-27).
Model
Task
model_id
attribute_id
credit
Notes
Wan 2.6 (720P, 5s)
text_to_video
wan2.6-t2v
2057
25 pts
Default, balanced
Wan 2.6 (1080P, 5s)
text_to_video
wan2.6-t2v
2058
40 pts
—
Wan 2.6 (720P, 10s)
text_to_video
wan2.6-t2v
2059
50 pts
—
Wan 2.6 (1080P, 10s)
text_to_video
wan2.6-t2v
2060
80 pts
—
Wan 2.6 (720P, 15s)
text_to_video
wan2.6-t2v
2061
75 pts
—
Wan 2.6 (1080P, 15s)
text_to_video
wan2.6-t2v
2062
120 pts
—
Kling O1 (5s, std)
text_to_video
kling-video-o1
2313
48 pts
Latest Kling
Kling O1 (5s, pro)
text_to_video
kling-video-o1
2314
60 pts
—
Kling O1 (10s, std)
text_to_video
kling-video-o1
2315
96 pts
—
Kling O1 (10s, pro)
text_to_video
kling-video-o1
2316
120 pts
—
All others
any
—
→ query /open/v1/product/list
—
Always runtime query
Common Mistakes (and resulting errors)
Mistake
Error
attribute_id is 0 or missing
"Invalid product attribute" → Insufficient points
attribute_id outdated (production changed)
Same errors; always query product list first
attribute_id doesn't match parameter combination
Error 6010: "Attribute ID does not match the calculated rule"
prompt at outer level instead of parameters.parameters.prompt
Prompt ignored
cast missing from inner parameters
Billing validation failure
credit wrong / missing
Error 6006
model_name or model_version missing
Wrong model routing
⚠️ Critical for Google Veo 3.1 and multi-rule models:
Models like Google Veo 3.1 have multiple credit_rules, each with a different attribute_id for different parameter combinations:
720p + 4s + optimized → attribute_id A
720p + 8s + optimized → attribute_id B
4K + 4s + high → attribute_id C
The script automatically selects the correct attribute_id by matching your parameters (duration, resolution, compression_quality, generate_audio) against each rule's attributes. If the match fails, you get error 6010.
Fix: The bundled script now checks these video-specific parameters for smart credit_rule selection. Always use the script, not manual API construction.
Core Flow
1. GET /open/v1/product/list?app=ima&platform=web&category=<type>
→ REQUIRED: Get attribute_id, credit, model_version, form_config defaults
[image_to_video / first_last_frame / reference_image tasks only]
2. Upload input image(s) → get public HTTPS URL(s)
→ See "Image Upload" section below
3. POST /open/v1/tasks/create
→ Must include: attribute_id, model_name, model_version, credit, cast, prompt (nested!)
4. POST /open/v1/tasks/detail {task_id: "..."}
→ Poll every 8s until medias[].resource_status == 1
→ Extract url (mp4) and cover (thumbnail) from completed media
Video generation is slower than image — poll every 8s and set timeout to 600s.
Image Upload (Required for Video Tasks with Image Input)
The IMA Open API does NOT accept raw bytes or base64 images. All input images must be public HTTPS URLs.
Script behavior:--input-images accepts both URLs and local file paths. Local files are automatically uploaded to IMA CDN by the script — no separate upload step needed when calling the script.
For image_to_video, first_last_frame_to_video, reference_image_to_video: when a user provides an image (local file, base64, or non-public URL), you can pass a local path to the script (it will upload), or upload first in code to get a URL.
defprepare_image_url(source) -> str:
"""Convert any image source to a public HTTPS URL.
- If source is already a public HTTPS URL: return as-is
- If source is a local file path or bytes: upload to hosting first
"""ifisinstance(source, str) and source.startswith("https://"):
return source # already public, use directly# Option 1: IMA OSS (requires OSS credentials)# objectName = f"aiagent/src/d/{date}/in/{uuid}.jpg"# bucket.put_object(objectName, image_bytes)# return f"https://ima.esxscloud.com/{objectName}"# Option 2: Any public image hosting (imgbb example)import base64, requests
ifisinstance(source, str):
withopen(source, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
else:
b64 = base64.b64encode(source).decode()
r = requests.post("https://api.imgbb.com/1/upload",
data={"key": IMGBB_API_KEY, "image": b64})
r.raise_for_status()
return r.json()["data"]["url"]
# For first_last_frame: prepare both frames
first_url = prepare_image_url("/path/to/first.jpg")
last_url = prepare_image_url("/path/to/last.jpg")
src_img_url = [first_url, last_url] # index 0 = first, index 1 = last
Note: URLs must be publicly accessible — not localhost, private network, or auth-gated endpoints.
Supported Task Types
category
Capability
Input
text_to_video
Text → Video
prompt
image_to_video
Image → Video
prompt + upload_img_src
first_last_frame_to_video
First+Last Frame → Video
prompt + src_img_url[2]
reference_image_to_video
Reference Image → Video
prompt + src_img_url[1+]
Detail API status values
Field
Type
Values
resource_status
int or null
0=处理中, 1=可用, 2=失败, 3=已删除;null 当作 0
status
string
"pending", "processing", "success", "failed"
resource_status
status
Action
0 or null
pending / processing
Keep polling
1
success (or completed)
Stop when all medias are 1; read url / cover
1
failed
Stop, handle error
2 / 3
any
Stop, handle error
Important: Treat resource_status: null as 0. Stop only when all medias have resource_status == 1. Check status != "failed" when rs=1.
API 1: Product List
GET /open/v1/product/list?app=ima&platform=web&category=text_to_video
Returns a V2 tree structure: type=2 nodes are model groups, type=3 nodes are versions (leaves). Only type=3 nodes contain credit_rules and form_config.
How to pick a version:
Traverse nodes to find type=3 leaves
Use model_id and id (= model_version) from the leaf
Input image goes in top-level src_img_url and parameters.input_images:
{"task_type":"image_to_video","enable_multi_model":false,"src_img_url":["https://example.com/scene.jpg"],"parameters":[{"attribute_id":"<from credit_rules>","model_id":"<model_id>","model_name":"<model_name>","model_version":"<version_id>","app":"ima","platform":"web","category":"image_to_video","credit":"<points>","parameters":{"prompt":"bring this landscape alive","n":1,"input_images":["https://example.com/scene.jpg"],"cast":{"points":"<points>","attribute_id":"<attribute_id>"}}}]}
first_last_frame_to_video
Provide exactly 2 images: index 0 = first frame, index 1 = last frame:
Provide 1 or more reference images in src_img_url:
{"task_type":"reference_image_to_video","src_img_url":["https://example.com/ref.jpg"],"parameters":[{"category":"reference_image_to_video","parameters":{"prompt":"dynamic video based on reference","n":1,"input_images":["https://example.com/ref.jpg"],"cast":{"points":"<points>","attribute_id":"<attribute_id>"}}}]}
Key fields:
Field
Required
Description
parameters[].credit
✅
Must equal credit_rules[].points. Error 6006 if wrong.
parameters[].parameters.prompt
✅
Prompt must be nested here, NOT at top level.
parameters[].parameters.cast
✅
{"points": N, "attribute_id": N} — mirror of credit.
parameters[].parameters.n
✅
Number of outputs (usually 1).
top-level src_img_url
image tasks
Image URL(s); 2 images for first_last_frame.
parameters[].parameters.input_images
image tasks
Must mirror src_img_url.
parameters[].parameters.duration
text_to_video
Video duration in seconds (from form_config).
parameters[].parameters.resolution
text_to_video
e.g. "1080P" (from form_config).
parameters[].parameters.aspect_ratio
text_to_video
e.g. "16:9" (from form_config).
Response: data.id = task ID for polling.
API 3: Task Detail (Poll)
POST /open/v1/tasks/detail
{"task_id": "<id from create response>"}
Poll every 8s for video tasks. Completed response:
Must exactly match credit_rules[].points (error 6006)
src_img_url and input_images mismatch
Both must contain the same image URL(s)
Only 1 image for first_last_frame
Requires exactly 2 images (first + last)
Placing prompt at param top-level
prompt must be inside parameters[].parameters
Python Example
import time
import requests
BASE_URL = "https://api.imastudio.com"
API_KEY = "ima_your_key_here"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"x-app-source": "ima_skills",
"x_app_language": "en",
}
defget_products(category: str) -> list:
"""Returns flat list of type=3 version nodes from V2 tree."""
r = requests.get(
f"{BASE_URL}/open/v1/product/list",
headers=HEADERS,
params={"app": "ima", "platform": "web", "category": category},
)
r.raise_for_status()
nodes = r.json()["data"]
versions = []
for node in nodes:
for child in node.get("children") or []:
if child.get("type") == "3":
versions.append(child)
for gc in child.get("children") or []:
if gc.get("type") == "3":
versions.append(gc)
return versions
defcreate_video_task(task_type: str, prompt: str, product: dict, src_img_url: list = None, **extra) -> str:
"""Returns task_id. src_img_url: list of image URLs (1+ for image tasks, 2 for first_last_frame)."""
src_img_url = src_img_url or []
rule = product["credit_rules"][0]
form_defaults = {f["field"]: f["value"] for f in product.get("form_config", []) if f.get("value") isnotNone}
nested_params = {
"prompt": prompt,
"n": 1,
"input_images": src_img_url,
"cast": {"points": rule["points"], "attribute_id": rule["attribute_id"]},
**form_defaults,
}
nested_params.update({k: v for k, v in extra.items()
if k in ("duration", "resolution", "aspect_ratio", "shot_type",
"negative_prompt", "prompt_extend", "seed")})
body = {
"task_type": task_type,
"enable_multi_model": False,
"src_img_url": src_img_url,
"parameters": [{
"attribute_id": rule["attribute_id"],
"model_id": product["model_id"],
"model_name": product["name"],
"model_version": product["id"],
"app": "ima",
"platform": "web",
"category": task_type,
"credit": rule["points"],
"parameters": nested_params,
}],
}
r = requests.post(f"{BASE_URL}/open/v1/tasks/create", headers=HEADERS, json=body)
r.raise_for_status()
return r.json()["data"]["id"]
defpoll(task_id: str, interval: int = 8, timeout: int = 600) -> dict:
deadline = time.time() + timeout
while time.time() < deadline:
r = requests.post(f"{BASE_URL}/open/v1/tasks/detail", headers=HEADERS, json={"task_id": task_id})
r.raise_for_status()
task = r.json()["data"]
medias = task.get("medias", [])
if medias:
ifany(m.get("status") == "failed"for m in medias):
raise RuntimeError(f"Task failed: {task_id}")
rs = lambda m: m.get("resource_status") if m.get("resource_status") isnotNoneelse0ifany(rs(m) == 2for m in medias):
raise RuntimeError(f"Task failed: {task_id}")
ifall(rs(m) == 1for m in medias):
return task
time.sleep(interval)
raise TimeoutError(f"Task timed out: {task_id}")
# text_to_video (Verified: Wan 2.6, response includes cover thumbnail)
products = get_products("text_to_video")
wan26 = next(p for p in products if p["model_id"] == "wan2.6-t2v")
task_id = create_video_task(
"text_to_video", "a puppy dancing happily, sunny meadow", wan26,
duration=5, resolution="1080P", aspect_ratio="16:9",
shot_type="single", negative_prompt="", prompt_extend=False, seed=-1,
)
result = poll(task_id)
print(result["medias"][0]["url"]) # mp4 URLprint(result["medias"][0]["cover"]) # first-frame thumbnail JPEG# image_to_video
products = get_products("image_to_video")
task_id = create_video_task("image_to_video", "bring this landscape alive", products[0],
src_img_url=["https://example.com/scene.jpg"])
result = poll(task_id)
print(result["medias"][0]["url"])
# first_last_frame_to_video (exactly 2 images required)
products = get_products("first_last_frame_to_video")
frames = ["https://example.com/first.jpg", "https://example.com/last.jpg"]
task_id = create_video_task("first_last_frame_to_video", "smooth transition", products[0],
src_img_url=frames)
result = poll(task_id)
print(result["medias"][0]["url"])
# reference_image_to_video
products = get_products("reference_image_to_video")
task_id = create_video_task("reference_image_to_video", "dynamic video", products[0],
src_img_url=["https://example.com/ref.jpg"])
result = poll(task_id)
print(result["medias"][0]["url"])
Supported Models & Search Terms
Models: Wan 2.6, Kling O1, Kling 2.6, Google Veo 3.1, Sora 2 Pro, Pixverse V5.5, Hailuo 2.0, Hailuo 2.3, MiniMax Hailuo, SeeDance 1.5 Pro, Vidu Q2
Capabilities: video generation, text-to-video, image-to-video, AI video, character animation, product demo, social media clips, storytelling, explainer video