Cách tạo video và ảnh AI bằng Meta Muse API
16 phút đọc • 12 tháng 10 năm 2026 (30 tháng 10 năm 2026)
useapi.net là API của bên thứ ba, không liên kết với Meta và không được Meta bảo trợ.
Mục lục
- Giới thiệu
- Chi phí
- Trước khi bắt đầu
- Cách làm
- Những gì chúng tôi rút ra
- Làm một Short 30 giây có thuyết minh (kịch bản, ba cảnh, một lần ghép)
- Câu hỏi thường gặp
- Kết luận
Giới thiệu
Muse API của useapi.net điều khiển Muse, agent AI cá nhân của Meta, bằng code: một lệnh POST tạo một ảnh hoặc một video 10 giây có lời thoại, và mỗi file nó tạo ra là một asset id mà job tiếp theo có thể nhận làm đầu vào.
Muse ở đây là agent của Meta tại muse.ai, không phải Skiv, công ty lưu trữ video đã dùng tên muse.ai cho tới tháng 3/2026. API được host sẵn, nên khác với các công cụ tự host như muse2api, bạn không phải triển khai gì: bài so sánh Meta Muse video API đặt API của chính Meta, muse2api và các API được host cạnh nhau.
API chạy trên gói đăng ký website Muse của bạn, và gói miễn phí cũng dùng được. Bài này lấy ba bức ảnh bình thường, một chiếc mô tô BMW cổ, một nữ tay lái tóc đỏ và bãi biển dưới cầu Golden Gate, rồi ghép thành một bức ảnh cô lái chiếc mô tô đó băng qua sóng. Bức ảnh sau đó thành một video trong đó cô hét lên một câu, và ở job thứ ba, một người phụ nữ khác, lấy từ bức ảnh thứ tư, thay cô trong video đó mà chuyến đi vẫn giữ nguyên. Trên đường đi, bài còn tạo ảnh từ văn bản, và phục hồi, tô màu một bức chân dung trăm năm tuổi rồi cho nhân vật ngước lên và cất lời. Mọi request dưới đây chính là request đã tạo ra media trên trang này.
Tay lái từ một bức ảnh, được thay vào clip Muse làm từ ảnh tĩnh (bước 8).
Chi phí
useapi.net là một API, không phải dịch vụ ảnh hay video riêng. Mọi lệnh gọi chạy trên một tài khoản Muse bạn thêm qua Setup Muse, và dùng hạn mức Muse hằng tuần của tài khoản đó, useapi.net không thu phí theo ảnh hay video. Muse báo hạn mức dưới dạng phần trăm đã dùng, làm tròn số nguyên, nên một ảnh thường không làm con số thay đổi.
Mỗi bước dùng bao nhiêu trên gói miễn phí, lấy từ percentUsed trước và sau bước đó, và mỗi job mất bao lâu:
| Bước | Endpoint | Đầu ra | Hạn mức đã dùng | Thời gian |
|---|---|---|---|---|
| Văn bản thành ảnh, 9:16 | POST /jobs/image | 1152×2048 | không đo | 30 s |
| Văn bản thành ảnh, đúng 16:9 | POST /jobs/image | 2048×1152 | 0% | 21 s |
| Tay lái + mô tô + bãi biển | POST /jobs/image | 2048×1152 | 0% | 31 s |
| Chuyến đi thành video | POST /jobs/video | 1280×720, 10 s | 3% | 88 s |
| Phục hồi ảnh cũ | POST /jobs/image | 1344×1792 | 1% | 34 s |
| Bức chân dung cất lời | POST /jobs/video | 832×1104, 10 s | 2% | 68 s |
| Thay tay lái | POST /jobs/video | 1248×704, 10 s | 3% | 138 s |
Tải file lên không tốn hạn mức. Trên gói miễn phí, một video dùng 2 đến 3 phần trăm của tuần và một ảnh 0 đến 1 phần trăm, nên một tài khoản miễn phí làm được khoảng 30 đến 50 video mỗi tuần, hoặc vài trăm ảnh (bước 9).
Trước khi bắt đầu
Bạn cần một API token của useapi.net và một tài khoản Muse thêm qua Setup Muse. Trước khi thêm tài khoản:
- Muse có ở Mỹ, Canada, Nhật Bản và Singapore (tính đến ngày 30/10/2026), nên hãy tạo tài khoản ở một trong các nước đó. Khi đã thêm tài khoản, bạn gọi API được từ bất cứ đâu.
- Hoàn tất bước làm quen của Muse tại muse.ai, gồm cả bước xác minh tuổi của Meta, và tạo một ảnh ở đó.
- Tài khoản phải đăng nhập được bằng email + mật khẩu, vì API đăng nhập bằng email và mật khẩu. Tài khoản Meta chỉ đăng nhập bằng mã gửi qua email thì chưa có mật khẩu: hãy tạo mật khẩu trong Meta Accounts Center (Mật khẩu và bảo mật), rồi thêm tài khoản ở đây. Không có mật khẩu, việc thêm tài khoản bị từ chối với
400. - Chỉ dùng tài khoản cho API, không chạy công cụ tự động nào khác trên đó. Mở tài khoản tại muse.ai trên trình duyệt thì không sao, nhưng chỉ từ Mỹ, Canada, Nhật Bản hoặc Singapore (các khu vực Muse chính thức hỗ trợ), hoặc qua VPN ở một trong các nước đó: Meta có thể tắt video của tài khoản nếu thấy nó được dùng từ nơi khác.
Mọi lệnh gọi cũng có trong Postman collection.
Không cần code: template n8n Old Photo to Talking Video phục hồi một bức ảnh và cho nó nói chuyện từ một biểu mẫu, còn template Narrated Faceless Shorts biến một chủ đề thành một Short có thuyết minh. Toàn bộ bài hướng dẫn cũng có trên GitHub dưới dạng một script, bằng Node.js và Python: images-videos/ trong useapi/muse-api, cùng một agent skill cho Claude Code và Codex.
Các bước dùng curl, jq cùng những biến và helper sau:
Mở biến và helper
export USEAPI_TOKEN="user:12345-..."
export EMAIL="[email protected]"
export MUSE_PASSWORD="..." # mật khẩu tài khoản Muse, chỉ dùng một lần ở bước 1
API=https://api.useapi.net/v1/muse
AUTH="Authorization: Bearer $USEAPI_TOKEN"
enc() { jq -rn --arg v "$1" '$v|@uri'; }
post() { curl -sS -X POST "$API/$1" -H "$AUTH" -H "Content-Type: application/json" -d "$2"; }
get() { curl -sS "$API/$1" -H "$AUTH"; }
upload() { curl -sS -X POST "$API/assets?email=$(enc "$EMAIL")" -H "$AUTH" -H "Content-Type: $2" --data-binary @"$1" | jq -r .assetId; }
download() { curl -sSf "$API/assets/$(enc "$1")" -H "$AUTH" -o "$2"; }
# chạy job bất đồng bộ: gửi job, gọi GET /jobs/{jobid} mỗi 10 giây, lưu bản ghi job cuối cùng vào $1
run() {
local job id
job=$(post "$2" "$(jq '. + {async: true}' <<< "$3")")
id=$(jq -r .jobid <<< "$job")
while [ "$(jq -r .status <<< "$job")" = started ]; do
sleep 10
job=$(get "jobs/$(enc "$id")")
done
echo "$job" > "$1"
jq '{status, error, text: .result.text, asset: .result.assets[0].assetId}' "$1"
}
Mọi lần tạo đều chạy dưới dạng job. Không có async, một lệnh POST chờ tối đa khoảng 100 giây và trả về bản ghi job đã xong, hoặc 202 khi job vẫn đang chạy. Ở đây một video mất 68 đến 138 giây, nên run gửi mọi job với async: true và gọi GET /jobs/jobid. Nếu run in ra status nào khác completed, hãy đọc error trước khi làm tiếp.
Để được gọi lại thay vì polling, thêm replyUrl: "https://example.com/hooks/muse" (và tùy chọn replyRef) vào bất kỳ body nào bên dưới. API sẽ gửi một lệnh POST chứa bản ghi job cuối cùng, dạng JSON, tới URL đó.
Id chứa : và @, nên enc mã hóa URL cho chúng mỗi khi đưa vào đường dẫn URL. Mọi đầu vào của một job phải nằm trên cùng một tài khoản Muse, nên các lần tải lên được gắn email, và một job chạy trên tài khoản đang giữ đầu vào của nó.
Cách làm
1. Thêm tài khoản
POST /accounts nhận email và mật khẩu của tài khoản Muse. API đăng nhập một lần, giữ phiên 30 ngày và tự gia hạn. Mỗi lần đăng nhập, Muse gửi email mã đăng nhập cho tài khoản. Email đó chỉ là thông báo, không cần nhập gì.
curl — POST /accounts
post accounts "$(jq -n --arg email "$EMAIL" --arg password "$MUSE_PASSWORD" '{email: $email, password: $password}')" | jq '{health, maxJobs, quota}'
Phản hồi cho thấy health: "OK", maxJobs (mặc định 10) cùng gói và mức sử dụng của tài khoản, ở đây là tier: "HATCH_FREE", gói miễn phí. Nếu phản hồi là 596, Meta muốn kiểm tra bảo mật: hãy đăng nhập một lần tại muse.ai trên trình duyệt, hoàn tất bước kiểm tra, rồi gửi lại cùng email và mật khẩu.
2. Tải ảnh lên
POST /assets nhận file thô làm body, tối đa 50 MB, và ghi nó vào workspace Muse của tài khoản. useapi.net không lưu gì. assetId trong phản hồi là thứ một job nhận làm image_N.
curl — POST /assets
BMW=$(upload bmw.jpeg image/jpeg)
RIDER=$(upload rider.jpeg image/jpeg)
BEACH=$(upload beach.jpeg image/jpeg)
OLD_PHOTO=$(upload old-photo.jpeg image/jpeg)
PINK=$(upload pink-hair.jpeg image/jpeg)
echo "$BMW"
# user:12345-email:6578616d706c6540676d61696c2e636f6d-image:7db53e7a1f0979cbab6ff46ec3f0a35b60e6ee579a0d738a9628cf46a0c7a0f5.jpg
Năm đầu vào: chiếc mô tô, tay lái, bãi biển, bức chân dung cũ và tay lái thứ hai.
Asset id được tạo từ nội dung file, nên tải lại cùng file lên cùng tài khoản sẽ trả về cùng id và không ghi gì thêm.
3. Ảnh từ văn bản
Muse không có tham số tỷ lệ khung hình: prompt nói điều đó. Trước tiên là một ảnh chân dung khổ dọc:
curl — POST /jobs/image
run portrait.json jobs/image "$(jq -n '{prompt: "Vertical 9:16 full-body portrait photo: a confident young woman biker with long wavy fiery red hair, green eyes and freckles, in a worn black leather jacket, dark jeans and boots, standing in a rain-soaked neon alley at dusk, looking straight at the camera, cinematic lighting, photorealistic."}')"
download "$(jq -r '.result.assets[0].assetId' portrait.json)" portrait.webp

