用克隆音色生成音乐 · 接口调用示例
适用接口:/api/music/voice-profile/*
一次提交固定生成 2 首成品。音色翻唱 1.2 元/次(开启 Max Mode 为 2.4 元/次);强化克隆按强化上传价计(当前 10 元/次,失败自动退款)。
0. 整体流程
① 创建音色 POST /api/music/voice-profile/create → 拿到 voice_id
② 等音色就绪 GET /api/music/voice-profile/{voice_id} → status=ready(强化克隆需要)
③ 生成音乐 POST /api/music/voice-profile/cover → 立刻拿到 2 个 song_id
④ 查进度 POST /api/music/query → 轮询到 status=completed
⑤ 下载成品 GET /api/music/download?song_id=…&kind=mp3
普通克隆第 ① 步通常直接返回 status=ready,可以跳过第 ② 步;强化克隆是异步的,必须等 ready。
1. 准备工作
| 项 | 说明 |
|---|---|
| Base URL | https://www.suno-api.io |
| 鉴权 | 每个请求带 Authorization: Bearer <你的 API Key> |
| 人声样本 | 6 秒以上(建议 10–60 秒)、≤10MB、mp3 / wav / m4a / aac / flac / ogg |
| 样本内容 | 干净人声,避免带伴奏的原曲或翻唱成品(与曲库录音高度相似会被拒) |
一个
voice_id只对创建它的账号可用。
2. ① 创建音色
推荐:直接上传文件
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/create" \
-H "Authorization: Bearer $API_KEY" \
-F "file=@./my-voice.mp3" \
-F "file_name=my-voice.mp3" \
-F "source_file_name=my-voice.mp3" \
-F "title=我的音色" \
-F "source_kind=upload"
响应(普通克隆):
{
"success": true,
"message": "",
"data": {
"voice_id": "vp_20260926080618509168500DXXrxe",
"clip_id": "91cc5935-389f-4193-b56b-cc796c15562d",
"song_id": "91cc5935-389f-4193-b56b-cc796c15562d",
"title": "我的音色",
"source_file_name": "my-voice.mp3",
"audio_url": "https://…/create-ui/voice-source/2026/09/26/xxx.mp3",
"duration_s": 29.18,
"enhanced": false,
"source_kind": "upload",
"status": "ready"
}
}
data.voice_id 就是后续生成音乐要用的音色 ID。
备选一:传一个公网音频地址
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/create" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"file_url": "https://your-cdn.example.com/voice/my-voice.mp3",
"file_name": "my-voice.mp3",
"title": "我的音色"
}'
地址必须是公网可直接下载的 HTTPS 直链;服务端会下载一次并长期保存。
备选二:传 base64
{
"file_base64": "data:audio/mpeg;base64,//uQxAAA…",
"file_name": "my-voice.mp3",
"title": "我的音色"
}
体积会放大 1.33 倍,大文件请改用上传文件。
强化克隆(样本含版权内容时)
加一个 enhanced=true:
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/create" \
-H "Authorization: Bearer $API_KEY" \
-F "file=@./my-voice.mp3" \
-F "title=我的音色" \
-F "enhanced=true"
- 返回立刻是
status=processing并带task_id,此时还没有clip_id; - 处理是异步的,耗时分钟级,请按第 3 步轮询,不要用同步超时等待;
- 成功后
status=ready;失败status=failed,费用自动退回。
3. ② 等音色就绪
curl -sS "https://www.suno-api.io/api/music/voice-profile/$VOICE_ID" \
-H "Authorization: Bearer $API_KEY"
关注 data.status:
| status | 含义 | 处理 |
|---|---|---|
ready |
可以用了 | 进入下一步 |
processing |
还在处理 | 每 5–10 秒查一次;可展示 progress_percent / progress_message |
failed |
失败 | 看 error_message,费用已退回 |
4. ③ 生成音乐
同一个接口支持两种场景,用是否传 song_clip_id 区分。
场景 A:用我的音色翻唱一首指定歌曲
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/cover" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "X-Create-Ui-Client-Request-Id: cover-$(date +%s)" \
-d '{
"model": "suno-v6",
"voice_id": "vp_20260926080618509168500DXXrxe",
"song_clip_id": "5b773e9a-a035-4134-a4a4-29c9961d3ccb",
"lyrics": "[Verse 1]\n原曲歌词…",
"cover_requirements": "咬字更清晰一些",
"style_requirements": "慢速民谣,木吉他",
"audio_weight": 0.85,
"max_mode": false
}'
场景 B:只给音色和歌词,让它唱一首新歌
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/cover" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "X-Create-Ui-Client-Request-Id: sing-$(date +%s)" \
-d '{
"model": "suno-v6",
"voice_id": "vp_20260926080618509168500DXXrxe",
"lyrics": "[Verse 1]\n这是一段示例歌词\n\n[Chorus]\n用我的声音唱出来",
"style_requirements": "温暖流行,中速,木吉他",
"title": "用我的音色唱新歌",
"audio_weight": 0.85,
"duration": 120
}'
常用字段
| 字段 | 必填 | 说明 |
|---|---|---|
model |
是 | 对客模型名,推荐 suno-v6(另有 suno-v6-wild、suno-v6-mini) |
voice_id |
是 | 第 1 步拿到的音色 ID,必须 ready |
song_clip_id |
否 | 传了 = 翻唱这首歌(场景 A);不传 = 唱新歌(场景 B) |
lyrics |
否 | 歌词全文,逐字上送,≤3000 字符 |
cover_requirements |
否 | 翻唱要求,例如「咬字更清晰」 |
style_requirements |
否 | 风格要求,例如「慢速民谣,木吉他」 |
title |
否 | 成品标题 |
audio_weight |
否 | 音频参考度,0–1 小数,默认 0.85;越高越贴近音色样本 |
duration |
否 | 期望时长(秒),1–480 的整数;平台实际最短约 30 秒 |
max_mode |
否 | true 时费用 ×2 |
client_request_id |
否 | 写入任务记录,便于排查;不做去重 |
提交成功会立刻返回 2 个 song_id:
{
"code": 200,
"message": "success",
"data": {
"resolved_scene": "sing",
"clips": [
{ "song_id": "9f1c…", "status": "processing" },
{ "song_id": "3a7d…", "status": "processing" }
]
}
}
提交成功不代表已完成,必须继续查进度。
5. ④ 查询进度
curl -sS -X POST "https://www.suno-api.io/api/music/query" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"suno-v6","song_ids":"9f1c…,3a7d…"}'
song_ids是英文逗号分隔的字符串,不是数组;- 返回是裸数组(没有
success/data外壳); - 建议间隔 5–10 秒,总超时 10–15 分钟;
- 只看
status,completed才算完成。
[
{
"song_id": "9f1c…",
"status": "completed",
"audio_url": "https://…/assets/9f1c….mp3",
"duration": 115.15,
"model_version": "suno-v6",
"generation_type": "voice_profile_cover"
}
]
6. ⑤ 下载成品
方式一:直接用查询结果里的 audio_url。
方式二:走下载接口(返回音频字节流,文件名已带在响应头里):
curl -sS -L "https://www.suno-api.io/api/music/download?song_id=9f1c…&kind=mp3" \
-H "Authorization: Bearer $API_KEY" \
-o song.mp3
kind 可选:mp3(等价 song)/ playback / wav / video / lyrics。
7. 完整脚本(bash + curl + jq)
保存为 clone-and-generate.sh,按需改前三个变量:
#!/usr/bin/env bash
set -euo pipefail
API_KEY="sk-你的密钥"
BASE="https://www.suno-api.io"
VOICE_FILE="./my-voice.mp3"
auth=(-H "Authorization: Bearer ${API_KEY}")
# ---------- ① 创建音色 ----------
echo "[1/5] 创建音色…"
CREATE=$(curl -sS -X POST "${BASE}/api/music/voice-profile/create" \
"${auth[@]}" \
-F "file=@${VOICE_FILE}" \
-F "title=我的音色" \
-F "source_kind=upload")
VOICE_ID=$(echo "$CREATE" | jq -r '.data.voice_id')
VOICE_STATUS=$(echo "$CREATE" | jq -r '.data.status')
echo "voice_id=${VOICE_ID} status=${VOICE_STATUS}"
if [ -z "${VOICE_ID}" ] || [ "${VOICE_ID}" = "null" ]; then
echo "$CREATE"; exit 1
fi
# ---------- ② 等音色就绪 ----------
echo "[2/5] 等待音色就绪…"
i=0
while [ "${VOICE_STATUS}" != "ready" ]; do
if [ "${VOICE_STATUS}" = "failed" ]; then
curl -sS "${BASE}/api/music/voice-profile/${VOICE_ID}" "${auth[@]}" | jq -r '.data.error_message'
exit 1
fi
i=$((i + 1))
if [ "$i" -gt 120 ]; then echo "音色创建超时"; exit 1; fi
sleep 10
DETAIL=$(curl -sS "${BASE}/api/music/voice-profile/${VOICE_ID}" "${auth[@]}")
VOICE_STATUS=$(echo "$DETAIL" | jq -r '.data.status')
echo " status=${VOICE_STATUS} $(echo "$DETAIL" | jq -r '.data.progress_message // ""')"
done
# ---------- ③ 生成音乐 ----------
echo "[3/5] 提交生成…"
COVER=$(curl -sS -X POST "${BASE}/api/music/voice-profile/cover" \
"${auth[@]}" \
-H "Content-Type: application/json" \
-H "X-Create-Ui-Client-Request-Id: demo-$(date +%s)" \
-d @- <<JSON
{
"model": "suno-v6",
"voice_id": "${VOICE_ID}",
"lyrics": "[Verse 1]\n这是一段示例歌词\n\n[Chorus]\n用我的声音唱出来",
"style_requirements": "温暖流行,中速,木吉他",
"title": "用我的音色唱新歌",
"audio_weight": 0.85,
"duration": 120
}
JSON
)
SONG_IDS=$(echo "$COVER" | jq -r '.data.clips | map(.song_id) | join(",")')
echo "song_ids=${SONG_IDS}"
if [ -z "${SONG_IDS}" ] || [ "${SONG_IDS}" = "null" ]; then
echo "$COVER"; exit 1
fi
# ---------- ④ 轮询 ----------
echo "[4/5] 等待生成完成…"
i=0
while true; do
i=$((i + 1))
if [ "$i" -gt 90 ]; then echo "生成超时"; exit 1; fi
sleep 10
Q=$(curl -sS -X POST "${BASE}/api/music/query" \
"${auth[@]}" \
-H "Content-Type: application/json" \
-d "{\"model\":\"suno-v6\",\"song_ids\":\"${SONG_IDS}\"}")
DONE=$(echo "$Q" | jq -r '[.[] | select(.status == "completed")] | length')
FAILED=$(echo "$Q" | jq -r '[.[] | select(.status == "failed")] | length')
echo " completed=${DONE} failed=${FAILED}"
if [ "${DONE}" -ge 2 ]; then break; fi
if [ "${FAILED}" -ge 1 ]; then echo "$Q"; exit 1; fi
done
# ---------- ⑤ 下载 ----------
echo "[5/5] 下载成品…"
n=0
for id in ${SONG_IDS//,/ }; do
n=$((n + 1))
curl -sS -L "${BASE}/api/music/download?song_id=${id}&kind=mp3" \
"${auth[@]}" -o "song-${n}.mp3"
echo " saved song-${n}.mp3 (${id})"
done
echo "完成"
脚本依赖
jq。没有jq的话可以用下面的 Node.js 版本。
8. Node.js 最小示例(Node 18+)
import { readFile, writeFile } from "node:fs/promises";
const BASE = "https://www.suno-api.io";
const KEY = process.env.SUNO_API_KEY;
const auth = { Authorization: `Bearer ${KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// ① 创建音色
const form = new FormData();
form.append("file", new Blob([await readFile("./my-voice.mp3")]), "my-voice.mp3");
form.append("title", "我的音色");
form.append("source_kind", "upload");
const created = await (
await fetch(`${BASE}/api/music/voice-profile/create`, {
method: "POST",
headers: auth,
body: form,
})
).json();
const voiceId = created.data.voice_id;
console.log("voice_id:", voiceId);
// ② 等音色就绪(普通克隆通常直接 ready)
let voice = created.data;
while (voice.status !== "ready") {
if (voice.status === "failed") throw new Error(voice.error_message || "voice failed");
await sleep(10000);
const detail = await (
await fetch(`${BASE}/api/music/voice-profile/${voiceId}`, { headers: auth })
).json();
voice = detail.data;
console.log("voice status:", voice.status, voice.progress_message || "");
}
// ③ 生成音乐(不传 song_clip_id = 用音色唱新歌)
const cover = await (
await fetch(`${BASE}/api/music/voice-profile/cover`, {
method: "POST",
headers: {
...auth,
"Content-Type": "application/json",
"X-Create-Ui-Client-Request-Id": `demo-${Date.now()}`,
},
body: JSON.stringify({
model: "suno-v6",
voice_id: voiceId,
lyrics: "[Verse 1]\n这是一段示例歌词\n\n[Chorus]\n用我的声音唱出来",
style_requirements: "温暖流行,中速,木吉他",
title: "用我的音色唱新歌",
audio_weight: 0.85,
duration: 120,
}),
})
).json();
const songIds = cover.data.clips.map((c) => c.song_id);
console.log("song_ids:", songIds);
// ④ 轮询
let rows = [];
for (let i = 0; i < 90; i++) {
await sleep(10000);
rows = await (
await fetch(`${BASE}/api/music/query`, {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({ model: "suno-v6", song_ids: songIds.join(",") }),
})
).json();
const done = rows.filter((r) => r.status === "completed").length;
console.log(`completed: ${done}/${songIds.length}`);
if (done >= songIds.length) break;
}
// ⑤ 下载
for (const [i, id] of songIds.entries()) {
const res = await fetch(`${BASE}/api/music/download?song_id=${id}&kind=mp3`, {
headers: auth,
});
const buf = Buffer.from(await res.arrayBuffer());
await writeFile(`song-${i + 1}.mp3`, buf);
console.log(`saved song-${i + 1}.mp3`);
}
运行:
export SUNO_API_KEY="sk-你的密钥"
node clone-and-generate.mjs
9. 常见错误
| HTTP | message | 原因与处理 |
|---|---|---|
| 401 | 无效的令牌 |
API Key 不对或已停用 |
| 200 | one of file_path, file_base64, or file_url is required |
创建音色时没带音频 |
| 200 | Uploaded audio is too short (currently 2.4 seconds). Minimum duration is 6 seconds. |
样本太短,换 ≥6 秒(建议 ≥10 秒) |
| 200 | This audio matches an existing recording in our catalog. |
样本与曲库录音高度相似,换一段干净人声 |
| 400 | voice_id is required and must be a ready voice |
没传 voice_id,或传的是占位值 |
| 400 | 该音色不存在或已被删除(voice_id=vp_xxx)… |
音色已删除、不存在或不属于当前账号;重新选择音色,或用同一段音频重新创建 |
| 400 | voice is not ready yet (status=processing) |
音色还在创建中,等 ready |
| 500 | model is required |
生成时漏了 model |
| 400 | song_clip_id must be a real completed clip |
song_clip_id 是占位符或那首歌还没完成 |
| 400 | song_clip_id must differ from the voice clip |
翻唱对象不能就是音色样本本身 |
| 400 | audio_weight must be a number between 0 and 1 |
audio_weight 要传 0–1 小数,不是百分数 |
10. 计费与限制速查
- 每次提交固定 2 首,音色翻唱 1.2 元/次,
max_mode=true时 2.4 元/次。 - 强化克隆按强化上传价计(当前 10 元/次,失败自动退款)。
- 人声样本:6 秒以上、≤10MB;建议 10–60 秒的干净人声。
lyrics≤ 3000 字符;duration为 1–480 的整数(实际最短约 30 秒)。- 提交成功后请以
status=completed判断完成,不要用audio_url是否为空判断。 - 音色的
voice_id只对创建它的账号可用;删除后不能继续用于新的翻唱,用同一段音频重新创建会拿回同一个voice_id。