Cómo generar videos e imágenes con IA con la API de Meta Muse
16 min de lectura • 12 de octubre de 2026 (30 de octubre de 2026)
useapi.net es una API de terceros. No está afiliada a Meta ni cuenta con su respaldo.
Índice
- Introducción
- Cuánto costó
- Antes de empezar
- Cómo se hizo
- Lo que aprendimos
- Haz un Short narrado de 30 segundos (guion, tres escenas, una unión)
- Preguntas frecuentes
- Conclusión
Introducción
La Muse API de useapi.net controla Muse, el agente personal de IA de Meta, desde código: un POST genera una imagen o un video de 10 segundos con diálogo hablado, y cada archivo que genera es un asset id que el siguiente job puede usar como entrada.
Muse aquí es el agente de Meta en muse.ai, no Skiv, la empresa de alojamiento de video que usó el nombre muse.ai hasta marzo de 2026. La API está alojada, así que, a diferencia de herramientas que alojas tú, como muse2api, no hay nada que desplegar: la comparación de API de video de Meta Muse (en inglés) pone lado a lado la API de la propia Meta, muse2api y las API alojadas.
La API funciona con tu suscripción al sitio web de Muse, y el plan gratuito sirve. Este recorrido toma tres fotos comunes (una motocicleta BMW antigua, una motociclista pelirroja y la playa bajo el Golden Gate) y las convierte en una imagen de ella conduciendo esa motocicleta entre las olas. Esa imagen se convierte después en un video en el que ella grita una frase, y en un tercer job otra mujer, tomada de una cuarta foto, la reemplaza en ese video mientras el paseo sigue igual. Por el camino genera imágenes a partir de texto, y restaura y colorea un retrato de cien años que luego levanta la mirada y habla. Cada solicitud de abajo es la que generó el contenido de esta página.
La motociclista de una foto, puesta en un clip que Muse hizo a partir de una imagen fija (paso 8).
Cuánto costó
useapi.net es una API, no un servicio propio de imágenes o videos. Cada llamada se ejecuta en una cuenta de Muse que agregas con Setup Muse, y usa la cuota semanal de Muse de esa cuenta, sin cobro por imagen ni por video de parte de useapi.net. Muse informa la cuota como un porcentaje entero usado, así que una sola imagen a menudo no muestra ningún cambio.
Lo que consumió cada paso en el plan gratuito, tomado de percentUsed antes y después, y cuánto tardó cada job:
| Paso | Endpoint | Resultado | Cuota usada | Tiempo |
|---|---|---|---|---|
| Texto a imagen, 9:16 | POST /jobs/image | 1152×2048 | no medido | 30 s |
| Texto a imagen, 16:9 exacto | POST /jobs/image | 2048×1152 | 0% | 21 s |
| Motociclista + motocicleta + playa | POST /jobs/image | 2048×1152 | 0% | 31 s |
| El paseo en video | POST /jobs/video | 1280×720, 10 s | 3% | 88 s |
| Restaurar una foto antigua | POST /jobs/image | 1344×1792 | 1% | 34 s |
| El retrato habla | POST /jobs/video | 832×1104, 10 s | 2% | 68 s |
| Cambiar a la motociclista | POST /jobs/video | 1248×704, 10 s | 3% | 138 s |
Las subidas no consumen cuota. En el plan gratuito, un video consumió del 2 al 3 por ciento de la semana y una imagen del 0 al 1 por ciento, así que una cuenta gratuita genera más o menos de 30 a 50 videos por semana, o varios cientos de imágenes (paso 9).
Antes de empezar
Necesitas un token de API de useapi.net y una cuenta de Muse agregada con Setup Muse. Antes de agregar la cuenta:
- Muse está disponible en EE. UU., Canadá, Japón y Singapur (al 30 de octubre de 2026), así que crea la cuenta en uno de esos países. Una vez agregada, puedes llamar a la API desde cualquier lugar.
- Termina el proceso de bienvenida de Muse en muse.ai, incluida la verificación de edad de Meta, y crea una imagen allí.
- La cuenta debe poder iniciar sesión con correo y contraseña, porque la API inicia sesión con el correo y la contraseña. Una cuenta de Meta que solo inicia sesión con un código enviado por correo todavía no tiene contraseña: crea una en el Centro de cuentas de Meta (Contraseña y seguridad) y después agrega la cuenta aquí. Sin contraseña, la cuenta se rechaza con
400. - Usa la cuenta solo para la API, sin otras herramientas de automatización. Abrirla en muse.ai desde un navegador está bien, pero solo desde EE. UU., Canadá, Japón o Singapur (las regiones donde Muse tiene soporte oficial), o con una VPN en una de ellas: Meta puede desactivar el video de una cuenta que ve usada desde otro lugar.
Todas las llamadas están también en la colección de Postman.
Sin código: la plantilla de n8n Old Photo to Talking Video restaura una foto y la hace hablar desde un formulario, y la plantilla Narrated Faceless Shorts convierte un tema en un Short narrado. El recorrido completo también está en GitHub como un solo script, en Node.js y Python: images-videos/ en useapi/muse-api, además de una agent skill para Claude Code y Codex.
Los pasos usan curl, jq y estas variables y funciones auxiliares:
Abrir las variables y las funciones auxiliares
export USEAPI_TOKEN="user:12345-..."
export EMAIL="[email protected]"
export MUSE_PASSWORD="..." # la contraseña de la cuenta de Muse, se usa una vez en el paso 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"; }
# ejecuta un job en modo asíncrono: lo envía, consulta GET /jobs/{jobid} cada 10 s y guarda el registro final del job en $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"
}
Cada generación se ejecuta como un job. Sin async, un POST espera hasta unos 100 segundos y devuelve el registro del job terminado, o 202 con el job todavía en curso. Un video aquí tardó de 68 a 138 segundos, así que run envía cada job con async: true y consulta GET /jobs/jobid. Si run muestra cualquier status distinto de completed, lee su error antes de seguir.
Para recibir un callback en lugar de consultar, agrega replyUrl: "https://example.com/hooks/muse" (y, si quieres, replyRef) a cualquier cuerpo de abajo. La API envía entonces un solo POST con el registro final del job, en JSON, a esa URL.
Los ids contienen : y @, así que enc los codifica para URL cada vez que van en una ruta. Todas las entradas de un job deben estar en la misma cuenta de Muse, así que las subidas fijan email, y un job se ejecuta en la cuenta que tiene sus entradas.
Cómo se hizo
1. Agregar la cuenta
POST /accounts recibe el correo y la contraseña de la cuenta de Muse. La API inicia sesión una vez, conserva la sesión de 30 días y la renueva por su cuenta. Muse envía a la cuenta un código de inicio de sesión por correo en cada inicio de sesión. Ese correo es solo un aviso, no hay que ingresar nada.
curl — POST /accounts
post accounts "$(jq -n --arg email "$EMAIL" --arg password "$MUSE_PASSWORD" '{email: $email, password: $password}')" | jq '{health, maxJobs, quota}'
La respuesta muestra health: "OK", maxJobs (10 por defecto) y el plan y el uso de la cuenta, aquí tier: "HATCH_FREE", el plan gratuito. Si en cambio responde 596, Meta quiere una verificación de seguridad: inicia sesión una vez en muse.ai desde un navegador, complétala y vuelve a enviar el mismo correo y la misma contraseña.
2. Subir las fotos
POST /assets recibe el archivo tal cual como cuerpo, hasta 50 MB, y lo guarda en el espacio de trabajo de Muse de la cuenta. No se guarda nada en useapi.net. El assetId de la respuesta es lo que un job recibe como 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

