Speed Painting API Reference
This page covers all steps to integrate speed painting API into your system.
Get your API keys
Your API requests are authenticated using API keys. Any request that doesn't include an API key will return an error.
You can generate an API key from your user dashboard in Miragic website anytime.

Authentication
All requests must include the X-API-Key header containing your assigned API key.
curl -X POST "https://backend.miragic.ai/api/v1/speed-painting/create" \
-H "X-API-Key: YOUR_API_KEY" \
-F "fps=30" \
-F "quality=hd" \
-F "sequence=auto" \
-F "hand_style=1" \
-F "image=@path/to/image.jpg"import fs from "fs";
import FormData from "form-data";
import fetch from "node-fetch";
const apiKey = "YOUR_API_KEY";
const baseUrl = "https://backend.miragic.ai";
async function speedPainting() {
const url = `${baseUrl}/api/v1/speed-painting/create`;
const formData = new FormData();
formData.append("fps", "30");
formData.append("quality", "hd");
formData.append("sequence", "auto");
formData.append("hand_style", "1");
formData.append("image", fs.createReadStream("path/to/image.jpg"));
const response = await fetch(url, {
method: "POST",
headers: {
"X-API-Key": apiKey,
...formData.getHeaders(),
},
body: formData,
});
const result = await response.text();
console.log(result);
}
speedPainting();import requests
import time
api_key = 'YOUR_API_KEY' # ← Replace with your actual API key
base_url = 'https://backend.miragic.ai'
def speedpainting():
url = f'{base_url}/api/v1/speed-painting/create'
data = {
'fps': '30', # Frames per second (30 or 60)
'quality': 'hd', # Can be 'sd' or 'hd'
'sequence': 'auto', # How the drawing animation sequence is generated
'hand_style': '1' # Hand style (likely options: 0 = none, 1 = realistic, etc.)
}
files = [
('image', ('image.jpg', open('path/to/image.jpg', 'rb'), 'image/jpeg'))
]
headers = {'X-API-Key': api_key}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(response.text)
if __name__ == '__main__':
speedpainting()How To Create Speed Painting Task
POST /api/v1/speed-painting/create
This API starts the Speed Painting process by creating a task that generates an hand-drawn artworks video.
Request
image
File
Yes
Input image
audio_file
File
Optional
Input audio
quality
String
Yes
This value can be hd or sd
sequence
String
Yes
How the drawing animation sequence is generated. the value can be auto or vertical
fps
Number
Yes
Frames per second: This can be 30 or 60
hand_style
Number
Yes
The value can be 0, 1, 2, 3, 4
Request Example (Without audio input)
curl -X POST "https://backend.miragic.ai/api/v1/speed-painting/create" \
-H "X-API-Key: YOUR_API_KEY" \
-F "fps=30" \
-F "quality=hd" \
-F "sequence=auto" \
-F "hand_style=1" \
-F "image=@path/to/image.jpg"import fs from "fs";
import FormData from "form-data";
import fetch from "node-fetch";
const apiKey = "YOUR_API_KEY";
const baseUrl = "https://backend.miragic.ai";
async function speedPainting() {
const url = `${baseUrl}/api/v1/speed-painting/create`;
const formData = new FormData();
formData.append("fps", "30");
formData.append("quality", "hd");
formData.append("sequence", "auto");
formData.append("hand_style", "1");
formData.append("image", fs.createReadStream("path/to/image.jpg"));
const response = await fetch(url, {
method: "POST",
headers: {
"X-API-Key": apiKey,
...formData.getHeaders(),
},
body: formData,
});
const result = await response.text();
console.log(result);
}
speedPainting();import requests
import time
api_key = 'YOUR_API_KEY' # ← Replace with your actual API key
base_url = 'https://backend.miragic.ai'
def speedpainting():
url = f'{base_url}/api/v1/speed-painting/create'
data = {
'fps': '30', # Frames per second (30 or 60)
'quality': 'hd', # Can be 'sd' or 'hd'
'sequence': 'auto', # How the drawing animation sequence is generated
'hand_style': '1' # Hand style (likely options: 0 = none, 1 = realistic, etc.)
}
files = [
('image', ('image.jpg', open('path/to/image.jpg', 'rb'), 'image/jpeg'))
]
headers = {'X-API-Key': api_key}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(response.text)
if __name__ == '__main__':
speedpainting()Request Example (With audio input)
curl -X POST "https://backend.miragic.ai/api/v1/speed-painting/create" \
-H "X-API-Key: YOUR_API_KEY" \
-F "fps=30" \
-F "quality=hd" \
-F "sequence=auto" \
-F "hand_style=1" \
-F "image=@path/to/image.jpg"
-F "audio_file=@path/to/audio.mp3"import fs from "fs";
import FormData from "form-data";
import fetch from "node-fetch";
const apiKey = "YOUR_API_KEY";
const baseUrl = "https://backend.miragic.ai";
async function speedPainting() {
const url = `${baseUrl}/api/v1/speed-painting/create`;
const formData = new FormData();
formData.append("fps", "30");
formData.append("quality", "hd");
formData.append("sequence", "auto");
formData.append("hand_style", "1");
formData.append("image", fs.createReadStream("path/to/image.jpg"));
formData.append("audio_file", fs.createReadStream("path/to/audio.mp3"));
const response = await fetch(url, {
method: "POST",
headers: {
"X-API-Key": apiKey,
...formData.getHeaders(),
},
body: formData,
});
const result = await response.text();
console.log(result);
}
speedPainting();import requests
import time
api_key = 'YOUR_API_KEY' # ← Replace with your actual API key
base_url = 'https://backend.miragic.ai'
def speedpainting():
url = f'{base_url}/api/v1/speed-painting/create'
data = {
'fps': '30', # Frames per second (30 or 60)
'quality': 'hd', # Can be 'sd' or 'hd'
'sequence': 'auto', # How the drawing animation sequence is generated
'hand_style': '1' # Hand style (likely options: 0 = none, 1 = realistic, etc.)
}
files = [
('image', ('image.jpg', open('path/to/image.jpg', 'rb'), 'image/jpeg')),
('audio_file', ('audio.mp3', open('path/to/audio.mp3', 'rb'), 'audio/mpeg'))
]
headers = {'X-API-Key': api_key}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(response.text)
if __name__ == '__main__':
speedpainting()Response
{
"success": true,
"data": {
"jobId":"0322d8f9-61de-4501-b49e-5ea4a2f297dc",
"status":"PENDING",
"originalImageUrl":"https://backend.miragic.ai/uploads/speedpainting/original/0f01f45d-37e5-4796-ae1d-4900-4722-97bd-93bfbfc03203.jpg"
},
"message":"Speed painting job created successfully"
}Response Field
jobId
String
A unique identifier used to track task status and retrieve results.
status
String
The initial status will be PENDING. Use the Get Task Status API to track progress.
originalImageUrl
String
URL to input image
message
String
Explanation for result
success
Logic
true or false to indicate whether task is successful or not.
How To Get Task Status
GET /api/v1/speed-painting/:jobId
This API lets you check the status of a try-on task and retrieve the final result. Because the try-on process runs asynchronously, you’ll need to poll this endpoint until the task is finished.
Task Status:
PENDING
Task is currently being processed.
0~99%
Continue polling
COMPLETED
Task has finished successfully.
100%
Download result using download_signed_url
FAILED
Task processing failed.
N/A
Check error details and retry if needed
Request:
URL Parameters
JobId
String
Yes
This value indicates task ID assigned by requesting VTO process API
Request Example
curl -X GET https://backend.miragic.ai/api/v1/speed-painting/25331fb2-d0b0-44f6fcc85e3e \
-H "X-API-Key: YOUR_API_KEY"const fetch = require("node-fetch"); // for Node.js
const apiKey = "YOUR_API_KEY";
const jobId = "25331fb2-d0b0-44f6fcc85e3e";
const url = `https://backend.miragic.ai/api/v1/speed-painting/${jobId}`;
const options = {
method: "GET",
headers: {
"X-API-Key": apiKey
}
};
fetch(url, options)
.then(response => response.json())
.then(data => {
console.log("Response:", data);
})
.catch(error => {
console.error("Error:", error);
});import requests
api_key = "YOUR_API_KEY"
job_id = "25331fb2-d0b0-44f6fcc85e3e"
url = f"https://backend.miragic.ai/api/v1/speed-painting/{job_id}"
headers = {
"X-API-Key": api_key
}
response = requests.get(url, headers=headers)
# Print status code and response JSON
print("Status Code:", response.status_code)
print("Response:", response.json())Response Example
Completed Status (200):
{
'success': True,
'data': {
'id': '941f9c37-aff6-4475-916b-50f4060a237e',
'userId': '0f01f45d-37e5-4796-ae1d-aca695a0d792',
'originalImagePath': '/var/www/html/miragicAI/backend/uploads/speedpainting/original/759849-a18f045c-fbf7-4693-a231-ce33707087b4.jpg',
'originalImageUrl': 'https://backend.miragic.ai/uploads/speedpainting/original/0f01f4545c-fbf7-4693-a231-ce33707087b4.jpg',
'processedVideoUrl': 'https://backend.miragic.ai/uploads/speedpainting/processed/0f01f45d-37e5-4796-ae1de34fc5c659.mp4',
'status': 'COMPLETED',
'errorMessage': None,
'metadata': {
'externalVideoUrl': 'https://www.dropbox.com/scl/fi/lsflecx1xj7cxsbg4v2sw/aa96fe6e-ba91-469d-96a4-0e4143953f85.mp4?rlkey=lxy7zqoavvzgcwymr1w4qs0ln&raw=1',
'processingEndTime': '2025-10-10T18:42:54.983Z',
'processingDurationMs': 14899
},
'creditsUsed': 5,
'createdAt': '2025-10-10T18:42:40.008Z',
'updatedAt': '2025-10-10T18:42:54.984Z',
'processedUrl': 'https://backend.miragic.ai/uploads/speedpainting/processed/0f01f45d22d6d-4f2c-4d13-b11b-bce34fc5c659.mp4'
}
}Response Fields
id
String
Unique identifier of the task
status
String
Current status of the task (PENDING/COMPLETED/FAILED)
userId
String
Unique identifier of the user
originalImagePath
String
Path to input image
originalImageUrl
String
URL to input image
processedVideoUrl
String
URL to result video
resultImagePath
String
URL to result image
createdAt
Number
Unix timestamp when processing is created
errorMessage
String
Error message
Full Code Example
The following code lines are quick example to use our API in multiple languages.
Case 1: Without audio input
curl -X POST "https://backend.miragic.ai/api/v1/speed-painting/create" \
-H "X-API-Key: YOUR_API_KEY" \
-F "fps=30" \
-F "quality=hd" \
-F "sequence=auto" \
-F "hand_style=1" \
-F "image=@path/to/image.jpg"import axios from "axios";
import fs from "fs";
import FormData from "form-data";
const apiKey = "YOUR_API_KEY";
const baseUrl = "https://devapi.miragic.ai";
async function speedpainting() {
const url = `${baseUrl}/api/v1/speed-painting/create`;
// Form data with your settings
const form = new FormData();
form.append("fps", 60); // 30, 60
form.append("quality", "hd"); // 'hd', 'sd'
form.append("sequence", "vertical"); // 'auto', 'vertical'
form.append("hand_style", 1); // 0, 1, 2, 3, 4
form.append("image", fs.createReadStream("path/to/image.jpg"));
const headers = {
"X-API-Key": apiKey,
...form.getHeaders(),
};
try {
// Step 1: Create job
const response = await axios.post(url, form, { headers });
console.log(response.data);
if (response.data.success) {
const jobId = response.data.data.jobId;
console.log(`Job ID: ${jobId}`);
// Step 2: Poll for results
let status = "PENDING";
while (status !== "COMPLETED" && status !== "FAILED") {
await new Promise((r) => setTimeout(r, 2000)); // wait 2 sec
const result = await axios.get(`${baseUrl}/api/v1/speed-painting/jobs/${jobId}`, {
headers: { "X-API-Key": apiKey },
});
status = result.data.data.status;
if (status === "COMPLETED") {
console.log("Result:", result.data);
break;
} else if (status === "FAILED") {
console.log("Job failed:", result.data);
break;
} else {
console.log(`Current status: ${status}...`);
}
}
} else {
console.log("Error:", response.data);
}
} catch (error) {
console.error("Request failed:", error.response?.data || error.message);
}
}
speedpainting();import requests
import time
api_key = 'YOUR_API_KEY' # ← Replace with your actual API key
base_url = 'https://backend.miragic.ai'
def speedpainting():
url = f'{base_url}/api/v1/speed-painting/create'
data = {
'fps': '30', # Frames per second (30 or 60)
'quality': 'hd', # Can be 'sd' or 'hd'
'sequence': 'auto', # How the drawing animation sequence is generated
'hand_style': '1' # Hand style (likely options: 0 = none, 1 = realistic, etc.)
}
files = [
('image', ('image.jpg', open('path/to/image.jpg', 'rb'), 'image/jpeg'))
]
headers = {'X-API-Key': api_key}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(response.text)
if response.json()['success']:
job_id = response.json()['data']['jobId']
print(f'Job ID: {job_id}')
# Poll for results
while True:
result = requests.get(
f'{base_url}/api/v1/speed-painting/jobs/{job_id}',
headers=headers
)
if result.json()['data']['status'] == 'COMPLETED':
print('Result:', result.json())
break
elif result.json()['data']['status'] == 'FAILED':
print('Job failed:', result.json())
break
time.sleep(2)
else:
print('Error:', response.json())
if __name__ == '__main__':
speedpainting()Case 2: With audio input
curl -X POST "https://backend.miragic.ai/api/v1/speed-painting/create" \
-H "X-API-Key: YOUR_API_KEY" \
-F "fps=30" \
-F "quality=hd" \
-F "sequence=auto" \
-F "hand_style=1" \
-F "image=@path/to/image.jpg"
-F "audio_file=@path/to/audio.mp3"import axios from "axios";
import fs from "fs";
import FormData from "form-data";
const apiKey = "YOUR_API_KEY";
const baseUrl = "https://devapi.miragic.ai";
async function speedpainting() {
const url = `${baseUrl}/api/v1/speed-painting/create`;
// Form data with your settings
const form = new FormData();
form.append("fps", 60); // 30, 60
form.append("quality", "hd"); // 'hd', 'sd'
form.append("sequence", "vertical"); // 'auto', 'vertical'
form.append("hand_style", 1); // 0, 1, 2, 3, 4
form.append("image", fs.createReadStream("path/to/image.jpg"));
formData.append("audio_file", fs.createReadStream("path/to/audio.mp3"));
const headers = {
"X-API-Key": apiKey,
...form.getHeaders(),
};
try {
// Step 1: Create job
const response = await axios.post(url, form, { headers });
console.log(response.data);
if (response.data.success) {
const jobId = response.data.data.jobId;
console.log(`Job ID: ${jobId}`);
// Step 2: Poll for results
let status = "PENDING";
while (status !== "COMPLETED" && status !== "FAILED") {
await new Promise((r) => setTimeout(r, 2000)); // wait 2 sec
const result = await axios.get(`${baseUrl}/api/v1/speed-painting/jobs/${jobId}`, {
headers: { "X-API-Key": apiKey },
});
status = result.data.data.status;
if (status === "COMPLETED") {
console.log("Result:", result.data);
break;
} else if (status === "FAILED") {
console.log("Job failed:", result.data);
break;
} else {
console.log(`Current status: ${status}...`);
}
}
} else {
console.log("Error:", response.data);
}
} catch (error) {
console.error("Request failed:", error.response?.data || error.message);
}
}
speedpainting();import requests
import time
api_key = 'YOUR_API_KEY' # ← Replace with your actual API key
base_url = 'https://backend.miragic.ai'
def speedpainting():
url = f'{base_url}/api/v1/speed-painting/create'
data = {
'fps': '30', # Frames per second (30 or 60)
'quality': 'hd', # Can be 'sd' or 'hd'
'sequence': 'auto', # How the drawing animation sequence is generated
'hand_style': '1' # Hand style (likely options: 0 = none, 1 = realistic, etc.)
}
files = [
('image', ('image.jpg', open('path/to/image.jpg', 'rb'), 'image/jpeg')),
('audio_file', ('audio.mp3', open('path/to/audio.mp3', 'rb'), 'audio/mpeg'))
]
headers = {'X-API-Key': api_key}
response = requests.request("POST", url, headers=headers, data=data, files=files)
print(response.text)
if response.json()['success']:
job_id = response.json()['data']['jobId']
print(f'Job ID: {job_id}')
# Poll for results
while True:
result = requests.get(
f'{base_url}/api/v1/speed-painting/jobs/{job_id}',
headers=headers
)
if result.json()['data']['status'] == 'COMPLETED':
print('Result:', result.json())
break
elif result.json()['data']['status'] == 'FAILED':
print('Job failed:', result.json())
break
time.sleep(2)
else:
print('Error:', response.json())
if __name__ == '__main__':
speedpainting()Last updated