Ảnh trả về đúng 9:16, 1152×2048. Một phiên bản ngang yêu cầu bằng Cinematic 16:9 landscape photo: … trả về 1920×1280, tức 3:2. Viết tỷ lệ là in exactly 16:9 aspect ratio đã khắc phục được:
curl — POST /jobs/image
run bmw-noir.json jobs/image "$(jq -n '{prompt: "In exactly 16:9 aspect ratio (landscape), a cinematic photo of a vintage 1920s black BMW motorcycle with white pinstripes, spoked wheels and a brown leather saddle, parked on wet cobblestones at night in San Francisco, the Golden Gate Bridge glowing through fog in the distance, neo-noir moonlight, reflections on the wet street, shot on 35mm film."}')"
download "$(jq -r '.result.assets[0].assetId' bmw-noir.json)" bmw-noir.webp

Muse trả lời “That 16:9 frame with the bridge ghosting through the fog is pure neo-noir. Enjoy.” Câu trả lời của nó nằm ở result.text.
4. Ghép ba ảnh thành một
Tối đa 9 ảnh vào một job dưới dạng image_1..image_9, và prompt gọi tên chúng. Ở đây chiếc mô tô là image_1, tay lái là image_2 và bãi biển là image_3. Prompt yêu cầu Muse dùng bãi biển đúng như trong ảnh chụp, nên cầu Golden Gate vẫn ở nguyên chỗ của nó trong ảnh.
curl — POST /jobs/image
run beach-ride.json jobs/image "$(jq -n --arg bmw "$BMW" --arg rider "$RIDER" --arg beach "$BEACH" \
'{image_1: $bmw, image_2: $rider, image_3: $beach,
prompt: "In exactly 16:9 aspect ratio (landscape), a cinematic photo: the woman from image_2 (her face, long wavy red hair, light blue top and jeans) riding the exact vintage motorcycle from image_1 along the shoreline of the beach in image_3, the front wheel cutting through the shallow surf and throwing spray, bright afternoon sun, her hair streaming in the wind, photorealistic. Use the beach, rocks and Golden Gate Bridge from image_3 as the background exactly as photographed: same position, same orientation, not mirrored or redrawn. Keep her face and the motorcycle'\''s design exactly as in the images."}')"
BEACH_RIDE=$(jq -r '.result.assets[0].assetId' beach-ride.json)
download "$BEACH_RIDE" beach-ride.webp

