Upload-then-cover API

Updated 2026-09-18 · Suno-API team

Endpoint description

Upload-then-cover submits an audio file or an audio URL and generates a new cover version from that source audio.

Endpoint: POST /api/music/upload-cover

Billing: Paid, currently 0.6 ¥ per call by default. This endpoint is "upload then cover" — it is not about uploading an image cover. The amount actually charged follows the current back-office price configuration.

Max Mode / Variety: this endpoint supports the optional parameters max_mode and variety (0-4). With max_mode on, this call is billed at 2× the price (0.6 → 1.2 ¥ per call); variety costs nothing extra. What they mean and how to send them is in the "Advanced parameters" section of the New API overview.

Wait times and timeouts (important): this is a synchronous endpoint — the order is only accepted and handed to generation when the response arrives. Measured, most requests return in 1-3 seconds, about 10% take longer than 30 seconds, and the longest is about 230 seconds. Set your client timeout to 300 seconds or more; no response does not mean nothing was generated, and do not retry immediately after a timeout (that duplicates the order and charges again). If the connection dropped, confirm later with GET /api/music/songs. See "Wait times and timeout settings" in the New API overview.

When the audio is large, split "upload" and "cover" into two steps (recommended)

This endpoint requires the whole audio to go into the request body: the bigger the audio, the bigger the body, and one network hiccup or timeout cuts the transfer halfway, after which the server returns unexpected end of JSON input (HTTP 400, no charge).

When the audio is over about 8 MB, the network is unstable, or the same source material will be reused, switch to the two-step form:

  1. POST /api/music/upload-source uploads the source audio first — free, retry anytime — and gives you a clip_id;
  2. POST /api/music/generate-from-source starts the cover with that clip_id — the body of the charged step is only about 250 bytes.

See the upload source audio API, the cover from a source clip API, and "Large files and truncated requests" at the end of this page.

Request parameters

Headers

Parameter Type Required Notes
Authorization string yes Bearer YOUR_API_KEY
Content-Type string yes application/json

Body parameters

Parameter Type Required Default Notes
model string no suno-v6 Customer-facing model name: suno-v6, suno-v6-wild or suno-v6-mini
file_url string no - Source audio URL
file_base64 string no - Base64 audio
file_name string no - File name
prompt string no - New lyrics or the direction of the adaptation
style string no - Style tags
title string no - Title
negativeTags string no - Negative style
instrumental boolean no false Whether the song is instrumental
waitAudio boolean no false Whether to wait for the audio to complete
cover_start_s number no - Start second of the covered segment
cover_end_s number no - End second of the covered segment
audio_weight number no - Influence weight of the reference audio, range 0.0-1.0; can only be sent when reference audio is provided

cover_start_s and cover_end_s are in seconds and may be decimals; the start time must be smaller than the end time and must not exceed the source audio duration. When both fields are omitted, the whole audio is used. audio_weight maps to Suno's metadata.control_sliders.audio_weight and controls how far the result leans on the reference audio; it takes 0.0-1.0 and may only be carried when the request provides a valid file_url or file_base64 reference audio. 0 is a valid value; omitting the field means "not specified", which keeps Suno's default behaviour. instrumental and waitAudio must be JSON booleans, not strings.

The upload endpoint returns asynchronously by default. While clips[].status in the response is pending, an empty audio_url is normal and does not mean the upload or the cover failed; save the real song_id you get back and poll the song query endpoint until it completes before reading the audio address.

Request example

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": "New lyrics or direction of the adaptation",
    "style": "Mandopop, acoustic guitar",
    "title": "Cover version",
    "negativeTags": "noise, low quality",
    "audio_weight": 0.5,
    "instrumental": false,
    "waitAudio": false,
    "cover_start_s": 0,
    "cover_end_s": 60
  }'

Response

{
  "code": 200,
  "message": "success",
  "data": {
    "upload": {
      "clip_id": "uploaded_clip_id",
      "status": "complete"
    },
    "clips": [
      {
        "song_id": "new_clip_id",
        "song_title": "Cover version",
        "status": "pending"
      }
    ]
  }
}

Large files and truncated requests

Recommended: split upload and cover into two steps

The one-shot endpoint (this one) merges upload and generation into a single step: the large body sits in that one and only step, so once it breaks you neither know whether anything was generated nor whether you were charged.

Step 1 upload Step 2 cover
Endpoint POST /api/music/upload-source POST /api/music/generate-from-source
Billing Free (upload only, no generation) 0.6 ¥ per call; 1.2 ¥ per call with Max Mode
Request body The audio itself (base64 / multipart), or just a link via file_url About 250 bytes (just one sourceClipId)
Returns clip_id (the source audio's clip ID) data.clips[].song_id (the generated result)
If it fails Just retry, no charge and no generation task Set the client timeout to ≥300 s; on timeout check with /api/music/songs first and do not retry immediately
Reusing the source material The same clip_id also works for extend / replace / separation The audio must be re-uploaded every time

Conclusion: audio over about 8 MB, an unstable network, or the same material used several times → use the two-step form; tiny audio on a stable network → this endpoint is less hassle.

What 400 unexpected end of JSON input means

It means the JSON the server received is incomplete (it is not a wrong parameter, a permission problem or a balance problem). The usual causes, most likely first:

  1. A large body truncated mid-transfer: the ingress layer records both "how many bytes the client declared" and "how many actually arrived". Measured case: the client declared 14.17 MB but only 11.8–12.4 MB arrived, and all three requests stopped at about 1.6–1.7 s; the missing byte count differed every time, which points at a broken transfer rather than a fixed limit (the server does not cap the request body size).
  2. Content-Length not matching the bytes actually sent: in Node.js, using a string's .length (UTF-16 character count) as the length miscalculates whenever the content contains Chinese or other multi-byte text.
  3. Writing the body as a string instead of a Buffer, so the bytes written do not match what was declared.

All three happen before billing, so no charge is produced.

Client self-check list

Common error reference

Error Meaning What to do
unexpected end of JSON input Request body incomplete (truncated) Work through the self-check above, or switch to the two-step form
invalid character '-' in numeric literal A multipart body was sent to a JSON endpoint Do not use multipart on JSON endpoints, or do not set Content-Type manually
one of file_path, file_base64, file_url, or multipart file is required No audio was supplied Add file_base64 / file_url / a multipart file
model is required The body was empty valid JSON (for example {}) Send at least model
Invalid request: Invalid request, ... Wrapper message for a body that failed to parse Read the second half for the concrete reason (usually one of the above)

Related endpoints: upload source audio API (step 1), cover from a source clip API (step 2).

NextCover from a source clip API

Get an API key

Create an API key in the console after signing up. ¥0.6 per run returns 2 tracks, downloads are unlimited, and no phone number is required.

Get API key Back to overview