Image to Video
Image-to-Video
Transform static images into dynamic, high-quality videos with smooth, natural motion guided by optional text prompts.
Create an Image-to-Video Task
Animate a static image into a video. The model analyzes the source image and generates fluid motion based on the visual content and optional text guidance.
Request URL
POST https://api-gen-na.bach.art/api/vdr/videos/image2video
Request Headers
| Header | Value |
|---|---|
Authorization | Bearer <your_api_token> |
Content-Type | application/json |
Request Body
{
"model_name": "bach-1.0-preview",
"image_url": "https://example.com/images/scene.jpg",
"prompt": "The scene comes alive with gentle movement",
"negative_prompt": "blurry, distorted, unnatural",
"resolution": "720p",
"duration": 6,
"cfg_scale": 5.0,
"enhance_prompt": true,
"generate_audio": false,
"audio_prompt": "gentle movement, ambient sounds",
"callback_url": "https://your-domain.com/callback",
"seed": 12345,
"enable_moderation": true
}
Request Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model_name | string | Yes | — | Model identifier. Currently only bach-1.0-preview is supported |
image_url | string | Yes | — | Publicly accessible HTTP/HTTPS URL of the source image |
prompt | string | No | — | Text description to guide the animation (max 10,000 characters) |
negative_prompt | string | No | — | Elements to exclude from the generated video (max 10,000 characters) |
resolution | string | Yes | — | Output resolution: 720p or 1080p (case-sensitive) |
duration | integer | Yes | — | Video duration in seconds. (range:1~6) |
fps | integer | No | 30 | Frame rate:30 or 24. Currently default at 30 |
cfg_scale | float | No | 5.0 | Classifier-free guidance scale. Higher values increase prompt adherence (range: 1.0–15.0) |
enhance_prompt | boolean | No | true | Automatically enhance the prompt for improved visual quality |
generate_audio | boolean | No | false | Generate a synchronized audio track |
audio_prompt | string | No | — | Text description for audio generation (max 200 characters). Only effective when generate_audio is true |
callback_url | string | No | — | Webhook URL for task completion notifications (max 500 characters) |
seed | integer | No | Random | Random seed for reproducible generation (range: 0–10,000,000) |
enable_moderation | boolean | No | true | Enable content moderation for text, image, and audio inputs |
Image Requirements
| Requirement | Specification |
|---|---|
| Supported Formats | JPEG, PNG, WebP, GIF, BMP, TIFF |
| Maximum File Size | 10 MB |
| Minimum Resolution | 300 × 300 pixels |
| Recommended Resolution | 720p or higher for best results |
| URL Accessibility | Must be publicly accessible via HTTP/HTTPS |
Response
Success (HTTP 200):
{
"code": 200,
"message": "Success",
"data": {
"task_id": "770e8400-e29b-41d4-a716-446655440002",
"create_at": 1709251200
}
}
| Field | Type | Description |
|---|---|---|
code | integer | Business response code |
message | string | Response message |
data.task_id | string | Unique task identifier (UUID) |
data.create_at | long | Task creation timestamp (Unix epoch, seconds) |
Error Examples:
| Scenario | HTTP Status | Code | Message |
|---|---|---|---|
| Missing prompt | 400 | 1000 | Please provide a prompt. |
| Invalid duration | 400 | 1000 | Duration must be between 1 and 5 seconds. |
| Insufficient credits | 403 | 1302 | Insufficient credit package. |
For a complete list of error codes, see Response Codes.
Query an Image-to-Video Task
Retrieve the status and result of a previously submitted image-to-video task.
Request URL
GET https://api-gen-na.bach.art/api/vdr/videos/image2video/{task_id}
Request Headers
| Header | Value |
|---|---|
Authorization | Bearer <your_api_token> |
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
task_id | string | Yes | Task identifier returned by the creation endpoint |
Request Example
curl -X GET "https://api-gen-na.bach.art/api/vdr/videos/image2video/770e8400-e29b-41d4-a716-446655440002" \
-H "Authorization: Bearer <your_api_token>"
Response
Success (HTTP 200):
{
"code": 200,
"message": "Success",
"data": {
"task_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "TASK_SUCCEEDED",
"message": "Video generation completed successfully",
"video_url": "https://cdn.bach.art/videos/770e8400-e29b-41d4-a716-446655440002.mp4"
}
}
| Field | Type | Description |
|---|---|---|
data.task_id | string | Unique task identifier |
data.status | string | Current task status. See Task Status |
data.message | string | Human-readable status message |
data.video_url | string | Download URL for the generated video. Present only when status is TASK_SUCCEEDED |
Task Status Values
| Status | Description |
|---|---|
TASK_PENDING | Task is queued, awaiting processing |
TASK_PROCESSING | Video generation is in progress |
TASK_SUCCEEDED | Generation completed; video_url is available |
TASK_FAILED | Generation failed; check message for details |
Webhook Callback
If you provide a callback_url when creating a task, the API sends an HTTP POST request to that URL upon task completion.
Callback Payload:
{
"task_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "TASK_SUCCEEDED",
"video_url": "https://cdn.bach.art/videos/770e8400-e29b-41d4-a716-446655440002.mp4",
"created_at": 1709251200,
"completed_at": 1709251280
}
Note: Your callback endpoint must return HTTP 200 within 5 seconds. Failed callbacks are retried up to 3 times with exponential backoff.
Code Examples
Python
import requests
import time
API_BASE = "https://api-gen-na.bach.art/api/vdr"
API_TOKEN = "<your_api_token>"
headers = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
}
# Step 1: Create an image-to-video task
payload = {
"model_name": "bach-1.0-preview",
"image_url": "https://example.com/images/landscape.jpg",
"prompt": "Clouds drift slowly across the sky, trees sway gently in the breeze",
"negative_prompt": "static, frozen, jerky motion",
"resolution": "1080p",
"duration": 5,
"cfg_scale": 5.0,
"enhance_prompt": True
}
response = requests.post(
f"{API_BASE}/videos/image2video",
headers=headers,
json=payload
)
task_id = response.json()["data"]["task_id"]
print(f"Task submitted: {task_id}")
# Step 2: Poll for completion
while True:
status_response = requests.get(
f"{API_BASE}/videos/image2video/{task_id}",
headers=headers
)
result = status_response.json()["data"]
status = result["status"]
if status "TASK_SUCCEEDED":
print(f"Video ready: {result['video_url']}")
break
elif status "TASK_FAILED":
print(f"Generation failed: {result['message']}")
break
else:
print(f"Status: {status}, waiting...")
time.sleep(10)
cURL
# Create task
curl -X POST "https://api-gen-na.bach.art/api/vdr/videos/image2video" \
-H "Authorization: Bearer <your_api_token>" \
-H "Content-Type: application/json" \
-d '{
"model_name": "bach-1.0-preview",
"image_url": "https://example.com/images/landscape.jpg",
"prompt": "Clouds drift slowly across the sky, trees sway gently in the breeze",
"resolution": "1080p",
"duration": 5
}'
# Query task status
curl -X GET "https://api-gen-na.bach.art/api/vdr/videos/image2video/{task_id}" \
-H "Authorization: Bearer <your_api_token>"
Node.js
const axios = require('axios');
const API_BASE = 'https://api-gen-na.bach.art/api/vdr';
const API_TOKEN = '<your_api_token>';
const headers = {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
};
async function animateImage() {
// Step 1: Create task
const submitResponse = await axios.post(
`${API_BASE}/videos/image2video`,
{
model_name: 'bach-1.0-preview',
image_url: 'https://example.com/images/landscape.jpg',
prompt: 'Clouds drift slowly across the sky, trees sway gently in the breeze',
resolution: '1080p',
duration: 5,
enhance_prompt: true
},
{ headers }
);
const taskId = submitResponse.data.data.task_id;
console.log(`Task submitted: ${taskId}`);
// Step 2: Poll for completion
while (true) {
const statusResponse = await axios.get(
`${API_BASE}/videos/image2video/${taskId}`,
{ headers }
);
const { status, video_url, message } = statusResponse.data.data;
if (status = 'TASK_SUCCEEDED') {
console.log(`Video ready: ${video_url}`);
return video_url;
} else if (status = 'TASK_FAILED') {
throw new Error(`Generation failed: ${message}`);
}
console.log(`Status: ${status}, waiting...`);
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
animateImage().catch(console.error);
Best Practices
Image Selection
- Use high-resolution sources: Images at 720p or higher produce the best output quality.
- Ensure clear subjects: Well-defined subjects with good lighting generate more coherent animations.
- Avoid excessive clutter: Overly busy scenes may result in less natural motion.
Prompt Writing
- Describe the desired motion: Focus on the type, speed, and direction of movement (e.g., "gentle swaying," "flowing water," "walking forward").
- Be specific: Include details about camera movement, environmental effects, and character actions.
- Leverage negative prompts: Specify unwanted effects such as "jerky motion," "morphing," or "distortion."
Duration Selection
| Duration | Recommended Use Case |
|---|---|
| 1–2 s | Quick animations, subtle effects, loops |
| 3–4 s | Standard product showcases, social media content |
| 5-6 s | Complex scenes, cinematic storytelling |