31 giây, và hạn mức hằng tuần không thay đổi thấy được.
5. Bức ảnh thành video, không cần tải lên lại
BEACH_RIDE là id của một file Muse đã tạo. File đã nằm trong workspace của tài khoản, nên đi thẳng vào job tiếp theo làm image_1, không cần tải về hay tải lên. Animate image_1 tạo một clip bắt đầu từ bức ảnh và giữ nguyên khổ hình, và câu trong ngoặc kép được nói ra.
curl — POST /jobs/video
run surf.json jobs/video "$(jq -n --arg img "$BEACH_RIDE" '{image_1: $img,
prompt: "Animate image_1 into a cinematic video in exactly 16:9 aspect ratio (landscape): she rides the vintage motorcycle along the shoreline, the front wheel slices through the shallow waves and sends spray flying, the old engine roars, she raises one fist and shouts with a laugh: \"Nothing beats this view!\" The camera tracks alongside her. The beach, the rocks and the Golden Gate Bridge stay exactly as in image_1 (same orientation). Keep her face and the motorcycle exactly as in image_1."}')"
SURF=$(jq -r '.result.assets[0].assetId' surf.json)
download "$SURF" surf.mp4
Xem thêm trên YouTube: 3 photos in, 1 talking video out: Meta Muse API from REST.
10 giây ở 1280×720 có âm thanh. Muse nói “Done. 10 seconds, 16:9 landscape, straight from your image — no edits, no upscaling.”
Lần thử đầu tiên của đúng job này lỗi sau 37 giây: Muse trả lời rằng “the video worker glitched out before it rendered anything, so no clip was made”. API báo câu trả lời như vậy là 503, không có gì được tạo, và cùng request đó chạy được khi gửi lại. Bị từ chối vì nội dung thì là 403, và cần một prompt khác.
6. Phục hồi và tô màu ảnh cũ
Một job ảnh cũng sửa được ảnh. Bức chân dung cũ là một ảnh nâu đỏ đã phai, 685×900 pixel, tỷ lệ 3:4. Prompt liệt kê những gì cần sửa và nhấn mạnh giữ nguyên khung hình.
curl — POST /jobs/image
run restored.json jobs/image "$(jq -n --arg img "$OLD_PHOTO" '{image_1: $img,
prompt: "Restore the old photograph image_1 as a high-quality modern photo: remove the scratches, dust, stains, fading and grain, recover sharp detail in the face, hair and fabric, and colorize it naturally (warm natural skin tones, dark brown hair, ivory tulle shawl, a soft pink rose with green leaves, a muted warm background). Keep the exact same person, expression, pose, framing and crop, and the same portrait aspect ratio as image_1 (3:4, 685×900): do not crop, extend or reframe it."}')"
RESTORED=$(jq -r '.result.assets[0].assetId' restored.json)
download "$RESTORED" restored.webp
Kết quả là 1344×1792, cùng khung 3:4 với kích thước khoảng gấp đôi, cùng tư thế và cùng cách cắt. Muse nói “Done — restored, de-grained, and colorized, same framing and pose.”
7. Bức chân dung sống dậy
Ảnh đã phục hồi đi thẳng vào một job video. Clip giữ nguyên khổ hình của bức chân dung, nên trả về 832×1104.
curl — POST /jobs/video
run portrait-video.json jobs/video "$(jq -n --arg img "$RESTORED" '{image_1: $img,
prompt: "Animate image_1 into a video with the same portrait frame: the young woman slowly lifts her eyes to the camera, her smile widens, she gently touches the rose on her shoulder and says softly: \"It has been a hundred years... and you still remember me.\" A light breeze moves a few strands of her hair, soft window light, the camera stays still with a very slow push-in. Keep her face exactly as in image_1."}')"
download "$(jq -r '.result.assets[0].assetId' portrait-video.json)" portrait.mp4
Xem thêm trên YouTube: This old portrait just spoke: one API call (Meta Muse API, third-party).
8. Thay tay lái trong video
Một job video cũng nhận video. video_1 là clip lướt sóng từ bước 5, còn image_1 là ảnh của một người phụ nữ thứ hai tóc hồng búi hai bên. Prompt yêu cầu Muse thay tay lái và giữ nguyên mọi thứ khác, và cho cô một câu thoại mới.
curl — POST /jobs/video
run swap.json jobs/video "$(jq -n --arg vid "$SURF" --arg img "$PINK" '{video_1: $vid, image_1: $img,
prompt: "Edit video_1: replace the rider with the woman from image_1 (her face, pink hair in two buns, colorful makeup and tattoos), and keep everything else the same: the motorcycle, the beach, the waves and spray, the Golden Gate Bridge, the light, the camera move and the timing. Instead of the original line she shouts: \"Catch me if you can, San Francisco!\" Keep the 16:9 frame and the same length."}')"
download "$(jq -r '.result.assets[0].assetId' swap.json)" swap.mp4
Với 138 giây, đây là job chậm nhất của bài, và cũng là lý do mọi job ở đây chạy async. Clip là cùng chuyến đi nhưng người phụ nữ kia ngồi trên mô tô, hét lên câu thoại mới. Muse nói “Done. She’s in, 10 seconds, 16:9, same ride, same bridge, same waves.”
Xem thêm trên YouTube: Replace the person in a video, keep everything else: Meta Muse API.
9. Kiểm tra hạn mức hằng tuần
GET /accounts/email đọc trực tiếp gói và mức sử dụng của tài khoản:
curl — GET /accounts/email
get "accounts/$(enc "$EMAIL")" | jq '{session, quota}'
quota.percentUsed là phần đã dùng của tuần, tính bằng phần trăm nguyên, còn quota.resetsAt là lúc hạn mức bắt đầu lại, một tuần sau khi bắt đầu. Ba video ở trên mỗi video dùng 2 đến 3 phần trăm và các ảnh 0 hoặc 1. Trong cả buổi thử nghiệm, gồm cả hai job không trình bày ở đây, tài khoản miễn phí đi từ 16 lên 28 phần trăm. Khi một tài khoản hết hạn mức, job mới không có email sẽ đi tới các tài khoản khác của bạn, còn job gắn với tài khoản đó trả về 412 cho tới resetsAt.
Những gì chúng tôi rút ra
- Viết tỷ lệ khung hình là
in exactly 16:9 aspect ratio.Cinematic 16:9 landscape photocó lần trả về 3:2. - Video nào cũng dài khoảng 10 giây. Prompt yêu cầu 5 giây vẫn nhận 10.
- Clip từ ảnh giữ khổ hình của ảnh, trừ khi prompt yêu cầu khổ khác:
in exactly 9:16 aspect ratiobiến ảnh bãi biển 16:9 của chúng tôi thành clip dọc 720×1280, được bố cục lại chứ không bị kéo giãn. - Câu thoại viết trong ngoặc kép trong prompt video sẽ được nói ra.
- Truyền file đã tạo bằng
assetId. Chúng nằm lại trong workspace của tài khoản, nên một chuỗi chỉnh sửa không cần tải về ở giữa. - Nói rõ cái gì phải giữ nguyên. “Same position, same orientation, not mirrored or redrawn” giữ được bãi biển thật trong ảnh ghép.
- Một lỗi
503kèm lời của chính Muse như “glitched out” thì đáng chạy lại.403là bị từ chối và cần prompt khác. - Gửi video với
async: true. Một request đồng bộ chờ khoảng 100 giây, còn lần thay người mất 138.
Làm một Short 30 giây có thuyết minh (kịch bản, ba cảnh, một lần ghép)
Video Muse luôn dài khoảng 10 giây, nên một Short dọc 30 giây có người thuyết minh cần ba job video và hai cuộc chat. Một chat viết kịch bản dạng JSON, ba job video chạy song song, mỗi job một cảnh, mỗi cảnh nói câu của mình bằng cùng giọng người thuyết minh, và một chat cuối ghép các clip bằng ffmpeg ngay trong workspace của tài khoản. Short dưới đây, về vụ phun trào núi Tambora năm 1815 và “năm không có mùa hè” sau đó, đi từ một chủ đề một dòng tới file MP4 trong khoảng 2 phút.
Xem thêm trên YouTube: A narrated 30-second Short made only with Meta Muse API calls.
Ba clip 10 giây ghép thành một Short 720×1280 dài 30 giây, từ chủ đề “how a single volcano cooled the whole planet in 1816”.
Kịch bản mất 11 giây, ba clip mất 75, 75 và 87 giây chạy cùng lúc, và lần ghép 20 giây, nên một Short mất khoảng 2 đến 3 phút. Short này được làm trên một gói Muse trả phí. Ở đó, bốn video của buổi thử nghiệm (ba video này và một video nữa) làm chỉ số hằng tuần tăng tổng cộng 2 điểm, còn các cuộc chat không làm tăng điểm nào. Trên gói miễn phí, một video dùng 2 đến 3 phần trăm của tuần, nên một Short ba cảnh tốn khoảng 6 đến 9 phần trăm.
Không cần code: cùng quy trình này có dạng ứng dụng n8n, template Narrated Faceless Shorts, với một biểu mẫu, một trang kịch bản và lưu vào Google Drive. Hai Short nó đã làm, đăng nguyên như khi ra lò: The Great Pyramid was once bright white và Why honey never spoils, được lồng tiếng bằng tính năng chuyển văn bản thành giọng nói của Muse.
Toàn bộ quy trình cũng là một script, bằng Node.js và Python: narrated-short/ trong useapi/muse-api. Script nhận một chủ đề, tùy chọn số cảnh và mô tả người thuyết minh của riêng bạn, và lưu Short vào output/.
Các bước dùng helper ở trên cộng thêm chat, helper bắt đầu một cuộc chat và đọc GET /chats/chatId cho tới khi Muse xong:
Mở helper chat
# bắt đầu một chat, gọi GET /chats/{chatId} mỗi 8 giây cho tới khi Muse xong, lưu chat vào $1
chat() {
local id c
id=$(post chats "$2" | jq -r .chatId)
while sleep 8; do
c=$(get "chats/$(enc "$id")")
jq -e '.pendingApprovals | length > 0' <<< "$c" > /dev/null &&
echo "Muse asks for permission: answer it with POST /chats/{chatId}/approvals/{approvalId}"
jq -e '(.status | IN("completed", "interrupted", "failed")) and (.pendingApprovals | length == 0)' <<< "$c" > /dev/null && break
done
echo "$c" > "$1"
jq '{status, reply: ([.messages[] | select(.role == "assistant" and .text != "")][-1].text)}' "$1"
}
Mọi request dưới đây đều gắn email. Một chat nhận file phải chạy trên tài khoản đang giữ chúng, nên ba clip và lần ghép đều ở trên một tài khoản.
1. Viết kịch bản dạng JSON
Chat đầu tiên yêu cầu đúng ba cảnh và nói rõ cấu trúc JSON. Mỗi cảnh có line, lời người thuyết minh, giới hạn 25 từ để vừa trong 10 giây, và visual, một câu mô tả cảnh quay. Prompt cũng bảo Muse không tạo file nào, nên cuộc chat chỉ có văn bản.
curl — POST /chats
TOPIC="how a single volcano cooled the whole planet in 1816"
chat script.json "$(jq -n --arg email "$EMAIL" --arg topic "$TOPIC" '{email: $email,
message: "Write a script for a 30-second faceless YouTube Short about: \"\($topic)\". Exactly 3 scenes. Reply with ONLY a JSON object, no prose, no markdown code fences, in this exact shape: {\"title\": string, \"scenes\": [{\"line\": string, \"visual\": string}, {\"line\": string, \"visual\": string}, {\"line\": string, \"visual\": string}]}. \"line\" is what the off-screen narrator says (at most 25 words, about 9 seconds spoken). \"visual\" is a one-sentence description of the 10-second shot, no people talking on camera. Do not create any files, images or videos."}')"
jq -r '[.messages[] | select(.role == "assistant" and .text != "")][-1].text' script.json | sed '/^```/d' > scenes.json
jq . scenes.json
Muse trả lời sau 11 giây, chỉ có JSON:
{
"title": "How One Volcano Cooled the Whole Planet in 1816",
"scenes": [
{
"line": "In April 1815, Mount Tambora in Indonesia erupted, the largest explosion in recorded history, blasting ash forty kilometers into the sky.",
"visual": "A massive volcanic eruption at dawn, with a towering ash column rising into the stratosphere above a dark island."
},
{
"line": "That ash veil circled Earth, blocking sunlight and dropping global temperatures, turning summer into winter across North America and Europe.",
"visual": "An animated globe wrapped in a gray haze as sunlight dims and frost spreads across continents."
},
{
"line": "1816 became the Year Without a Summer: crops failed, snow fell in July, and famine spread as the planet shivered.",
"visual": "Snow falling over green farmland in summer, covering withered crops and empty village fields under a pale sun."
}
]
}
Chúng tôi chạy cùng prompt cho ba chủ đề và lần nào cũng nhận JSON sạch, trong 11 đến 29 giây, không có khối code và không có chữ thừa. Mẫu đó còn nhỏ, nên sed vẫn bỏ dòng ``` lạc nếu có, và script trên GitHub hỏi lại một lần khi câu trả lời không phân tích được.
2. Ba cảnh cùng lúc
Mỗi cảnh thành một lệnh POST /jobs/video async. Cả ba prompt mang cùng một mô tả người thuyết minh, giống từng chữ, theo sau là The narrator says exactly: "<line>". Muse nói câu trong ngoặc kép đúng như đã viết, và mô tả chung giữ giọng nhất quán giữa các clip. Vertical 9:16 video trả về 720×1280.
curl — POST /jobs/video
NARRATOR="Narration: one off-screen narrator only, the same voice throughout: a calm, deep, middle-aged British male documentary narrator, measured pace, warm and authoritative, like a nature documentary. Nobody on screen speaks. No music."
for i in 0 1 2; do
post jobs/video "$(jq --arg email "$EMAIL" --arg narrator "$NARRATOR" --argjson i $i '.scenes[$i] | {email: $email, async: true,
prompt: "Vertical 9:16 video, about 10 seconds. \(.visual) Slow cinematic camera move, photoreal. \($narrator) The narrator says exactly: \"\(.line)\""}' scenes.json)" | jq -r .jobid
done > jobs.txt
Mỗi lệnh POST trả về 201 ngay với một jobid. Ba job chiếm ba trong số các slot maxJobs của tài khoản (mặc định 10), nên chúng chạy song song. Một lỗi 429 ở đây nghĩa là mọi slot đều bận và chưa có gì được bắt đầu: hãy gửi lại job đó sau 30 giây.
3. Polling các job
GET /jobs/jobid trả về status: "started" cho tới khi clip sẵn sàng. Các job chạy song song, nên đọc lần lượt từng job không tốn thêm thời gian:
curl — GET /jobs/jobid
for n in 1 2 3; do
id=$(sed -n "${n}p" jobs.txt)
until job=$(get "jobs/$(enc "$id")"); [ "$(jq -r .status <<< "$job")" != started ]; do sleep 10; done
echo "$job" > clip$n.json
jq '{status, error, text: .result.text, asset: .result.assets[0].assetId}' clip$n.json
done
Cả ba đều xong. Về clip đầu tiên, Muse nói “Here it is — vertical 9:16, photoreal volcanic eruption at dawn with the narration as specified”. Mỗi clip nói câu của mình đúng từng chữ, và mọi câu, dài 20 đến 21 từ, đều vừa trong 10 giây. Một job lỗi 503 không tạo ra gì và có thể chạy lại. Mọi lỗi khác, như bị từ chối 403, cần xem error.message trước.
4. Ghép các clip trong một chat
Ba id clip đi vào một chat dưới dạng files, nơi Muse thấy chúng là video_1, video_2 và video_3. Tin nhắn yêu cầu ffmpeg, thứ tự, âm thanh và tên file, và kết thúc bằng No public links. Với dòng đó, Muse không dừng lại xin phép.
curl — POST /chats
CLIPS=$(jq -s '[.[].result.assets[0].assetId]' clip1.json clip2.json clip3.json)
chat join.json "$(jq -n --arg email "$EMAIL" --argjson files "$CLIPS" '{email: $email, files: $files,
message: "Concatenate video_1, video_2, video_3 in order into one MP4 with ffmpeg, keep the audio, save it to workspace/your_files/short.mp4 and attach it here. No public links."}')"
SHORT=$(jq -r '[.messages[] | select(.role == "assistant") | .files[] | select(.type == "video")][-1].assetId' join.json)
echo "$SHORT"
# user:12345-email:6578616d706c6540676d61696c2e636f6d-video:ws~your_files~short.mp4
20 giây sau, Muse nói “Concatenated all three in order — 30 seconds, 720x1280, with audio kept.” và đính kèm file trong một tin nhắn riêng, với một video trong files. Asset id của nó được đặt theo đường dẫn workspace, nên hãy đặt cho mỗi Short một tên file riêng. ffmpeg chép các luồng mà không mã hóa lại: Short dài đúng 30,0 giây, và cả ba câu đều có trong đó, đúng thứ tự.
5. Tải Short về
GET /assets/assetId trả về file MP4:
curl — GET /assets/assetId
download "$SHORT" tambora-short.mp4
Các clip và Short cũng nằm lại trong workspace Muse của tài khoản, nơi ứng dụng muse.ai hiển thị chúng, và asset id của Short có thể vào job tiếp theo làm video_1.
Giọng cố định thay thế: chuyển văn bản thành giọng nói làm audio_1
Một mô tả chung cho ra cùng kiểu giọng, chứ không khóa cứng một giọng. Trong ba clip Tambora, cao độ trung vị của người thuyết minh là 105 đến 117 Hz, chênh nhau chưa tới hai nửa cung, nhưng Muse lồng tiếng lại từ đầu cho mỗi clip. Để chắc chắn chỉ một giọng, hãy cho Muse đọc mỗi câu bằng tính năng chuyển văn bản thành giọng nói trước, rồi truyền file MP3 đó vào job video làm audio_1. Cuộc chat chuyển văn bản thành giọng nói mất 20 giây trong thử nghiệm của chúng tôi.
curl — POST /chats và POST /jobs/video
chat voice1.json "$(jq -n --arg email "$EMAIL" --arg line "$(jq -r '.scenes[0].line' scenes.json)" '{email: $email,
message: "Generate one mp3 file with text to speech: single speaker, voice Aria (avocado_v2:MAI_01), speed 100, language en, clean narration only: no music, no sound effects. Read exactly this text, do not change any word:\n\"\($line)\"\nSave it directly in workspace/your_files/ (not in a subfolder) as line-1.mp3 and attach it here. No public links and no uploads to remote storage."}')"
VOICE1=$(jq -r '[.messages[] | select(.role == "assistant") | .files[] | select(.type == "audio")][-1].assetId' voice1.json)
run clip1.json jobs/video "$(jq --arg email "$EMAIL" --arg voice "$VOICE1" '.scenes[0] | {email: $email, audio_1: $voice,
prompt: "Vertical 9:16 video, about 10 seconds, no people on screen and nobody speaking on camera. \(.visual) Slow cinematic camera move, photoreal. Use audio_1 as the narration soundtrack exactly as it is: the off-screen narrator'\''s voice in audio_1, word for word, with no other voice and no new speech. Quiet ambient sound under it is fine."}' scenes.json)"
jq -r '.result.assets[] | select(.origin == "made") | .assetId' clip1.json
Muse tạo clip của nó rồi đặt audio_1 lên clip bằng ffmpeg. Job liệt kê cả hai file: bản hoàn chỉnh trước, với origin: "made", rồi clip thô của Muse, với origin: "generated". Hãy lấy bản made. Clip thô mang một giọng Muse tự nghĩ ra thay vì giọng của bạn. Job video mất 108 giây trong thử nghiệm của chúng tôi. Lặp lại cho mỗi cảnh và ghép các clip made như ở bước 4.
Câu hỏi thường gặp
Meta Muse (muse.ai) có API không? Qua useapi.net thì có: Muse API là API của bên thứ ba chạy Muse trên gói đăng ký website Muse của bạn. Tạo ảnh bằng POST /jobs/image và video bằng POST /jobs/video. Model API chính thức của Meta bán model Muse Image với giá $0,01 một ảnh, nhưng tính đến tháng 10/2026 không có tính năng tạo video và không có API cho agent Muse tại muse.ai, nơi video được tạo. Bài so sánh Meta Muse video API của chúng tôi nói cả về muse2api.
Gói Muse miễn phí có dùng được không? Qua useapi.net thì được: bài hướng dẫn này được làm trên gói miễn phí (HATCH_FREE), có hạn mức hằng tuần. Một video dùng 2 đến 3 phần trăm hạn mức và một ảnh 0 đến 1 phần trăm, nên một tài khoản miễn phí làm được khoảng 30 đến 50 video mỗi tuần. Các gói trả phí Power ($20 một tháng) và Maximum ($100 một tháng) nâng hạn mức lên (tính đến tháng 10/2026).
Muse có làm được video dài hơn 10 giây không? Qua useapi.net, không trong một job: video nào cũng dài khoảng 10 giây. Hãy làm một clip cho mỗi cảnh rồi để một chat ghép chúng bằng ffmpeg, như trong Làm một Short 30 giây có thuyết minh, nơi ba clip thành một Short trong khoảng 2 đến 3 phút. Một chat nhận tối đa 3 video.
Đặt tỷ lệ khung hình, độ dài hay độ phân giải thế nào? Qua useapi.net, bằng prompt, vì Muse không có tham số cho chúng. Tỷ lệ khung hình được tuân theo khi viết là in exactly 16:9 aspect ratio, và clip từ ảnh giữ khổ hình của ảnh trừ khi prompt yêu cầu khổ khác. Độ dài và độ phân giải cố định: video nào cũng trả về khoảng 720p có âm thanh, dù prompt yêu cầu gì.
Có dùng ảnh và video của chính mình được không? Qua useapi.net thì được: tải chúng lên bằng POST /assets, mỗi file tối đa 50 MB, và truyền assetId làm image_1..image_9, giống như truyền kết quả từ một job trước. Job video còn nhận video_1..video_3 và audio_1..audio_3. Mọi đầu vào của một job phải nằm trên cùng một tài khoản.
Làm sao cho một bức ảnh biết nói? Qua useapi.net, truyền ảnh làm image_1 vào POST /jobs/video với prompt kiểu Animate image_1: … she says softly: "…". Muse giữ khổ hình của ảnh và nói câu trong ngoặc kép, như ở bước 7, nơi một bức chân dung trăm năm tuổi đã phục hồi ngước lên và cất lời.
Có thay được người trong video không? Qua useapi.net thì được: truyền clip làm video_1 và ảnh người mới làm image_1, rồi yêu cầu Muse thay người và giữ nguyên mọi thứ khác, như ở bước 8. Nói rõ cái gì phải giữ nguyên, như chuyến đi, cây cầu và sóng biển, và cho người mới một câu thoại trong ngoặc kép nếu họ cần nói.
Vì sao request đồng bộ của tôi trả về 202? Qua useapi.net, 202 nghĩa là job vẫn đang chạy sau khoảng 100 giây, và nó tiếp tục chạy phía chúng tôi. Lấy kết quả bằng GET /jobs/jobid, gửi job dài với async: true rồi polling, hoặc thêm replyUrl để nhận bản ghi job đã xong. Trong các lần chạy của chúng tôi, một video mất 68 đến 138 giây.
Vì sao Muse gửi email mã đăng nhập cho tôi? Qua useapi.net, API đã đăng nhập vào tài khoản Muse của bạn, việc này xảy ra khi bạn thêm tài khoản và khi API gia hạn phiên 30 ngày, trước khi phiên hết hạn hoặc bất cứ lúc nào Muse yêu cầu đăng nhập lại. Muse gửi email mã đăng nhập mỗi lần đăng nhập, và bạn không cần làm gì với mã đó. Xem Setup Muse.
Khác gì so với muse2api? Qua useapi.net, Muse API được host sẵn, nên không có gì phải triển khai: bạn thêm mỗi tài khoản bằng email và mật khẩu và chúng tôi giữ cho nó luôn đăng nhập. Kết quả nối tiếp nhau bằng asset id, và job đã xong có thể gọi webhook của bạn. Bạn cũng có thể chat với agent Muse, với câu trả lời được stream trực tiếp. muse2api là một dự án bạn tự triển khai, tự host và tự duy trì.
Kết luận
Ghé Discord Server hoặc
Telegram Channel của chúng tôi cho mọi câu hỏi hỗ trợ.
Xem repo GitHub của chúng tôi với các ví dụ code.
Cùng những lệnh gọi này có sẵn dưới dạng tool trên Muse MCP server được host sẵn cho Claude Code, Cursor và VS Code.
Đăng ở nơi khác
Cũng đăng trên dev.to, thảo luận trên Reddit, chia sẻ trên Bluesky, và trên YouTube dưới dạng bản demo 2:49 của toàn bộ API (các bản này bằng tiếng Anh).
Bắt đầu dùng API
Một gói đăng ký $15/tháng dùng được mọi API trên useapi.net: một token cho tất cả dịch vụ. Mỗi dịch vụ bạn kết nối tối đa 3 tài khoản của riêng mình, còn useapi.net lo REST API, cân bằng tải và polling. Cần thêm tài khoản? Mỗi gói đăng ký thêm giá $10/tháng và cho thêm 3 tài khoản ở mỗi dịch vụ.
Không có thẻ thanh toán quốc tế? Bạn có thể đăng ký bằng tiền mã hóa (thanh toán bằng tiền mã hóa không được hoàn tiền). Giá và các gói số lượng lớn có trên trang đăng ký. Nếu thanh toán qua Stripe, bạn được hoàn tiền toàn bộ trong 14 ngày kể từ lần mua đầu tiên khi có dưới 50 lượt tạo thành công. Đã đăng ký rồi? Hãy đổi số lượng trong Stripe Customer Portal thay vì mua lại.





