Studio batch edit
curl --request POST \
--url https://api.mountsea.ai/suno/v2/studio/edit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"clip_id": "<string>",
"ops": [
{
"start_s": 123,
"end_s": 123,
"insert_at_s": 123,
"at_s": 123,
"sections": [
{
"start_s": 1,
"end_s": 1
}
],
"close_gap": true,
"rate": 1.1,
"duration_s": 123
}
],
"title": "<string>"
}
'import requests
url = "https://api.mountsea.ai/suno/v2/studio/edit"
payload = {
"clip_id": "<string>",
"ops": [
{
"start_s": 123,
"end_s": 123,
"insert_at_s": 123,
"at_s": 123,
"sections": [
{
"start_s": 1,
"end_s": 1
}
],
"close_gap": True,
"rate": 1.1,
"duration_s": 123
}
],
"title": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
clip_id: '<string>',
ops: [
{
start_s: 123,
end_s: 123,
insert_at_s: 123,
at_s: 123,
sections: [{start_s: 1, end_s: 1}],
close_gap: true,
rate: 1.1,
duration_s: 123
}
],
title: '<string>'
})
};
fetch('https://api.mountsea.ai/suno/v2/studio/edit', 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.mountsea.ai/suno/v2/studio/edit",
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([
'clip_id' => '<string>',
'ops' => [
[
'start_s' => 123,
'end_s' => 123,
'insert_at_s' => 123,
'at_s' => 123,
'sections' => [
[
'start_s' => 1,
'end_s' => 1
]
],
'close_gap' => true,
'rate' => 1.1,
'duration_s' => 123
]
],
'title' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.mountsea.ai/suno/v2/studio/edit"
payload := strings.NewReader("{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.mountsea.ai/suno/v2/studio/edit")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mountsea.ai/suno/v2/studio/edit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"taskId": "15c257ff-43f7-4678-bd41-202ad6b8488b"
}Studio
Studio Batch Edit
Run multiple timeline ops in one export
POST
/
suno
/
v2
/
studio
/
edit
Studio batch edit
curl --request POST \
--url https://api.mountsea.ai/suno/v2/studio/edit \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"clip_id": "<string>",
"ops": [
{
"start_s": 123,
"end_s": 123,
"insert_at_s": 123,
"at_s": 123,
"sections": [
{
"start_s": 1,
"end_s": 1
}
],
"close_gap": true,
"rate": 1.1,
"duration_s": 123
}
],
"title": "<string>"
}
'import requests
url = "https://api.mountsea.ai/suno/v2/studio/edit"
payload = {
"clip_id": "<string>",
"ops": [
{
"start_s": 123,
"end_s": 123,
"insert_at_s": 123,
"at_s": 123,
"sections": [
{
"start_s": 1,
"end_s": 1
}
],
"close_gap": True,
"rate": 1.1,
"duration_s": 123
}
],
"title": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
clip_id: '<string>',
ops: [
{
start_s: 123,
end_s: 123,
insert_at_s: 123,
at_s: 123,
sections: [{start_s: 1, end_s: 1}],
close_gap: true,
rate: 1.1,
duration_s: 123
}
],
title: '<string>'
})
};
fetch('https://api.mountsea.ai/suno/v2/studio/edit', 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.mountsea.ai/suno/v2/studio/edit",
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([
'clip_id' => '<string>',
'ops' => [
[
'start_s' => 123,
'end_s' => 123,
'insert_at_s' => 123,
'at_s' => 123,
'sections' => [
[
'start_s' => 1,
'end_s' => 1
]
],
'close_gap' => true,
'rate' => 1.1,
'duration_s' => 123
]
],
'title' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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.mountsea.ai/suno/v2/studio/edit"
payload := strings.NewReader("{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.mountsea.ai/suno/v2/studio/edit")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mountsea.ai/suno/v2/studio/edit")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"clip_id\": \"<string>\",\n \"ops\": [\n {\n \"start_s\": 123,\n \"end_s\": 123,\n \"insert_at_s\": 123,\n \"at_s\": 123,\n \"sections\": [\n {\n \"start_s\": 1,\n \"end_s\": 1\n }\n ],\n \"close_gap\": true,\n \"rate\": 1.1,\n \"duration_s\": 123\n }\n ],\n \"title\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"taskId": "15c257ff-43f7-4678-bd41-202ad6b8488b"
}Run crop / remove / duplicate / split / reverse / fade / speed ops in order, then export once. Poll Get Task Status until
Part of Studio Editing. Seconds for each op are relative to the timeline after previous ops.
Supported
Tips for writing
success.
Usually free (0 credits; see
conf_task_policy). Do not put addSection or replace into ops — use dedicated endpoints.Parameters
| Field | Type | Required | Description |
|---|---|---|---|
clip_id | string | Yes | Source clip |
ops | array | Yes | 1–20 operations (see below) |
title | string | No | Final export title |
beat | object | No | Optional metronome export (enabled, optional bpm / time_signature). Omit for legacy behavior — see Studio Editing |
Supported ops[].op
| op | Meaning | Key fields |
|---|---|---|
crop | Keep only a range | start_s, end_s |
removeSection | Delete one or more ranges | sections[], optional close_gap (default true) |
duplicate | Copy selection | start_s, end_s, optional insert_at_s |
split | Cut at a point | at_s |
reverse | Reverse range or whole song | optional paired start_s / end_s; omit both = whole song |
fadeIn | Fade in | start_s, optional end_s or duration_s (default ~2s) |
fadeOut | Fade out | start_s, optional end_s (default to end) |
setSpeed | Absolute rate vs original | rate (0.5–2.0), optional paired start_s / end_s |
Tips for writing ops
- Prefer
crop/removeSectionbeforefade*/setSpeed. - After a length-changing op, re-estimate seconds — do not reuse original song timestamps blindly.
fadeOut.start_smust not exceed the current remaining duration.- Prefer one batch export over crop→export→fade→export chains (lock contention).
Example
curl -X POST https://api.mountsea.ai/suno/v2/studio/edit \
-H "Authorization: Bearer your-api-key" \
-H "Content-Type: application/json" \
-d '{
"clip_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"title": "精修后的歌",
"ops": [
{ "op": "crop", "start_s": 10, "end_s": 100 },
{ "op": "removeSection", "sections": [{ "start_s": 40, "end_s": 48 }], "close_gap": true },
{ "op": "setSpeed", "start_s": 50, "end_s": 70, "rate": 1.1 },
{ "op": "fadeOut", "start_s": 85 }
]
}'
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
Response
201 - application/json
task id. Use this id to query task status.
Example:
"15c257ff-43f7-4678-bd41-202ad6b8488b"
⌘I