API de calibración de marcas de tiempo de la letra
Esto no es reconocimiento de voz. El texto usa siempre la letra original que tú aportas; nosotros solo colocamos cada carácter en el instante correcto — así nunca ocurre eso de "caracteres mal oídos que descuadran la letra".
Descripción del endpoint
Alinea una letra existente con un audio y devuelve marcas de tiempo por línea y por carácter, para resaltado carácter a carácter tipo karaoke, letra con desplazamiento y generación de subtítulos.
Endpoint: POST /api/music/lyrics-align
Autenticación: consulta Autenticación; la cabecera es Authorization: Bearer YOUR_API_KEY
Facturación: se cobra por llamada (actualmente 0,1 ¥ por llamada por defecto); si en una canción de la plataforma marcas la separación de voz, se cobra una vez más al precio de "separación de voz/acompañamiento". El importe realmente cobrado sigue la configuración de precios del back-office.
Tiempo medio: 5–15 segundos (según la duración del audio y si hay que separar la voz al momento)
Por qué hace falta calibrar: las marcas del lado generador no siempre son exactas
La API de letras con marcas de tiempo devuelve directamente las marcas palabra a palabra del lado generador y tienen imprecisiones:
- las repeticiones, las armonías densas, el rap y las notas largas suelen desviarse en conjunto o desplazar caracteres sueltos;
- a algunas canciones les falta un tramo al principio (por ejemplo una intro pura, con el primer fragmento empezando ya en la adolescencia del tiempo);
- algunas líneas son difíciles de anclar a un instante claro.
La calibración rehace la alineación temporal sobre la letra que tú aportas: solo se corrige el tiempo, nunca el texto, lo que encaja en casos donde importa que "cuadre" (resaltado por carácter tipo KTV, subtítulos por carácter, puntuación de canto).
Enfoque recomendado (tres pasos, mejor resultado)
- Extrae primero la voz (separación voz/acompañamiento) y alinea solo la pista de voz: el acompañamiento y las armonías dejan de interferir. Base medida: en una comparación línea a línea de "mezcla completa vs pista de voz" de la misma canción, 5 de 28 líneas diferían más de 0,25 s (la mayor, 2,64 s); dos motores independientes diferían de media 0,239 s en la pista de voz y 0,508 s en la mezcla completa — casi la mitad de concordancia. Por eso, para resaltado por carácter (KTV/subtítulos) se recomienda activarlo. (La mejora exacta se está midiendo de nuevo con el motor nuevo.)
- Aporta la letra completa: la canción entera, línea a línea, correspondiendo uno a uno con el audio. Si falta una frase o una sección, todas las líneas posteriores se desplazan; no incluyas marcas como
[00:23.82]en la letra (se ignoran automáticamente). - En una canción de la plataforma basta con marcar
vocal_separate: truey hacemos "separación + alineación" en un solo paso.
Tres formas de usarlo
| Uso | Qué envías | De dónde sale la letra | Separación de voz |
|---|---|---|---|
| Canción externa · URL pública | audio_url + letra |
La aportas tú | ❌ No admitido |
| Canción externa · subida directa de un archivo local (nuevo en 2026-10) | audio_object_key + letra |
La aportas tú | ❌ No admitido |
| Canción de la plataforma (generada en este sitio) | song_id |
La tomamos del registro de la canción | ✅ Opcional |
Cómo se relacionan los parámetros (es lo que más se falla: léelo con atención)
- Enviar
song_id→ ruta de canción de la plataforma: no envíes ademáslyrics/audio_url/audio_object_key; - Enviar
audio_urloaudio_object_key→ ruta de canción externa: solo uno de los dos y no envíessong_id; vocal_separatesolo funciona con canciones de la plataforma; si lo envías en una canción externa se rechaza (el audio no está en nuestro lado, no se puede separar).
Nuevo: subida directa de un archivo local (el audio no pasa por nuestros servidores)
Úsalo cuando el audio está en tu máquina y prefieres no subirlo antes a tu propio almacenamiento público. Dos pasos:
POST /api/music/lyrics-align/upload-ticketconfile_name/file_size/content_typey recibes unaput_url(URL firmada, sin credenciales de larga vida) y unobject_key;- Haz
PUTdel archivo aput_url, llevando elcontent_typede la respuesta tal cual (participa en la firma; un carácter cambiado devuelve 403); - Al enviar la alineación, manda
audio_object_keyen lugar deaudio_url.
La credencial es de un solo uso: al terminar la alineación (éxito o fallo) el servidor borra el objeto y reutilizar la misma clave da error.
Nuevo: la letra ahora es opcional
Antes una canción externa exigía letra. Ahora puedes omitirla: el servidor hace un reconocimiento y usa el texto reconocido como letra.
Hay que decirlo con claridad: el texto pasa a depender del resultado del reconocimiento, así que algún carácter puede ser incorrecto. Esas respuestas se marcan con
lyrics_source: "asr", confidence: "low" y, en warnings[],
{"code":"no_reference_lyrics"}.
Para resaltado por carácter / KTV, aporta siempre la letra original.
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 |
|---|---|---|---|---|
| song_id | string | uno de dos | - | ID de canción de la plataforma |
| lyrics | string | no | - | Letra original, líneas separadas por \n. Ahora puede omitirse |
| audio_url | string | uno de dos para externas | - | Dirección del audio; debe ser descargable públicamente |
| audio_object_key | string | uno de dos para externas | - | Clave del objeto subido directamente (llama antes a /lyrics-align/upload-ticket) |
| vocal_separate | boolean | no | false |
Si separar la voz primero (solo canciones de la plataforma) |
| language | string | no | automático | Chinese / English, etc.; si no se envía se deduce de la letra |
| granularity | string | no | both |
both / line (sin salida por carácter) / word |
| sections | string | no | keep |
keep conserva marcas como [Chorus] (no entran en la línea de tiempo) / drop |
| format | string | no | json |
json / lrc / lrc-word (los dos últimos devuelven también el texto lrc y lrc_word) |
Límites
| Elemento | Límite |
|---|---|
| Duración del audio | ≤ 6 minutos (más devuelve error y reembolso completo) |
| Origen del audio | Debe ser descargable públicamente; no se aceptan direcciones que requieran sesión |
| Formato de la letra | Texto plano, líneas con \n; las marcas de sección como [Verse] o 【主歌】 se conservan tal cual pero no entran en la línea de tiempo |
| Lotes | Una canción por llamada; para varias, haz tu propio bucle |
| Guardado del resultado | Este endpoint no persiste nada; guarda tú el resultado |
Ejemplos de petición
Canción externa (letra + dirección del audio)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"lyrics": "Caminando por calles frías\nLa brisa nocturna roza mis ojos\nEl tiempo fluye como el agua",
"audio_url": "https://your-bucket.example.com/song.mp3"
}'
Canción de la plataforma (sin separación)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"song_id": "17e52af7-b5df-4877-a98a-dce94e0e6aa2"}'
Canción de la plataforma + separación de voz (recomendado para karaoke)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"song_id": "17e52af7-b5df-4877-a98a-dce94e0e6aa2", "vocal_separate": true}'
Respuesta
Respuesta correcta
{
"success": true,
"lyrics_source": "platform",
"vocal_separate": false,
"coverage": 0.935,
"exact": 196,
"fuzzy": 4,
"total": 214,
"lines": [
{
"text": "Caminando por calles frías",
"start": 21.66,
"end": 24.06,
"chars": [
{"char": "C", "start": 21.66, "end": 21.74, "word": true},
{"char": "a", "start": 21.98, "end": 22.22, "word": true}
]
}
]
}
Referencia de campos
| Campo | Tipo | Notas |
|---|---|---|
success |
boolean | Si la petición tuvo éxito |
lyrics_source |
string | platform = letra tomada de la canción de la plataforma; user = letra aportada por ti; asr = no diste letra y el texto vino del reconocimiento |
vocal_separate |
boolean | Si esta vez pasó por separación de voz |
confidence |
string | high / low (siempre low cuando lyrics_source=asr) |
warnings[] |
array | Avisos de degradación; contiene {"code":"no_reference_lyrics"} cuando no hubo letra |
coverage |
number | Calidad de la alineación: proporción de caracteres con ancla temporal clara (0–1) |
exact / fuzzy / total |
number | Caracteres exactos / homófonos / caracteres válidos de la letra |
lines[].text |
string | Una línea de letra, carácter a carácter igual a tu original |
lines[].start / end |
number | Inicio y fin de la línea (segundos) |
lines[].section |
boolean | Si la línea es una marca de sección (true = sin tiempo y sin resaltado) |
lines[].chars[] |
array | Tiempos por carácter: char, start/end en segundos, word si entra en la línea de tiempo (la puntuación es false) |
words[] |
array | Lista plana por carácter: text / start / end / line; no se devuelve con granularity=line |
lrc |
string | Texto LRC por línea (solo con format=lrc o lrc-word) |
lrc_word |
string | LRC por carácter mejorado, con etiquetas <mm:ss.xx> en línea (solo con format=lrc-word) |
Cómo usar coverage (tres tramos)
| coverage | Uso sugerido |
|---|---|
| ≥ 0,9 | Sirve para resaltado por carácter (karaoke) |
| 0,8 – 0,9 | Mezcla por carácter y por línea, o resalta solo líneas y usa el carácter como referencia |
| < 0,8 | Solo resaltado por línea (repeticiones, armonías densas, dialectos y rap tienden a salir bajos) |
Estado y tiempos
| Escenario | Tiempo medido |
|---|---|
| Canción de plataforma · sin separación | unos 4,5 s |
| Canción de plataforma · separación (ya hay pista de voz) | unos 11 s |
| Canción de plataforma · separación (hay que separar al momento) | unos 25 s, hasta 1 minuto |
| Canción externa · letra + dirección del audio | unos 5–15 s (según la duración) |
El límite de una ejecución en el servidor es 8 minutos; configura el timeout del cliente en 120 segundos o más.
Respuestas de error
{
"success": false,
"message": "音频超过 6 分钟上限(实际 7.2 分钟)"
}
| Escenario | ¿Se cobra? |
|---|---|
| Falta el audio (no se envía ninguno de los tres) | No se cobra (no se inició el proceso) |
audio_url y audio_object_key a la vez |
No se cobra (no se inició el proceso) |
| El objeto subido aún no está o ya se borró | No se cobra (no se inició el proceso) |
granularity / sections / format inválidos |
No se cobra (no se inició el proceso) |
| La canción de la plataforma no existe / no es de la cuenta actual | No se cobra (no se inició el proceso) |
| Parámetros ausentes o inválidos | No se cobra (no se inició el proceso) |
| Audio por encima del límite de 6 minutos | Reembolso completo |
| Audio no descargable (dirección no pública / requiere login) | Reembolso completo |
| Sin letra y el reconocimiento del servidor falló | Reembolso completo |
| Marcaste separación de voz pero no hay pista usable | Reembolso completo (incluye el precio de la separación) |
| Fallo o timeout del servicio de alineación | Reembolso completo |
Principio: sin resultado final, reembolso completo. Solo se cobra cuando realmente se devuelven las marcas por carácter, y el reembolso es automático, sin solicitud.
Facturación
| Concepto | Cuándo se cobra | Notas |
|---|---|---|
| Calibración de marcas de la letra (base) | En cada llamada | Por llamada (actualmente 0,1 ¥ por llamada por defecto); el importe real sigue la configuración de precios del back-office |
| Recargo por transcripción | Solo si no aportas letra | El servidor debe ejecutar un reconocimiento de voz, un coste que el tramo "con letra" no tiene, así que se tarifa aparte |
| Separación de voz (opcional, solo canciones de la plataforma) | Al marcar vocal_separate |
Se cobra una vez al precio actual de "separación de voz/acompañamiento" y se liquida junto con este endpoint |
La combinación:
a pagar = precio base + (¿sin letra? recargo por transcripción : 0) + (¿separación marcada? precio de separación : 0)
La separación de voz se cobra una sola vez: si ya separaste y tienes la pista de voz disponible, la cobra este endpoint; si hay que separar al momento, la cobra el paso de separación.
Ejemplo completo (Python)
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://www.suno-api.io"
def align_lyrics(song_id=None, lyrics=None, audio_url=None, vocal_separate=False):
payload = {}
if song_id:
payload["song_id"] = song_id
payload["vocal_separate"] = vocal_separate
else:
payload["lyrics"] = lyrics
payload["audio_url"] = audio_url
r = requests.post(
f"{BASE}/api/music/lyrics-align",
headers={"Authorization": f"Bearer {API_KEY}"},
json=payload,
timeout=600,
)
data = r.json()
if not data.get("success"):
raise RuntimeError(data.get("message"))
return data
res = align_lyrics(song_id="17e52af7-b5df-4877-a98a-dce94e0e6aa2", vocal_separate=True)
print("calidad de alineación coverage =", res["coverage"])
for line in res["lines"]:
print(f'{line["start"]:7.2f} {line["text"]}')
# karaoke por carácter: cada carácter en line["chars"] tiene su start / end
Preguntas frecuentes
P: ¿La salida es por carácter o por línea?
R: Las dos. lines[].start es por línea y lines[].chars[].start / end por carácter; el reproductor usa la que necesite.
P: ¿Por qué el texto devuelto es idéntico al que envié? R: Es el diseño. No reconocemos ni reescribimos, solo alineamos tiempos, así que la letra nunca se "corrige a errata".
P: El coverage es alto pero aún suena algo desviado.
R: El error por carácter suele estar en decenas de milisegundos; si toda la canción va desviada una cantidad fija, lo más probable es que haya un tramo de silencio al principio del audio: recórtalo y vuelve a probar.
P: ¿Por qué hace un momento servía la separación y ahora dice "pista de voz no disponible"? R: Los resultados de separación son direcciones temporales de vida corta (medido: caducan a la media hora aproximadamente). En ese caso el endpoint intenta separar de nuevo; si aun así falla, hay reembolso completo. Así que "separar ahora y calibrar luego" no es fiable: hazlo dentro del mismo flujo.
P: ¿Tengo que separar yo una canción de la plataforma?
R: No. Con vocal_separate: true comprobamos si la canción ya tiene pista de voz; si no hay una usable, da error y reembolsa en lugar de pasar la mezcla completa.
P: ¿Se pueden hacer lotes? R: Una canción por petición. Para lotes, haz un bucle; cada llamada se cobra con normalidad, así que se recomienda cachear los resultados.
P: ¿Se guarda el resultado? R: Este endpoint no persiste nada; guarda tú el valor devuelto (las marcas por línea y por carácter van en la respuesta).
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