API de subida y cover en un paso
Descripción del endpoint
Subida y cover en un paso envía un archivo de audio o una URL de audio y genera una nueva versión de cover a partir de ese audio de origen.
Endpoint: POST /api/music/upload-cover
Facturación: De pago, actualmente 0,6 ¥ por llamada por defecto. Este endpoint es «subir y hacer el cover», no se trata de subir una portada de imagen. 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 (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.
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% tardan 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.
Cuando el audio es grande, conviene separar «subida» y «cover» en dos pasos (recomendado)
Este endpoint exige que todo el audio vaya en el cuerpo de la petición: cuanto más grande el audio, más grande el cuerpo, y un solo problema de red o un timeout corta la transferencia a medias, tras lo cual el servidor devuelve
unexpected end of JSON input(HTTP 400, sin cargo).Cuando el audio supera unos 8 MB, la red es inestable o el mismo material de origen se va a reutilizar, pasa a la forma en dos pasos:
POST /api/music/upload-sourcesube primero el audio de origen — gratis, se puede reintentar en cualquier momento — y devuelve unclip_id;POST /api/music/generate-from-sourcelanza el cover con eseclip_id— el cuerpo del paso que se cobra tiene solo unos 250 bytes.Consulta la API de subida de audio de origen, la API de cover desde un clip de origen y «Archivos grandes y peticiones truncadas» al final de esta página.
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 |
|---|---|---|---|---|
| model | string | no | suno-v6 | Nombre de modelo de cara al cliente: suno-v6, suno-v6-wild o suno-v6-mini |
| file_url | string | no | - | URL del audio de origen |
| file_base64 | string | no | - | Audio en Base64 |
| file_name | string | no | - | Nombre del archivo |
| prompt | string | no | - | Letra nueva o dirección de la adaptación |
| style | string | no | - | Etiquetas de estilo |
| title | string | no | - | Título |
| negativeTags | string | no | - | Estilo negativo |
| instrumental | boolean | no | false | Si la canción es instrumental |
| waitAudio | boolean | no | false | Si se espera a que el audio termine |
| cover_start_s | number | no | - | Segundo de inicio del fragmento que se va a versionar |
| cover_end_s | number | no | - | Segundo de fin del fragmento que se va a versionar |
| audio_weight | number | no | - | Dependencia del audio de referencia, rango 0.0-1.0; solo puede enviarse cuando se aporta un audio de referencia |
cover_start_s y cover_end_s están en segundos y admiten decimales; el tiempo de inicio debe ser menor que el de fin y no puede superar la duración del audio de origen. Si se omiten ambos campos, se usa el audio completo. audio_weight se corresponde con metadata.control_sliders.audio_weight de Suno y controla cuánto se apoya el resultado en el audio de referencia; toma valores 0.0-1.0 y solo puede incluirse cuando la petición aporta un audio de referencia válido en file_url o file_base64. 0 es un valor válido; omitir el campo significa "no especificado" y mantiene el comportamiento por defecto de Suno. instrumental y waitAudio deben ser booleanos JSON, no cadenas.
El endpoint de subida devuelve de forma asíncrona por defecto. Mientras clips[].status en la respuesta sea pending, que audio_url esté vacío es normal y no significa que la subida o el cover hayan fallado; guarda el song_id real que recibes y consulta el endpoint de consulta de canciones hasta que termine antes de leer la dirección del audio.
Ejemplo de petición
curl -X POST https://www.suno-api.io/api/music/upload-cover \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"file_url": "https://example.com/source.mp3",
"file_name": "source.mp3",
"prompt": "Letra nueva o dirección de la adaptación",
"style": "Mandopop, acoustic guitar",
"title": "Versión cover",
"negativeTags": "noise, low quality",
"audio_weight": 0.5,
"instrumental": false,
"waitAudio": false,
"cover_start_s": 0,
"cover_end_s": 60
}'
Respuesta
{
"code": 200,
"message": "success",
"data": {
"upload": {
"clip_id": "uploaded_clip_id",
"status": "complete"
},
"clips": [
{
"song_id": "new_clip_id",
"song_title": "Versión cover",
"status": "pending"
}
]
}
}
Archivos grandes y peticiones truncadas
Recomendado: dividir subida y cover en dos pasos
El endpoint de una sola vez (este) une subida y generación en un único paso: el cuerpo grande está en ese único paso, así que cuando se rompe no sabes si se generó algo ni si se cobró.
| Paso 1 subida | Paso 2 cover | |
|---|---|---|
| Endpoint | POST /api/music/upload-source |
POST /api/music/generate-from-source |
| Facturación | Gratis (solo sube, no genera) | 0,6 ¥ por llamada; 1,2 ¥ por llamada con Max Mode |
| Cuerpo de la petición | El audio en sí (base64 / multipart), o solo un enlace con file_url |
Unos 250 bytes (solo un sourceClipId) |
| Devuelve | clip_id (el clip ID del audio de origen) |
data.clips[].song_id (el resultado generado) |
| Si falla | Reintenta sin más, sin cargo y sin tarea de generación | Fija el timeout del cliente en ≥300 s; ante un timeout consulta primero con /api/music/songs y no reintentes de inmediato |
| Reutilizar el material de origen | El mismo clip_id sirve también para extender / reemplazar / separar |
Hay que volver a subir el audio cada vez |
Conclusión: audio de más de unos 8 MB, red inestable o el mismo material usado varias veces → usa la forma en dos pasos; audio diminuto con red estable → este endpoint da menos trabajo.
Qué significa 400 unexpected end of JSON input
Significa que el JSON que recibió el servidor está incompleto (no es un parámetro mal escrito, ni un problema de permisos o de saldo). Las causas habituales, de más a menos probable:
- Un cuerpo grande truncado a mitad de transferencia: la capa de entrada registra tanto «cuántos bytes declaró el cliente» como «cuántos llegaron de verdad». Caso medido: el cliente declaró 14,17 MB y solo llegaron 11,8–12,4 MB, y las tres peticiones se detuvieron hacia 1,6–1,7 s; el número de bytes que faltaban era distinto cada vez, lo que apunta a un corte de transferencia y no a un límite fijo (el servidor no limita el tamaño del cuerpo).
Content-Lengthque no coincide con los bytes realmente enviados: en Node.js, usar el.lengthde una cadena (recuento de caracteres UTF-16) como longitud calcula mal en cuanto el contenido lleva chino u otro texto multibyte.- Escribir el cuerpo como cadena en lugar de Buffer, con lo que los bytes escritos no coinciden con lo declarado.
Los tres casos ocurren antes del cobro, así que no generan ningún cargo.
Lista de autocomprobación del cliente
-
Content-Lengthsale deBuffer.byteLength(json, 'utf8')(oBuffer.from(json).length) — nunca dejson.length; - El cuerpo de la petición se escribe como Buffer, no como cadena;
- El timeout del socket / de la petición es ≥ 300 segundos;
- Cuando el audio supera unos 8 MB: usa
file_url(el cuerpo son unos cientos de bytes), o la subida multipart deupload-source, o pasa directamente a la forma en dos pasos; - En las peticiones multipart, no configures
Content-Typea mano (deja que el cliente añada el boundary); - Imprime los «bytes realmente enviados» y compáralos con
Content-Length; - En la forma en dos pasos, confirma que el paso 1 devolvió un
clip_idconstatuscompletado antes de enviar el paso 2.
Errores frecuentes
| Error | Significado | Qué hacer |
|---|---|---|
unexpected end of JSON input |
Cuerpo de la petición incompleto (truncado) | Repasa la autocomprobación anterior, o pasa a la forma en dos pasos |
invalid character '-' in numeric literal |
Se envió un cuerpo multipart a un endpoint JSON | No uses multipart en endpoints JSON, o no configures Content-Type a mano |
one of file_path, file_base64, file_url, or multipart file is required |
No se aportó audio | Añade file_base64 / file_url / un file multipart |
model is required |
El cuerpo era JSON válido pero vacío (por ejemplo {}) |
Envía al menos model |
Invalid request: Invalid request, ... |
Mensaje envoltorio de un cuerpo que no se pudo analizar | Lee la segunda mitad para ver el motivo concreto (normalmente uno de los anteriores) |
Endpoints relacionados: API de subida de audio de origen (paso 1), API de cover desde un clip de origen (paso 2).
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