Generate AI talking head videos from a face image and audio
Include the authorization header with your secret token in all API requests:
Authorization: Bearer magicroll-avatar-2026Due to GPU cold start times (~5-9 min) and HTTP timeout limits, the API operates asynchronously:
job_id instantly.completed or failed.POST /api/generate
Submits a talking head generation request. Automatically applies silence-based smart chunking to process long audio in parallel.
| Parameter | Type | Description |
|---|---|---|
| image_url | string required | URL of the face image (JPG/PNG) |
| audio_url | string required | URL of the speech audio (MP3/WAV) |
| prompt | string | Scene description for the video |
| fps | number | Frames per second (default: 30) |
| seed | integer | Random seed for reproducibility (-1 = random) |
| use_vocals_only | boolean | Extract vocals from audio before generation |
{
"job_id": "c138f619e07f4f6ca5ff9341498b8de3",
"status": "queued",
"poll_url": "/api/jobs/c138f619e07f4f6ca5ff9341498b8de3"
}GET /api/jobs/{job_id}
Polls for the progress and result of a submitted job.
{
"job_id": "c138f619e07f4f6ca5ff9341498b8de3",
"status": "completed",
"elapsed": 128.5,
"result": {
"video_base64": "AAAAIGZ0eXB...",
"format": "mp4",
"total_duration": 55.4,
"num_chunks": 3,
"successful_chunks": 3,
"failed_chunks": 0,
"chunk_boundaries": [
{"start": 0.0, "end": 20.2, "duration": 20.2, "status": "success"},
{"start": 20.2, "end": 38.5, "duration": 18.3, "status": "success"},
{"start": 38.5, "end": 55.4, "duration": 16.9, "status": "success"}
],
"generation_time": 121.2,
"stitch_time": 1.8,
"total_time": 123.0,
"size_kb": 18200
}
}Submit Job:
curl -X POST "https://avatar-video-api-production.up.railway.app/api/generate" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer magicroll-avatar-2026" \
-d '{
"image_url": "https://d4g1s8ya3xoeq.cloudfront.net/4faf801f-1755-450a-a7e7-cde87830cf4b.jpg",
"audio_url": "https://magicrollai-videos.s3.ap-south-1.amazonaws.com/magic-agent/sessions/bae09b6c-f61c-43bf-861e-f4b471d30bf6/uploaded_assets/narration.mp3",
"prompt": "A distinguished Indian gentleman speaking passionately in Hindi"
}'Poll Status:
curl -X GET "https://avatar-video-api-production.up.railway.app/api/jobs/<job_id>" \
-H "Authorization: Bearer magicroll-avatar-2026"import requests, base64, time
API_BASE = "https://avatar-video-api-production.up.railway.app"
AUTH_TOKEN = "magicroll-avatar-2026"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {AUTH_TOKEN}"
}
# 1. Submit Job
resp = requests.post(f"{API_BASE}/api/generate", headers=headers, json={
"image_url": "https://d4g1s8ya3xoeq.cloudfront.net/4faf801f-1755-450a-a7e7-cde87830cf4b.jpg",
"audio_url": "https://magicrollai-videos.s3.ap-south-1.amazonaws.com/magic-agent/sessions/bae09b6c-f61c-43bf-861e-f4b471d30bf6/uploaded_assets/narration.mp3",
"prompt": "A distinguished Indian gentleman speaking passionately in Hindi"
})
job_id = resp.json()["job_id"]
# 2. Poll Status
while True:
status_resp = requests.get(f"{API_BASE}/api/jobs/{job_id}", headers=headers)
status_data = status_resp.json()
if status_data["status"] == "completed":
video_bytes = base64.b64decode(status_data["result"]["video_base64"])
with open("output.mp4", "wb") as f:
f.write(video_bytes)
break
elif status_data["status"] == "failed":
print("Failed:", status_data["error"])
break
time.sleep(5)| Scenario | Wall Time | Cost (approx) |
|---|---|---|
| Short (<20s) cold | ~5 min | ā¹24 |
| Short (<20s) warm | ~2 min | ā¹10 |
| 1 min audio, cold | ~5 min | ā¹94 |
| 1 min audio, warm | ~2 min | ā¹39 |
Cold start happens when GPU containers are idle for >10s. All chunks run in parallel ā wall time stays ~constant regardless of duration.