API de upload e cover em uma etapa
Descrição do endpoint
Upload e cover em uma etapa envia um arquivo de áudio ou uma URL de áudio e gera uma nova versão de cover a partir desse áudio de origem.
Endpoint: POST /api/music/upload-cover
Cobrança: Pago, atualmente ¥0,6 por chamada por padrão. Este endpoint é "enviar e fazer o cover" — não se trata de enviar uma capa de imagem. O valor realmente cobrado segue a configuração de preços atual do back-office.
Max Mode / Variety: este endpoint aceita os parâmetros opcionais max_mode e variety (0-4). Com
max_mode ligado, esta chamada é cobrada em 2× o preço (0,6 → 1,2 ¥ por chamada); variety não custa nada
a mais. O que significam e como enviá-los está na seção "Parâmetros avançados" da
Visão geral da nova API.
Tempos de espera e timeouts (importante): este é um endpoint síncrono — o pedido só é aceito e entregue à geração quando a resposta chega. Pelo medido, a maioria das requisições responde em 1-3 segundos, cerca de 10% leva mais de 30 segundos e a mais longa fica em torno de 230 segundos. Defina o timeout do cliente em 300 segundos ou mais; não receber resposta não significa que nada foi gerado, e não repita logo após um timeout (isso duplica o pedido e cobra de novo). Se a conexão caiu, confirme depois com
GET /api/music/songs. Veja "Tempos de espera e configuração de timeout" na Visão geral da nova API.
Quando o áudio é grande, convém separar "envio" e "cover" em duas etapas (recomendado)
Este endpoint exige que todo o áudio vá no corpo da requisição: quanto maior o áudio, maior o corpo, e uma oscilação de rede ou um timeout corta a transferência pela metade, e então o servidor devolve
unexpected end of JSON input(HTTP 400, sem cobrança).Quando o áudio passa de cerca de 8 MB, a rede é instável ou o mesmo material de origem será reutilizado, mude para a forma em duas etapas:
POST /api/music/upload-sourceenvia primeiro o áudio de origem — grátis, pode repetir a qualquer momento — e devolve umclip_id;POST /api/music/generate-from-sourceinicia o cover com esseclip_id— o corpo da etapa cobrada tem apenas cerca de 250 bytes.Veja a API de upload de áudio de origem, a API de cover a partir de um clip de origem e "Arquivos grandes e requisições truncadas" no fim desta página.
Parâmetros da requisição
Headers
| Parâmetro | Tipo | Obrigatório | Observações |
|---|---|---|---|
| Authorization | string | sim | Bearer YOUR_API_KEY |
| Content-Type | string | sim | application/json |
Parâmetros do body
| Parâmetro | Tipo | Obrigatório | Padrão | Observações |
|---|---|---|---|---|
| model | string | não | suno-v6 | Nome de modelo de cara ao cliente: suno-v6, suno-v6-wild ou suno-v6-mini |
| file_url | string | não | - | URL do áudio de origem |
| file_base64 | string | não | - | Áudio em Base64 |
| file_name | string | não | - | Nome do arquivo |
| prompt | string | não | - | Letra nova ou direção da adaptação |
| style | string | não | - | Tags de estilo |
| title | string | não | - | Título |
| negativeTags | string | não | - | Estilo negativo |
| instrumental | boolean | não | false | Se a música é instrumental |
| waitAudio | boolean | não | false | Se espera o áudio terminar |
| cover_start_s | number | não | - | Segundo inicial do trecho que será versionado |
| cover_end_s | number | não | - | Segundo final do trecho que será versionado |
| audio_weight | number | não | - | Dependência do áudio de referência, faixa 0.0-1.0; só pode ser enviado quando um áudio de referência é fornecido |
cover_start_s e cover_end_s estão em segundos e aceitam decimais; o tempo inicial deve ser menor que o final e não pode passar da duração do áudio de origem. Se os dois campos forem omitidos, usa-se o áudio inteiro. audio_weight é mapeado para o metadata.control_sliders.audio_weight do Suno e controla o quanto o resultado se apoia no áudio de referência; assume 0.0-1.0 e só pode ser incluído quando a requisição traz um áudio de referência válido em file_url ou file_base64. 0 é um valor válido; omitir o campo significa "não especificado" e mantém o comportamento padrão do Suno. instrumental e waitAudio devem ser booleanos JSON, não strings.
O endpoint de upload devolve de forma assíncrona por padrão. Enquanto clips[].status na resposta for pending, um audio_url vazio é normal e não significa que o upload ou o cover falharam; guarde o song_id real devolvido e consulte o endpoint de consulta de músicas até terminar antes de ler o endereço do áudio.
Exemplo de requisição
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": "Nova letra ou direção da adaptação",
"style": "Mandopop, acoustic guitar",
"title": "Versão cover",
"negativeTags": "noise, low quality",
"audio_weight": 0.5,
"instrumental": false,
"waitAudio": false,
"cover_start_s": 0,
"cover_end_s": 60
}'
Resposta
{
"code": 200,
"message": "success",
"data": {
"upload": {
"clip_id": "uploaded_clip_id",
"status": "complete"
},
"clips": [
{
"song_id": "new_clip_id",
"song_title": "Versão cover",
"status": "pending"
}
]
}
}
Arquivos grandes e requisições truncadas
Recomendado: dividir upload e cover em duas etapas
O endpoint de uma só vez (este) junta upload e geração numa única etapa: o corpo grande fica nessa única etapa, então quando ele quebra você não sabe se algo foi gerado nem se houve cobrança.
| Etapa 1 upload | Etapa 2 cover | |
|---|---|---|
| Endpoint | POST /api/music/upload-source |
POST /api/music/generate-from-source |
| Cobrança | Grátis (só envia, não gera) | ¥0,6 por chamada; ¥1,2 por chamada com Max Mode |
| Corpo da requisição | O áudio em si (base64 / multipart), ou apenas um link em file_url |
Cerca de 250 bytes (apenas um sourceClipId) |
| Devolve | clip_id (o clip ID do áudio de origem) |
data.clips[].song_id (o resultado gerado) |
| Se falhar | Repita a chamada, sem cobrança e sem tarefa de geração | Defina o timeout do cliente em ≥300 s; em caso de timeout consulte primeiro com /api/music/songs e não repita logo |
| Reutilizar o material de origem | O mesmo clip_id também serve para estender / substituir / separar |
O áudio precisa ser reenviado toda vez |
Conclusão: áudio acima de cerca de 8 MB, rede instável ou o mesmo material usado várias vezes → use a forma em duas etapas; áudio pequeno em rede estável → este endpoint dá menos trabalho.
O que significa 400 unexpected end of JSON input
Significa que o JSON que o servidor recebeu está incompleto (não é parâmetro errado, nem problema de permissão ou saldo). As causas comuns, da mais provável para a menos:
- Um corpo grande truncado no meio da transferência: a camada de entrada registra tanto "quantos bytes o cliente declarou" quanto "quantos chegaram de fato". Caso medido: o cliente declarou 14,17 MB e chegaram apenas 11,8–12,4 MB, e as três requisições pararam por volta de 1,6–1,7 s; a quantidade de bytes faltantes era diferente a cada vez, o que indica corte de transferência e não um limite fixo (o servidor não limita o tamanho do corpo).
Content-Lengthdiferente dos bytes realmente enviados: no Node.js, usar o.lengthde uma string (contagem de caracteres UTF-16) como comprimento erra sempre que o conteúdo tem chinês ou outro texto multibyte.- Escrever o corpo como string em vez de Buffer, de modo que os bytes escritos não batem com o declarado.
Os três casos acontecem antes da cobrança, então nenhum valor é gerado.
Lista de autoverificação do cliente
- O
Content-Lengthvem deBuffer.byteLength(json, 'utf8')(ouBuffer.from(json).length) — nunca dejson.length; - O corpo da requisição é escrito como Buffer, não como string;
- O timeout do socket / da requisição é ≥ 300 segundos;
- Quando o áudio passa de cerca de 8 MB: use
file_url(o corpo tem só algumas centenas de bytes), ou o upload multipart doupload-source, ou vá direto para a forma em duas etapas; - Em requisições multipart, não defina
Content-Typemanualmente (deixe o cliente incluir o boundary); - Imprima os "bytes realmente enviados" e compare com o
Content-Length; - Na forma em duas etapas, confirme que a etapa 1 devolveu um
clip_idcomstatusconcluído antes de enviar a etapa 2.
Erros frequentes
| Erro | Significado | O que fazer |
|---|---|---|
unexpected end of JSON input |
Corpo da requisição incompleto (truncado) | Faça a autoverificação acima, ou mude para a forma em duas etapas |
invalid character '-' in numeric literal |
Um corpo multipart foi enviado a um endpoint JSON | Não use multipart em endpoints JSON, nem defina Content-Type manualmente |
one of file_path, file_base64, file_url, or multipart file is required |
Nenhum áudio foi enviado | Inclua file_base64 / file_url / um file multipart |
model is required |
O corpo era JSON válido vazio (por exemplo {}) |
Envie ao menos model |
Invalid request: Invalid request, ... |
Mensagem de embrulho de um corpo que não pôde ser analisado | Leia a segunda metade para ver o motivo concreto (normalmente um dos anteriores) |
Endpoints relacionados: API de upload de áudio de origem (etapa 1), API de cover a partir de um clip de origem (etapa 2).
Obter uma chave de API
Crie uma chave de API no console após o cadastro. Cada geração custa ¥0,6 e devolve 2 faixas, os downloads são ilimitados e não é preciso número de telefone.
Obter chave de API Voltar à visão geral