API de generación en modo simple
Descripción del endpoint
La generación en modo simple sirve para convertir una descripción de una frase en una canción completa. El servicio escribe la letra, la melodía, el arreglo y la voz a partir de tu descripción.
Endpoint: POST /api/music/create
Facturación: De pago, actualmente 0,6 ¥ por llamada por defecto. Cada llamada suele devolver 2 canciones; el importe realmente cobrado sigue la configuración de precios actual del back-office.
Max Mode / Variety: este endpoint admite los parámetros opcionales max_mode y variety (0-4). Con
max_mode activado, esta llamada se factura al doble de precio (0,6 ¥ → 1,2 ¥ por llamada); variety no cuesta
nada extra. Qué significan y cómo enviarlos está en la sección «Parámetros avanzados» del
Resumen de la nueva API.
Modelo recomendado: suno-v6
Tiempos de espera y timeouts (importante): es un endpoint síncrono — el pedido solo se acepta y se entrega a generación cuando llega la respuesta. Según lo medido, la mayoría de las peticiones responden en 1-3 segundos, alrededor del 10% tarda más de 30 segundos y la más lenta ronda los 230 segundos. Configura el timeout del cliente en 300 segundos o más; no recibir respuesta no significa que no se haya generado nada, y no reintentes justo después de un timeout (eso duplica el pedido y vuelve a cobrar). Si la conexión se cayó, confírmalo más tarde con
GET /api/music/songs. Consulta «Tiempos de espera y configuración de timeout» en el Resumen de la nueva API.
Parámetros de la petición
Headers
| Parámetro | Tipo | Obligatorio | Notas |
|---|---|---|---|
| Authorization | string | sí | Bearer YOUR_API_KEY |
| Content-Type | string | sí | application/json |
Parámetros del body
| Parámetro | Tipo | Obligatorio | Por defecto | Notas |
|---|---|---|---|---|
| description | string | sí | - | Descripción de la canción, en cualquier idioma; como máximo 3000 caracteres (más devuelve 400 y no se cobra) |
| model | string | no | suno-v6 | Nombre de modelo para el cliente: suno-v6, suno-v6-wild o suno-v6-mini |
| instrumental | boolean | no | false | Si la canción es solo instrumental |
| wait_completion | boolean | no | false | Si esperar a que termine la generación antes de responder |
| references | array | no | - | Lista de material de referencia, que puede llevar canciones de referencia / voces heredadas / imágenes de referencia; como máximo 5 canciones, 1 voz y 1 imagen. Ver «Material de referencia references (opcional)» más abajo |
Ejemplos de petición
curl -X POST https://www.suno-api.io/api/music/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"description": "una canción pop en mandarín animada sobre el verano junto al mar",
"instrumental": false,
"wait_completion": false
}'
Material de referencia references (opcional)
references es un array que adjunta «material de referencia» a esta generación. Es totalmente opcional (omitirlo se comporta exactamente igual que antes) y puedes adjuntar solo un tipo o cualquier combinación.
Tipos de elemento
| type | Campo obligatorio | Campos opcionales | Máximo | Notas |
|---|---|---|---|---|
song |
song_id |
style_prompt, lyrics, duration_s |
5 | Canción de referencia; el song_id viene de la API de consulta e historial de canciones y la canción debe estar ya completada |
voice |
voice_id |
- | 1 | Voz heredada; el voice_id viene de la API de clonación de voz y generación con voz |
image |
base64 |
- | 1 | Imagen de referencia; envía contenido base64 con la forma data:image/jpeg;base64,... |
Reglas
- El orden de las canciones de referencia es su orden semántico: pásalas en el orden que quieras expresar (por ejemplo «melodía de la primera, voz de la segunda»).
style_prompt/lyrics/duration_spueden omitirse; la plataforma los completa desde la información de la canción y lo que envíes tú prevalece.- En canciones puramente instrumentales,
lyricspuede ser""o"[Instrumental]". - Las imágenes de referencia admiten
jpeg/png/webp, hasta 10MB cada una, enviadas con el cuerpo de la petición en base64. - Cuando adjuntes varias canciones de referencia, usa también
accept_mode=async(ver «Modo de recibo de aceptación» arriba): el servicio debe preparar primero el material de referencia, así que una espera síncrona puede ser larga.
Ejemplo: dos canciones de referencia
curl -X POST https://www.suno-api.io/api/music/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"description": "combina estas ideas en una sola canción",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "song", "song_id": "a90438d2-35fc-4443-88f4-56531e6e5d24" }
]
}'
Ejemplo: canción de referencia + voz heredada
{
"model": "suno-v6",
"description": "canta estas ideas con esta voz",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "voice", "voice_id": "5813cbe1-36f1-414a-a9a8-4d399dfeb292" }
]
}
Ejemplo: canción de referencia + imagen de referencia
{
"model": "suno-v6",
"description": "captura el ambiente de esta imagen",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "image", "base64": "data:image/jpeg;base64,/9j/4AAQ..." }
]
}
Errores de parámetros
Estos casos devuelven HTTP 400, bloqueados antes de cualquier cobro, así que no cuestan nada:
| Caso | Mensaje de error |
|---|---|
| Más de 5 canciones de referencia | references supports at most 5 song references |
| Más de 1 voz | references supports at most 1 voice reference |
| Más de 1 imagen de referencia | references supports at most 1 image reference |
type no válido |
references[0].type must be one of song, voice, image |
Canción sin song_id |
references[0].song_id is required |
| Canción aún no terminada | references[0].song_id must be a real completed clip |
| La misma canción repetida | references[0].song_id is duplicated |
El número en
references[0]es el índice de ese elemento en el array, así que el elemento que falla es fácil de localizar.
Respuesta
Un array de canciones, que normalmente contiene 2 tareas o canciones.
[
{
"song_id": "clip_id",
"song_title": "Brisa marina de verano",
"status": "pending",
"description": "una canción pop en mandarín animada sobre el verano junto al mar",
"audio_url": "",
"cover_url": "",
"video_url": "",
"model_version": "suno-v6",
"generation_type": "generate",
"created_at": "2026-05-21T10:00:00Z"
}
]
Modo de recibo de aceptación (opcional, recomendado para clientes que no deben mantener conexiones largas)
Por defecto este endpoint es síncrono: que llegue la respuesta es lo que significa que el pedido fue aceptado, y las esperas medidas pueden llegar a unos 230 segundos. Si tu cliente no debe mantener una conexión larga, activa el modo de recibo de aceptación — sirve cualquiera de las dos:
- añadir
"accept_mode": "async"al cuerpo de la petición - añadir la cabecera
X-Accept-Mode: async
Con él activado, el endpoint devuelve HTTP 202 inmediatamente, lo que solo significa «aceptado y en cola de generación», mientras la generación continúa en segundo plano:
{
"success": true,
"data": {
"request_id": "ac_20260920092714315816800d76fv3nq",
"status": "queued",
"accepted_at": 1789896434,
"pre_consumed_quota": 300000,
"tasks": [
{ "index": 0, "status": "queued" },
{ "index": 1, "status": "queued" }
]
}
}
La fase de aceptación no devuelve un
song_id. Todavía no existe un ID de canción real, y nirequest_idnitasks[].indexson un ID de canción — no los guardes comosong_id. Elsong_idreal aparece en la consulta de progreso de abajo.
Consultar el progreso de aceptación
Endpoint: GET /api/music/requests/{request_id} (gratis, se autentica con la misma clave de API)
curl "https://www.suno-api.io/api/music/requests/ac_20260920092714315816800d76fv3nq" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"request_id": "ac_20260920092714315816800d76fv3nq",
"status": "processing",
"tasks": [
{ "index": 0, "status": "processing", "song_id": "f3fa09f5-3d55-4953-826c-0d23f043ec57" },
{ "index": 1, "status": "processing", "song_id": "5fcafe3e-3fae-4d64-8f66-c01bc027b0c3" }
]
}
}
Qué significa cada valor de status:
| status | Significado |
|---|---|
queued |
Aceptado, aún sin vincular a canciones concretas (tasks puede ser un array vacío) |
processing |
Enviado a generación |
partial |
Una de las dos ya ha terminado |
completed |
Las dos han terminado, tasks[].song_id es legible |
failed |
El envío falló, el importe se ha reembolsado por completo y error_message indica el motivo |
Cada tarea tiene además su propio tasks[].status, con los mismos valores que la API de consulta de canciones:
pending (enviada, generando), processing, completed, failed. Los elementos de tarea también pueden traer title,
duration y un audio_url ya registrado; si falta algo, simplemente significa que aún no está generado.
Cuando tengas el song_id real, continúa con la API de consulta de canciones o los endpoints de descarga.
Ejemplo en Python
import time
import requests
BASE = "https://www.suno-api.io"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"}
accepted = requests.post(
f"{BASE}/api/music/create",
headers={**HEADERS, "Idempotency-Key": "your-own-unique-key"},
json={"description": "una canción pop animada", "model": "suno-v6", "accept_mode": "async"},
timeout=300,
).json()["data"]
request_id = accepted["request_id"]
while True:
time.sleep(5)
progress = requests.get(
f"{BASE}/api/music/requests/{request_id}", headers=HEADERS, timeout=60
).json()["data"]
if progress["status"] in ("completed", "failed"):
print(progress)
break
Compatibilidad y notas
- Sin
accept_mode, el comportamiento es exactamente el de antes: espera síncrona, devolviendo200y un array de canciones. Las integraciones existentes no necesitan cambiar código. - Este interruptor hoy solo funciona en
POST /api/music/createyPOST /api/music/create/custom; los demás endpoints de generación aún no lo admiten. - Envía también un
Idempotency-Key(tu propia cadena única, ≤128 caracteres): enviar la misma clave dos veces se acepta una sola vez, una repetición devuelve el mismo recibo y no se cobra dos veces. Esto importa aún más en modo asíncrono. - Con
accept_mode=async,wait_completionse ignora (el recibo vuelve de inmediato sin esperar las canciones). - El importe se sigue preconsumiendo cuando se acepta el pedido; una generación fallida se reembolsa por completo de forma automática.
- Límite del campo de texto:
descriptionadmite como máximo 3000 caracteres (contados en caracteres Unicode, un carácter Han cuenta como 1). Un texto más largo devuelve HTTP400directamente, nunca entra en generación y no se cobra, y el mensaje de error lleva la longitud medida, por ejemplodescription must not exceed 3000 characters; received 4120. Este endpoint no tiene campos de letra/estilo; para eso mira «Límite del campo de texto» en la API de generación en modo personalizado. Las convenciones generales están en «Límites de campos de texto» del Resumen de la nueva API. - Sin
references, el comportamiento, el precio y la respuesta son exactamente los de antes: las integraciones existentes no necesitan cambiar código. - Cuando se adjunta material de referencia (sobre todo varias canciones), prefiere el modo de recibo
accept_mode=asyncantes que una larga espera síncrona; cuánto tarda en prepararse el material depende de su cantidad y su origen.
Siguientes pasos
Si las canciones no han terminado cuando llega la respuesta, usa la API de consulta de canciones para obtener el resultado final.
Ejemplo de integración en Node/Electron
Si integras generación estándar dentro del proceso principal de Electron, un servidor Node.js o un cliente de escritorio, este es el flujo recomendado:
- Llama a
POST /api/music/createpara crear la tarea de generación. - Lee
song_idoidde la respuesta. - Llama a
POST /api/music/querycada 2 segundos para comprobar el estado. - Da la generación por terminada en cuanto aparezca
audio_urlen el resultado de la consulta.
Deja de usar las rutas antiguas POST /api/generate o GET /api/clip?id=...; no forman parte de la superficie pública de integración recomendada actualmente.
const http = require('http');
const https = require('https');
const BASE_URL = 'https://www.suno-api.io';
const MODEL = 'suno-v6';
const POLL_INTERVAL_MS = 2000;
const MAX_POLL_ATTEMPTS = 60;
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function requestJson(urlString, apiKey, body) {
const url = new URL(urlString);
const transport = url.protocol === 'https:' ? https : http;
const payload = JSON.stringify(body);
return new Promise((resolve, reject) => {
const req = transport.request(
{
method: 'POST',
hostname: url.hostname,
port: url.port || undefined,
path: `${url.pathname}${url.search}`,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload),
},
},
(res) => {
let raw = '';
res.setEncoding('utf8');
res.on('data', (chunk) => {
raw += chunk;
});
res.on('end', () => {
const data = raw ? JSON.parse(raw) : {};
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
reject(new Error(`Suno API request failed: HTTP ${res.statusCode} ${raw}`));
return;
}
resolve(data);
});
}
);
req.on('error', reject);
req.write(payload);
req.end();
});
}
function getPayload(response) {
return response && response.data !== undefined ? response.data : response;
}
function toSongList(payload) {
if (Array.isArray(payload)) return payload;
if (Array.isArray(payload?.songs)) return payload.songs;
if (Array.isArray(payload?.clips)) return payload.clips;
return payload ? [payload] : [];
}
function collectSongIds(createResponse) {
return toSongList(getPayload(createResponse))
.map((song) => song.song_id || song.id)
.filter(Boolean);
}
async function generateSunoSong({ apiKey, description, instrumental = false }) {
const createResponse = await requestJson(`${BASE_URL}/api/music/create`, apiKey, {
description,
model: MODEL,
instrumental,
wait_completion: false,
});
const songIds = collectSongIds(createResponse);
if (songIds.length === 0) {
throw new Error(`Suno API did not return song ids: ${JSON.stringify(createResponse)}`);
}
for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt += 1) {
await sleep(POLL_INTERVAL_MS);
const queryResponse = await requestJson(`${BASE_URL}/api/music/query`, apiKey, {
song_ids: songIds,
model: MODEL,
});
const songs = toSongList(getPayload(queryResponse));
const completed = songs.find((song) => song.audio_url);
if (completed) {
return {
audioUrl: completed.audio_url,
title: completed.song_title || completed.title || 'Suno Song',
duration: completed.duration,
};
}
const allFailed = songs.length > 0 && songs.every((song) =>
['failed', 'error', 'rejected'].includes(String(song.status || '').toLowerCase())
);
if (allFailed) {
throw new Error(`Suno generation failed: ${JSON.stringify(songs)}`);
}
}
throw new Error('Suno generation timed out after 120 seconds. Please query again later.');
}
// Usage:
// generateSunoSong({
// apiKey: process.env.SUNO_API_KEY,
// description: 'A bright pop song about the ocean in summer',
// }).then(console.log).catch(console.error);
En proyectos reales, guarda la clave de API en una variable de entorno del servidor, en los ajustes de un cliente de escritorio o en almacenamiento seguro — nunca en código de front-end ni en un repositorio.
Obtener una clave de API
Crea una clave de API en la consola después de registrarte. Cada generación cuesta 0,6 ¥ y devuelve 2 pistas, las descargas son ilimitadas y no hace falta número de teléfono.
Obtener clave de API Volver al resumen