image_1 — la motocicleta
image_2 — la motociclista
image_3 — la playa

Las cinco entradas: la motocicleta, la motociclista, la playa, el retrato antiguo y la segunda motociclista.
El asset id se calcula a partir del contenido del archivo, así que volver a subir el mismo archivo a la misma cuenta devuelve el mismo id y no guarda nada.
3. Imágenes a partir de texto
Muse no tiene un parámetro de relación de aspecto: lo dice el prompt. Primero, un retrato vertical:
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

Llegó exactamente en 9:16, 1152×2048. Una versión horizontal pedida como Cinematic 16:9 landscape photo: … llegó en 1920×1280, que es 3:2. Escribir la relación como in exactly 16:9 aspect ratio lo resolvió:
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 respondió “That 16:9 frame with the bridge ghosting through the fog is pure neo-noir. Enjoy.” Su respuesta está en result.text.
4. Tres fotos en una sola imagen
En un job entran hasta 9 imágenes como image_1..image_9, y el prompt las nombra. Aquí la motocicleta es image_1, la motociclista image_2 y la playa image_3. El prompt le pide a Muse que use la playa fotografiada tal como es, así que el Golden Gate se queda donde estaba en la foto.
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 segundos, y ningún cambio visible en la cuota semanal.
5. La imagen se vuelve video, sin volver a subirla
BEACH_RIDE es el id de un archivo que hizo Muse. Ya está en el espacio de trabajo de la cuenta, así que entra directo en el siguiente job como image_1, sin descargarlo ni subirlo. Animate image_1 genera un clip que parte de la imagen y conserva su formato, y la frase entre comillas se dice en voz alta.
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
También en YouTube: 3 photos in, 1 talking video out: Meta Muse API from REST.
10 segundos en 1280×720, con sonido. Muse dijo “Done. 10 seconds, 16:9 landscape, straight from your image — no edits, no upscaling.”
El primer intento de este mismo job falló a los 37 segundos: Muse respondió que “the video worker glitched out before it rendered anything, so no clip was made”. La API informa una respuesta así como 503, sin nada generado, y la misma solicitud funcionó al ejecutarla otra vez. Un rechazo por el contenido es un 403, y necesita otro prompt.
6. Restaurar y colorear una foto antigua
Un job de imagen también puede reparar una imagen. El retrato antiguo es una foto sepia desteñida de 685×900 píxeles, 3:4. El prompt enumera lo que hay que arreglar e insiste en el mismo encuadre.
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
El resultado mide 1344×1792, el mismo encuadre 3:4 a cerca del doble de tamaño, con la misma pose y el mismo recorte. Muse dijo “Done — restored, de-grained, and colorized, same framing and pose.”
7. El retrato cobra vida
La imagen restaurada entra directo en un job de video. El clip conserva el formato del retrato, así que llegó en 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
También en YouTube: This old portrait just spoke: one API call (Meta Muse API, third-party).
8. Cambiar a la motociclista del video
Un job de video también recibe videos. video_1 es el clip de las olas del paso 5, e image_1 es la foto de una segunda mujer con el pelo rosa recogido en dos moños. El prompt le pide a Muse que reemplace a la motociclista y conserve todo lo demás, y le da una frase nueva.
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
Con 138 segundos, este fue el job más lento del recorrido, y por eso cada job aquí se ejecuta en modo asíncrono. El clip es el mismo paseo con la otra mujer en la motocicleta, gritando la frase nueva. Muse dijo “Done. She’s in, 10 seconds, 16:9, same ride, same bridge, same waves.”
También en YouTube: Replace the person in a video, keep everything else: Meta Muse API.
9. Revisar la cuota semanal
GET /accounts/email lee en vivo el plan y el uso de la cuenta:
curl — GET /accounts/email
get "accounts/$(enc "$EMAIL")" | jq '{session, quota}'
quota.percentUsed es la parte de la semana ya usada, en porcentaje entero, y quota.resetsAt es cuándo vuelve a empezar, una semana después de su inicio. Los tres videos de arriba consumieron del 2 al 3 por ciento cada uno y las imágenes 0 o 1. En toda la sesión de pruebas, que también ejecutó dos jobs que no aparecen aquí, la cuenta gratuita pasó del 16 al 28 por ciento. Cuando una cuenta se queda sin cuota, los jobs nuevos sin email van a tus otras cuentas, y un job fijado a ella responde 412 hasta resetsAt.
Lo que aprendimos
- Escribe la relación de aspecto como
in exactly 16:9 aspect ratio.Cinematic 16:9 landscape photollegó una vez en 3:2. - Cada video dura unos 10 segundos. Un prompt que pedía 5 segundos igual recibió 10.
- Un clip de imagen a video conserva el formato de su imagen salvo que el prompt pida otro:
in exactly 9:16 aspect ratioconvirtió nuestra imagen 16:9 de la playa en un clip vertical de 720×1280, reencuadrado en lugar de estirado. - Las frases escritas entre comillas en un prompt de video se dicen en voz alta.
- Pasa los archivos generados por su
assetId. Se quedan en el espacio de trabajo de la cuenta, así que una cadena de ediciones no necesita descargas intermedias. - Di lo que debe seguir igual. “Same position, same orientation, not mirrored or redrawn” conservó la playa real en la composición.
- Vale la pena volver a ejecutar un
503con palabras de Muse como “glitched out”. Un403es un rechazo y necesita otro prompt. - Envía los videos con
async: true. Una solicitud síncrona espera unos 100 segundos, y el cambio de persona tardó 138.
Haz un Short narrado de 30 segundos (guion, tres escenas, una unión)
Un video de Muse siempre dura unos 10 segundos, así que un Short vertical de 30 segundos con narrador necesita tres jobs de video y dos chats. Un chat escribe el guion en JSON, tres jobs de video se ejecutan en paralelo, uno por escena, cada uno diciendo su frase con la voz del mismo narrador, y un último chat une los clips con ffmpeg en el propio espacio de trabajo de la cuenta. El Short de abajo, sobre la erupción del monte Tambora en 1815 y el “año sin verano” que le siguió, pasó de un tema de una línea a un MP4 en unos 2 minutos.
También en YouTube: A narrated 30-second Short made only with Meta Muse API calls.
Tres clips de 10 segundos unidos en un Short de 720×1280 y 30 segundos, a partir del tema “how a single volcano cooled the whole planet in 1816”.
El guion tardó 11 segundos, los tres clips 75, 75 y 87 segundos ejecutándose a la vez, y la unión 20 segundos, así que un Short tarda unos 2 a 3 minutos. Este se hizo con un plan de pago de Muse. Ahí, los cuatro videos de esa sesión de pruebas (estos tres y uno más) movieron la lectura semanal 2 puntos en total, y los chats ninguno. En el plan gratuito un video consume del 2 al 3 por ciento de la semana, así que un Short de tres escenas cuesta allí entre un 6 y un 9 por ciento.
Sin código: el mismo flujo es una app de n8n, la plantilla Narrated Faceless Shorts, con un formulario, una página de guion y guardado en Google Drive. Dos Shorts que hizo, publicados tal como salieron: The Great Pyramid was once bright white y Why honey never spoils, que narró con el texto a voz de Muse.
El flujo completo también es un solo script, en Node.js y Python: narrated-short/ en useapi/muse-api. Recibe un tema y, opcionalmente, el número de escenas y tu propia descripción del narrador, y guarda el Short en output/.
Los pasos usan las funciones auxiliares de arriba más chat, que inicia un chat y lee GET /chats/chatId hasta que Muse termina:
Abrir la función auxiliar de chat
# inicia un chat, consulta GET /chats/{chatId} cada 8 s hasta que Muse termine y guarda el chat en $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"
}
Cada solicitud de abajo fija email. Un chat que recibe archivos debe ejecutarse en la cuenta que los tiene, así que los tres clips y la unión se quedan en una sola cuenta.
1. Escribir el guion en JSON
El primer chat pide exactamente tres escenas y detalla la forma del JSON. Cada escena tiene una line, lo que dice el narrador, limitada a 25 palabras para que quepa en 10 segundos, y un visual, una frase que describe la toma. El prompt también le dice a Muse que no cree ningún archivo, así que el chat se queda en texto.
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 respondió en 11 segundos solo con el 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."
}
]
}
Ejecutamos el mismo prompt con tres temas y obtuvimos un JSON limpio cada vez, en 11 a 29 segundos, sin bloques de código y sin texto extra. Es una muestra pequeña, así que el sed quita de todos modos una línea suelta de cierre ```, y el script de GitHub vuelve a pedirlo cuando la respuesta no se puede analizar.
2. Tres escenas a la vez
Cada escena se convierte en un POST /jobs/video asíncrono. Los tres prompts llevan la misma descripción del narrador, palabra por palabra, seguida de The narrator says exactly: "<line>". Muse dice una frase entre comillas tal como está escrita, y la descripción compartida mantiene la voz constante de un clip a otro. Vertical 9:16 video llegó en 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
Cada POST responde 201 al instante con un jobid. Los tres jobs ocupan tres de los espacios maxJobs de la cuenta (10 por defecto), así que se ejecutan en paralelo. Un 429 aquí significa que todos los espacios están ocupados y no se inició nada: vuelve a enviar ese job en 30 segundos.
3. Consultar los jobs
GET /jobs/jobid responde status: "started" hasta que el clip está listo. Los jobs corren en paralelo, así que leerlos uno tras otro no agrega tiempo:
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
Los tres terminaron. Sobre el primero, Muse dijo “Here it is — vertical 9:16, photoreal volcanic eruption at dawn with the narration as specified”. Cada clip dice su frase palabra por palabra, y cada frase, de 20 a 21 palabras, cupo en sus 10 segundos. Un job que falló con 503 no generó nada y se puede volver a ejecutar. Cualquier otro fallo, como un rechazo 403, requiere revisar primero error.message.
4. Unir los clips en un chat
Los ids de los tres clips entran en un solo chat como files, donde Muse los ve como video_1, video_2 y video_3. El mensaje pide ffmpeg, el orden, el audio y un nombre de archivo, y termina con No public links. Con esa línea, Muse no se detuvo a pedir permiso.
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 segundos después Muse dijo “Concatenated all three in order — 30 seconds, 720x1280, with audio kept.” y adjuntó el archivo en un mensaje propio, con un video en sus files. Su asset id lleva el nombre de la ruta en el espacio de trabajo, así que dale a cada Short su propio nombre de archivo. ffmpeg copió las pistas sin volver a codificarlas: el Short dura exactamente 30,0 segundos, y las tres frases están en él, en orden.
5. Descargar el Short
GET /assets/assetId devuelve el MP4:
curl — GET /assets/assetId
download "$SHORT" tambora-short.mp4
Los clips y el Short también se quedan en el espacio de trabajo de Muse de la cuenta, donde los muestra la app de muse.ai, y el asset id del Short puede entrar en el siguiente job como video_1.
Una voz fija: texto a voz como audio_1
Una descripción compartida da el mismo tipo de voz, no una voz fija. En los tres clips de Tambora, el tono mediano del narrador fue de 105 a 117 Hz, a menos de dos semitonos de distancia, pero Muse vuelve a crear la voz en cada clip. Para tener con seguridad una sola voz, haz que Muse diga primero cada frase con su texto a voz y luego pasa ese MP3 al job de video como audio_1. El chat de texto a voz tardó 20 segundos en nuestra prueba.
curl — POST /chats y 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 genera su clip y luego le pone audio_1 encima con ffmpeg. El job lista los dos archivos: primero la copia terminada, con origin: "made", y después el clip original de Muse, con origin: "generated". Toma el made. El clip original lleva una voz que Muse inventó en lugar de la tuya. El job de video tardó 108 segundos en nuestra prueba. Repítelo para cada escena y une los clips made como en el paso 4.
Preguntas frecuentes
¿Existe una API para Meta Muse (muse.ai)? Con useapi.net, sí: la Muse API es una API de terceros que ejecuta Muse con tu suscripción al sitio web de Muse. Genera imágenes con POST /jobs/image y videos con POST /jobs/video. La Model API oficial de Meta vende el modelo Muse Image a US$0,01 por imagen, pero, a octubre de 2026, no tiene generación de video ni una API para el agente Muse de muse.ai, donde se hacen los videos. Nuestra comparación de API de video de Meta Muse (en inglés) también cubre muse2api.
¿Funciona con el plan gratuito de Muse? Con useapi.net, sí: este recorrido se hizo con el plan gratuito (HATCH_FREE), que tiene una cuota semanal. Un video consumió del 2 al 3 por ciento de ella y una imagen del 0 al 1 por ciento, así que una cuenta gratuita genera más o menos de 30 a 50 videos por semana. Los planes de pago Power (US$20 al mes) y Maximum (US$100 al mes) aumentan la cuota (a octubre de 2026).
¿Muse puede hacer un video de más de 10 segundos? Con useapi.net, no en un solo job: cada video dura unos 10 segundos. Genera un clip por escena y haz que un chat los una con ffmpeg, como en Haz un Short narrado de 30 segundos, donde tres clips se convirtieron en un Short en unos 2 a 3 minutos. Un chat recibe hasta 3 videos.
¿Cómo defino la relación de aspecto, la duración o la resolución? Con useapi.net, en el prompt, porque Muse no tiene parámetros para eso. La relación de aspecto se respeta cuando se escribe como in exactly 16:9 aspect ratio, y un clip de imagen a video conserva el formato de su imagen salvo que el prompt pida otro. La duración y la resolución son fijas: cada video llega en unos 720p con sonido, pida lo que pida el prompt.
¿Puedo usar mis propias fotos y videos? Con useapi.net, sí: súbelos con POST /assets, hasta 50 MB cada uno, y pasa el assetId como image_1..image_9, igual que pasas el resultado de un job anterior. Los jobs de video también reciben video_1..video_3 y audio_1..audio_3. Todas las entradas de un job deben estar en la misma cuenta.
¿Cómo hago que una foto hable? Con useapi.net, pasa la foto como image_1 a POST /jobs/video con un prompt como Animate image_1: … she says softly: "…". Muse conserva el formato de la foto y dice la frase entre comillas, como en el paso 7, donde un retrato restaurado de cien años levanta la mirada y habla.
¿Puede reemplazar a una persona en un video? Con useapi.net, sí: pasa el clip como video_1 y una foto de la nueva persona como image_1, y pídele a Muse que reemplace a la persona y conserve todo lo demás, como en el paso 8. Di lo que debe seguir igual, como el paseo, el puente y las olas, y dale a la nueva persona una frase entre comillas si debe hablar.
¿Por qué mi solicitud síncrona devolvió 202? Con useapi.net, un 202 significa que el job seguía en curso después de unos 100 segundos, y sigue ejecutándose de nuestro lado. Consúltalo con GET /jobs/jobid, envía los jobs largos con async: true y consulta, o agrega un replyUrl para que te envíen el registro del job terminado. En nuestras pruebas, un video tardó de 68 a 138 segundos.
¿Por qué Muse me envió un código de inicio de sesión por correo? Con useapi.net, la API inició sesión en tu cuenta de Muse, lo que ocurre cuando la agregas y cuando la API renueva la sesión de 30 días, antes de que venza o cada vez que Muse pide un nuevo inicio de sesión. Muse envía un código por correo en cada inicio de sesión, y no hay que hacer nada con él. Consulta Setup Muse.
¿En qué se diferencia de muse2api? Con useapi.net, la Muse API está alojada, así que no hay nada que desplegar: agregas cada cuenta con su correo y contraseña y nosotros mantenemos la sesión iniciada. Los resultados se encadenan por asset id, y un job terminado puede llamar a tu webhook. También puedes chatear con el agente Muse, con sus respuestas transmitidas en vivo. muse2api es un proyecto que despliegas, alojas y mantienes en marcha tú mismo.
Conclusión
Visita nuestro servidor de Discord o nuestro
canal de Telegram para cualquier pregunta de soporte.
Consulta nuestro repositorio de GitHub con ejemplos de código.
Las mismas llamadas están disponibles como herramientas en el servidor MCP de Muse alojado, para Claude Code, Cursor y VS Code.
Publicado también en
También publicado en dev.to, comentado en Reddit, compartido en Bluesky y en YouTube como una demo de 2:49 de toda la API (todos en inglés).
Empieza a usar la API
Una sola suscripción de US$15 al mes cubre todas las API de useapi.net: un token para todos los servicios. Conectas hasta 3 cuentas propias por servicio, cada una con la suscripción de su sitio web, y useapi.net se encarga de la API REST, el balanceo de carga y el polling. ¿Necesitas más cuentas? Cada suscripción adicional cuesta US$10 al mes y suma 3 cuentas más por servicio.
Suscríbete — US$15/mes Pagar con cripto
¿No tienes una tarjeta de crédito internacional? También puedes suscribirte con criptomonedas (los pagos con cripto no se reembolsan). Los precios y los planes por volumen están en la página de suscripción. Si pagas con Stripe, recibes el reembolso completo dentro de los 14 días posteriores a la primera compra, si tienes menos de 50 generaciones exitosas. ¿Ya tienes una suscripción? Cambia la cantidad en el portal de clientes de Stripe en lugar de volver a comprar.
