curl --request POST \
--url https://api.ttapi.io/suno/v1/upload-extend \
--header 'Content-Type: application/json' \
--header 'TT-API-KEY: <api-key>' \
--data '
{
"audio_url": "<string>",
"continue_at": 10,
"mv": "chirp-v6",
"prompt": "<string>",
"title": "<string>",
"tags": "rock, blues, hip-hop, r&b",
"negative_tags": "<string>",
"style_weight": 0.5,
"weirdness_constraint": 0.5,
"audio_weight": 0.5,
"duration": 120,
"auto_lyrics": false,
"persona_id": "<string>",
"variety": "normal",
"max_mode": false,
"audio_format": "mp3",
"hookUrl": "<string>",
"isStorage": true
}
'import requests
url = "https://api.ttapi.io/suno/v1/upload-extend"
payload = {
"audio_url": "<string>",
"continue_at": 10,
"mv": "chirp-v6",
"prompt": "<string>",
"title": "<string>",
"tags": "rock, blues, hip-hop, r&b",
"negative_tags": "<string>",
"style_weight": 0.5,
"weirdness_constraint": 0.5,
"audio_weight": 0.5,
"duration": 120,
"auto_lyrics": False,
"persona_id": "<string>",
"variety": "normal",
"max_mode": False,
"audio_format": "mp3",
"hookUrl": "<string>",
"isStorage": True
}
headers = {
"TT-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'TT-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
audio_url: '<string>',
continue_at: 10,
mv: 'chirp-v6',
prompt: '<string>',
title: '<string>',
tags: 'rock, blues, hip-hop, r&b',
negative_tags: '<string>',
style_weight: 0.5,
weirdness_constraint: 0.5,
audio_weight: 0.5,
duration: 120,
auto_lyrics: false,
persona_id: '<string>',
variety: 'normal',
max_mode: false,
audio_format: 'mp3',
hookUrl: '<string>',
isStorage: true
})
};
fetch('https://api.ttapi.io/suno/v1/upload-extend', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ttapi.io/suno/v1/upload-extend",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'audio_url' => '<string>',
'continue_at' => 10,
'mv' => 'chirp-v6',
'prompt' => '<string>',
'title' => '<string>',
'tags' => 'rock, blues, hip-hop, r&b',
'negative_tags' => '<string>',
'style_weight' => 0.5,
'weirdness_constraint' => 0.5,
'audio_weight' => 0.5,
'duration' => 120,
'auto_lyrics' => false,
'persona_id' => '<string>',
'variety' => 'normal',
'max_mode' => false,
'audio_format' => 'mp3',
'hookUrl' => '<string>',
'isStorage' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"TT-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ttapi.io/suno/v1/upload-extend"
payload := strings.NewReader("{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("TT-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ttapi.io/suno/v1/upload-extend")
.header("TT-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ttapi.io/suno/v1/upload-extend")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["TT-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "SUCCESS",
"message": "success",
"data": {
"jobId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}{
"status": "FAILED",
"message": "<string>",
"data": {}
}{
"status": "FAILED",
"message": "Wrong TT-API-KEY or email is not activated."
}Suno Upload Extend API Reference
Upload an external audio file and extend it in one request.
curl --request POST \
--url https://api.ttapi.io/suno/v1/upload-extend \
--header 'Content-Type: application/json' \
--header 'TT-API-KEY: <api-key>' \
--data '
{
"audio_url": "<string>",
"continue_at": 10,
"mv": "chirp-v6",
"prompt": "<string>",
"title": "<string>",
"tags": "rock, blues, hip-hop, r&b",
"negative_tags": "<string>",
"style_weight": 0.5,
"weirdness_constraint": 0.5,
"audio_weight": 0.5,
"duration": 120,
"auto_lyrics": false,
"persona_id": "<string>",
"variety": "normal",
"max_mode": false,
"audio_format": "mp3",
"hookUrl": "<string>",
"isStorage": true
}
'import requests
url = "https://api.ttapi.io/suno/v1/upload-extend"
payload = {
"audio_url": "<string>",
"continue_at": 10,
"mv": "chirp-v6",
"prompt": "<string>",
"title": "<string>",
"tags": "rock, blues, hip-hop, r&b",
"negative_tags": "<string>",
"style_weight": 0.5,
"weirdness_constraint": 0.5,
"audio_weight": 0.5,
"duration": 120,
"auto_lyrics": False,
"persona_id": "<string>",
"variety": "normal",
"max_mode": False,
"audio_format": "mp3",
"hookUrl": "<string>",
"isStorage": True
}
headers = {
"TT-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'TT-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
audio_url: '<string>',
continue_at: 10,
mv: 'chirp-v6',
prompt: '<string>',
title: '<string>',
tags: 'rock, blues, hip-hop, r&b',
negative_tags: '<string>',
style_weight: 0.5,
weirdness_constraint: 0.5,
audio_weight: 0.5,
duration: 120,
auto_lyrics: false,
persona_id: '<string>',
variety: 'normal',
max_mode: false,
audio_format: 'mp3',
hookUrl: '<string>',
isStorage: true
})
};
fetch('https://api.ttapi.io/suno/v1/upload-extend', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.ttapi.io/suno/v1/upload-extend",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'audio_url' => '<string>',
'continue_at' => 10,
'mv' => 'chirp-v6',
'prompt' => '<string>',
'title' => '<string>',
'tags' => 'rock, blues, hip-hop, r&b',
'negative_tags' => '<string>',
'style_weight' => 0.5,
'weirdness_constraint' => 0.5,
'audio_weight' => 0.5,
'duration' => 120,
'auto_lyrics' => false,
'persona_id' => '<string>',
'variety' => 'normal',
'max_mode' => false,
'audio_format' => 'mp3',
'hookUrl' => '<string>',
'isStorage' => true
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"TT-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.ttapi.io/suno/v1/upload-extend"
payload := strings.NewReader("{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("TT-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ttapi.io/suno/v1/upload-extend")
.header("TT-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ttapi.io/suno/v1/upload-extend")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["TT-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"audio_url\": \"<string>\",\n \"continue_at\": 10,\n \"mv\": \"chirp-v6\",\n \"prompt\": \"<string>\",\n \"title\": \"<string>\",\n \"tags\": \"rock, blues, hip-hop, r&b\",\n \"negative_tags\": \"<string>\",\n \"style_weight\": 0.5,\n \"weirdness_constraint\": 0.5,\n \"audio_weight\": 0.5,\n \"duration\": 120,\n \"auto_lyrics\": false,\n \"persona_id\": \"<string>\",\n \"variety\": \"normal\",\n \"max_mode\": false,\n \"audio_format\": \"mp3\",\n \"hookUrl\": \"<string>\",\n \"isStorage\": true\n}"
response = http.request(request)
puts response.read_body{
"status": "SUCCESS",
"message": "success",
"data": {
"jobId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
}{
"status": "FAILED",
"message": "<string>",
"data": {}
}{
"status": "FAILED",
"message": "Wrong TT-API-KEY or email is not activated."
}- Submit a publicly accessible
audio_url. Recommended duration is 8 minutes or less. continue_atmust be>= 1and less than the uploaded audio duration.- This endpoint always runs in custom mode. If
promptis empty, the extension is treated as instrumental. - Store the returned
jobIdand retrieve the result through Suno Fetch V2 or yourhookUrlcallback.
Authorizations
You can obtain your API key from the TTAPI Dashboard.
Body
Publicly accessible audio URL to upload and extend. Recommended duration: 8 minutes or less.
Timestamp, in seconds, where the audio extension should begin. Must be >= 1 and less than the uploaded audio duration.
10
Model to use. Available values: chirp-v6, chirp-v6-wild, chirp-v6-mini. Suno legacy models have all been discontinued; passing a legacy name maps it to chirp-v6. See Model Mapping. After creating a custom model, you can also pass chirp-custom:{model_id}. See Create Model. persona_id and chirp-custom cannot be used together.
chirp-v6, chirp-v6-wild, chirp-v6-mini Lyrics.
Used in custom mode (custom=true). Required when instrumental is false. The lyrics will be used and sung in the generated track. Maximum length: 5000 characters.
Music title.
Used in custom mode (custom=true). Maximum length: 80 characters.
Music style or genre.
Used in custom mode (custom=true). Maximum length: 1000 characters.
"rock, blues, hip-hop, r&b"
Music styles or genres that should be excluded from generation.
Used in custom mode (custom=true).
Music style weight, range: 0.00โ1.00.
Used in custom mode. Valid range: 0 <= x <= 1.
0.5
Audio creativity (weirdness) weight, range: 0.00โ1.00.
Used in custom mode. Valid range: 0 <= x <= 1.
0.5
Audio weight, range: 0.00โ1.00.
Used in custom mode. Valid range: 0 <= x <= 1.
0.5
Audio duration, in seconds
Used in custom mode. Valid range: 10 <= x <= 360.
120
Whether to automatically generate lyrics. Custom mode only.
- true: The input lyrics will be creatively rewritten, similar to the inspiration mode prompt effect
- false: Use the provided lyrics directly to generate the music
Vocal gender.
-
Male: Male voice
-
Female: Female voice
Male, Female Music style ID. Available in both inspiration mode and custom mode.
Cannot be used together with mv=chirp-custom:{model_id}.
Style variety. Controls how much the generated result varies from the specified style.
- off: Exact style
- normal: Balanced variety
- high: Distinct styles
- extra: Bold exploration
- max: Unreasonably varied
off, normal, high, extra, max Whether to use more compute to maximize consistency throughout the song. Custom mode only.
- false: No (default)
- true: Yes. Credit consumption is doubled when enabled
Audio format of audioUrl after the job succeeds.
mp3, m4a, wav "mp3"
Callback notification URL
Whether to store the generated audio.
- true: The audio will be stored and a TTAPI CDN URL will be returned
- false: The original source URL will be returned