靈感模式生成 API
介面說明
靈感模式生成適合用一句話描述生成完整歌曲。系統會依描述自動生成歌詞、旋律、編曲與演唱。
介面位址:POST /api/music/create
計費:收費,目前預設 0.6 元/次。每次通常回傳 2 首歌曲,實際扣費以目前後台價格設定為準。
Max Mode / Variety:本介面支援選用參數 max_mode 與 variety(0-4)。開啟 max_mode
時本次依 2 倍價格計費(0.6 → 1.2 元/次),variety 不額外計費;兩者的含義與寫法見
Suno API 介面文件總覽 的「進階參數」一節。
推薦模型:suno-v6
等待時間與逾時(重要):本介面是同步介面,回應返回時才代表訂單已被受理並提交生成。實測多數請求 1–3 秒返回,約 10% 超過 30 秒,最長約 230 秒。請把用戶端逾時設為 300 秒以上;未收到回應不等於沒有生成,逾時後請勿立即重試(會重複下單、重複扣費)。 連線中斷可稍後用
GET /api/music/songs確認。詳見 Suno API 介面文件總覽的「等待時間與逾時設定」。
請求參數
Headers
| 參數名 | 型別 | 必填 | 說明 |
|---|---|---|---|
| Authorization | string | 是 | Bearer YOUR_API_KEY |
| Content-Type | string | 是 | application/json |
Body 參數
| 參數名 | 型別 | 必填 | 預設值 | 說明 |
|---|---|---|---|---|
| description | string | 是 | - | 歌曲描述,支援中英文;最多 3000 字元(超長回傳 400,不扣費) |
| model | string | 否 | suno-v6 | 對客模型名:suno-v6、suno-v6-wild 或 suno-v6-mini |
| instrumental | boolean | 否 | false | 是否為純音樂 |
| wait_completion | boolean | 否 | false | 是否等待生成完成後再返回 |
| references | array | 否 | - | 參考素材清單,可掛參考歌曲 / 傳統音色 / 參考圖;最多 5 首歌曲、1 個音色、1 張圖片。詳見下方「參考素材 references(選用)」 |
請求範例
curl -X POST https://www.suno-api.io/api/music/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"description": "一首輕快的中文流行歌,關於夏天海邊",
"instrumental": false,
"wait_completion": false
}'
參考素材 references(選用)
references 是一個陣列,用來給這次生成掛「參考資料」。可以不傳(不傳就與以前完全一致),也可以只掛一種或任意組合。
元素類型
| type | 必填欄位 | 選填欄位 | 數量上限 | 說明 |
|---|---|---|---|---|
song |
song_id |
style_prompt、lyrics、duration_s |
5 | 參考歌曲;song_id 取自歌曲查詢與歷史 API 回傳的 song_id,且歌曲必須已完成 |
voice |
voice_id |
- | 1 | 傳統音色(人聲);voice_id 取自人聲複製與指定人聲生成 API |
image |
base64 |
- | 1 | 參考圖;傳 data:image/jpeg;base64,... 形式的 base64 內容 |
規則
- 參考歌曲的順序就是語意順序:依你要表達的先後順序傳入(例如「用第一首的旋律、第二首的人聲」)。
style_prompt/lyrics/duration_s都可以不填,平台會自動從歌曲資訊補齊;填了以你填的為準。- 純器樂歌曲的
lyrics傳""或"[Instrumental]"都可以。 - 參考圖支援
jpeg/png/webp,單張不超過 10MB,以 base64 形式隨請求內容一併提交。 - 掛多首參考歌曲時,建議同時使用
accept_mode=async(見上方「受理回執模式」):伺服器需要先把參考素材準備好,同步等待時間可能較長。
範例:掛 2 首參考歌曲
curl -X POST https://www.suno-api.io/api/music/create \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"description": "把這些靈感合成一首歌",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "song", "song_id": "a90438d2-35fc-4443-88f4-56531e6e5d24" }
]
}'
範例:參考歌曲 + 傳統音色
{
"model": "suno-v6",
"description": "用這個音色演唱這些靈感",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "voice", "voice_id": "5813cbe1-36f1-414a-a9a8-4d399dfeb292" }
]
}
範例:參考歌曲 + 參考圖
{
"model": "suno-v6",
"description": "參考這張圖的氛圍",
"references": [
{ "type": "song", "song_id": "43eb711d-81f8-4e72-a68e-b2498bac88f9" },
{ "type": "image", "base64": "data:image/jpeg;base64,/9j/4AAQ..." }
]
}
參數錯誤
以下情況會回傳 HTTP 400,在扣費之前攔截,不會產生費用:
| 情況 | 錯誤訊息 |
|---|---|
| 參考歌曲超過 5 首 | references supports at most 5 song references |
| 音色超過 1 個 | references supports at most 1 voice reference |
| 參考圖超過 1 張 | references supports at most 1 image reference |
type 取值不合法 |
references[0].type must be one of song, voice, image |
歌曲缺少 song_id |
references[0].song_id is required |
| 歌曲尚未完成 | references[0].song_id must be a real completed clip |
| 同一首歌重複傳入 | references[0].song_id is duplicated |
references[0]裡的數字是該元素在陣列中的索引,方便定位是哪一項出錯。
回應結果
回傳歌曲陣列,通常包含 2 筆任務或歌曲。
[
{
"song_id": "clip_id",
"song_title": "夏日海風",
"status": "pending",
"description": "一首輕快的中文流行歌,關於夏天海邊",
"audio_url": "",
"cover_url": "",
"video_url": "",
"model_version": "suno-v6",
"generation_type": "generate",
"created_at": "2026-05-21T10:00:00Z"
}
]
受理回執模式(選用,推薦給不想掛長連線的用戶端)
預設情況下本介面是同步介面:回應返回時才代表訂單已被受理,實測最長可能等到約 230 秒。 如果用戶端不適合掛長連線,可以開啟受理回執模式——二選一:
- 請求內容加
"accept_mode": "async" - 請求標頭加
X-Accept-Mode: async
開啟後介面立刻回傳 HTTP 202,只表示「已受理、已進入生成佇列」,生成在後台繼續:
{
"success": true,
"data": {
"request_id": "ac_20260920092714315816800d76fv3nq",
"status": "queued",
"accepted_at": 1789896434,
"pre_consumed_quota": 300000,
"tasks": [
{ "index": 0, "status": "queued" },
{ "index": 1, "status": "queued" }
]
}
}
受理階段不會回傳
song_id。 此時還不存在真實歌曲 ID,request_id與tasks[].index都不是歌曲 ID,請不要把它們當作song_id保存。真實song_id會在下面的進度查詢中出現。
查詢受理進度
介面位址:GET /api/music/requests/{request_id}(免費,用同一個 API Key 認證)
curl "https://www.suno-api.io/api/music/requests/ac_20260920092714315816800d76fv3nq" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"success": true,
"data": {
"request_id": "ac_20260920092714315816800d76fv3nq",
"status": "processing",
"tasks": [
{ "index": 0, "status": "processing", "song_id": "f3fa09f5-3d55-4953-826c-0d23f043ec57" },
{ "index": 1, "status": "processing", "song_id": "5fcafe3e-3fae-4d64-8f66-c01bc027b0c3" }
]
}
}
status 的取值與含義:
| status | 含義 |
|---|---|
queued |
已受理,還沒登記到具體歌曲(tasks 可能是空陣列) |
processing |
已提交生成 |
partial |
兩筆裡已有一筆完成 |
completed |
兩筆都完成,tasks[].song_id 可讀 |
failed |
提交失敗,費用已全額退回,error_message 給出原因 |
單筆任務還有自己的 tasks[].status,取值與歌曲查詢 API 一致:
pending(已提交、生成中)、processing、completed、failed。任務項裡還可能帶 title、
duration,以及已經登記的 audio_url;沒有就是尚未生成。
拿到真實 song_id 之後,依歌曲查詢 API 或下載介面繼續即可。
Python 範例
import time
import requests
BASE = "https://www.suno-api.io"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"}
accepted = requests.post(
f"{BASE}/api/music/create",
headers={**HEADERS, "Idempotency-Key": "your-own-unique-key"},
json={"description": "一首輕快的流行歌曲", "model": "suno-v6", "accept_mode": "async"},
timeout=300,
).json()["data"]
request_id = accepted["request_id"]
while True:
time.sleep(5)
progress = requests.get(
f"{BASE}/api/music/requests/{request_id}", headers=HEADERS, timeout=60
).json()["data"]
if progress["status"] in ("completed", "failed"):
print(progress)
break
相容性與注意事項
- 不帶
accept_mode時,行為與以前完全一致:同步等待、回傳200和歌曲陣列。既有接入方不需要改任何程式碼。 - 這個開關目前只在
POST /api/music/create和POST /api/music/create/custom生效,其他生成類介面暫不支援。 - 建議同時帶上
Idempotency-Key(自訂的唯一字串,≤128 字元):同一個 key 重複提交只會受理一次,重放回傳同一份回執,不會重複扣費。非同步模式下這一點尤其重要。 - 開啟
accept_mode=async時wait_completion會被忽略(回執立即返回,不等出歌)。 - 費用仍然在受理時預扣;生成失敗會自動全額退回。
- 文字欄位長度上限:
description最多 3000 字元(依 Unicode 字元計,一個漢字算 1 個),超長直接回傳 HTTP400、不進入生成也不扣費,錯誤訊息會帶實測字數,例如description must not exceed 3000 characters; received 4120。本介面沒有歌詞/風格欄位;帶這些欄位的專業模式見專業模式生成 API的「文字欄位長度上限」。通用約定見 Suno API 介面文件總覽的「文字欄位長度上限」。 - 不傳
references時,行為、價格與回應與以前完全一致:既有接入方不需要改任何程式碼。 - 掛了參考素材(尤其是多首參考歌曲)時,建議改用
accept_mode=async受理回執模式,避免同步介面長時間等待;參考素材的準備耗時取決於素材數量與來源。
下一步
如果回應時歌曲還未完成,請使用歌曲查詢 API 查詢最終結果。
Node/Electron 接入案例
如果在 Electron 主行程、Node.js 伺服器或桌面用戶端中對接普通生成,推薦依下面的流程實作:
- 呼叫
POST /api/music/create建立生成任務。 - 從回應裡讀取
song_id或id。 - 每隔 2 秒呼叫
POST /api/music/query查詢狀態。 - 查詢結果中出現
audio_url後,即視為生成完成。
不要繼續使用舊路徑 POST /api/generate 或 GET /api/clip?id=...,這些不是目前推薦的公開接入路徑。
const http = require('http');
const https = require('https');
const BASE_URL = 'https://www.suno-api.io';
const MODEL = 'suno-v6';
const POLL_INTERVAL_MS = 2000;
const MAX_POLL_ATTEMPTS = 60;
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function requestJson(urlString, apiKey, body) {
const url = new URL(urlString);
const transport = url.protocol === 'https:' ? https : http;
const payload = JSON.stringify(body);
return new Promise((resolve, reject) => {
const req = transport.request(
{
method: 'POST',
hostname: url.hostname,
port: url.port || undefined,
path: `${url.pathname}${url.search}`,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload),
},
},
(res) => {
let raw = '';
res.setEncoding('utf8');
res.on('data', (chunk) => {
raw += chunk;
});
res.on('end', () => {
const data = raw ? JSON.parse(raw) : {};
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
reject(new Error(`Suno API request failed: HTTP ${res.statusCode} ${raw}`));
return;
}
resolve(data);
});
}
);
req.on('error', reject);
req.write(payload);
req.end();
});
}
function getPayload(response) {
return response && response.data !== undefined ? response.data : response;
}
function toSongList(payload) {
if (Array.isArray(payload)) return payload;
if (Array.isArray(payload?.songs)) return payload.songs;
if (Array.isArray(payload?.clips)) return payload.clips;
return payload ? [payload] : [];
}
function collectSongIds(createResponse) {
return toSongList(getPayload(createResponse))
.map((song) => song.song_id || song.id)
.filter(Boolean);
}
async function generateSunoSong({ apiKey, description, instrumental = false }) {
const createResponse = await requestJson(`${BASE_URL}/api/music/create`, apiKey, {
description,
model: MODEL,
instrumental,
wait_completion: false,
});
const songIds = collectSongIds(createResponse);
if (songIds.length === 0) {
throw new Error(`Suno API did not return song ids: ${JSON.stringify(createResponse)}`);
}
for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt += 1) {
await sleep(POLL_INTERVAL_MS);
const queryResponse = await requestJson(`${BASE_URL}/api/music/query`, apiKey, {
song_ids: songIds,
model: MODEL,
});
const songs = toSongList(getPayload(queryResponse));
const completed = songs.find((song) => song.audio_url);
if (completed) {
return {
audioUrl: completed.audio_url,
title: completed.song_title || completed.title || 'Suno Song',
duration: completed.duration,
};
}
const allFailed = songs.length > 0 && songs.every((song) =>
['failed', 'error', 'rejected'].includes(String(song.status || '').toLowerCase())
);
if (allFailed) {
throw new Error(`Suno generation failed: ${JSON.stringify(songs)}`);
}
}
throw new Error('Suno generation timed out after 120 seconds. Please query again later.');
}
// Usage:
// generateSunoSong({
// apiKey: process.env.SUNO_API_KEY,
// description: 'A bright pop song about the ocean in summer',
// }).then(console.log).catch(console.error);
實際專案中建議把 API Key 放在伺服器環境變數、桌面用戶端設定或安全儲存中,不要寫進前端程式碼,也不要提交到程式碼倉庫。