API สร้างเพลงโหมดง่าย
คำอธิบายเอนด์พอยต์
การสร้างเพลงในโหมดง่ายใช้เปลี่ยนคำอธิบายหนึ่งประโยคให้เป็นเพลงที่สมบูรณ์ ระบบจะเขียนเนื้อเพลง ทำนอง การเรียบเรียง และเสียงร้องให้เองจากคำอธิบายของคุณ
เอนด์พอยต์: POST /api/music/create
ค่าบริการ: มีค่าใช้จ่าย ปัจจุบันค่าเริ่มต้น 0.6 หยวนต่อครั้ง โดยทั่วไปแต่ละครั้งได้ 2 เพลง และจำนวนที่หักจริงเป็นไปตามการตั้งราคาในระบบหลังบ้านปัจจุบัน
Max Mode / Variety: เอนด์พอยต์นี้รองรับพารามิเตอร์ทางเลือก max_mode และ variety (0-4) เมื่อเปิด
max_mode ครั้งนี้จะคิดค่าบริการเป็น 2 เท่า (0.6 → 1.2 หยวนต่อครั้ง) ส่วน variety ไม่มีค่าใช้จ่ายเพิ่ม
ความหมายและวิธีส่งดูได้ในหัวข้อ "พารามิเตอร์ขั้นสูง" ของ
ภาพรวม API ใหม่
โมเดลที่แนะนำ: suno-v6
ระยะเวลารอและ timeout (สำคัญ): เอนด์พอยต์นี้เป็นแบบซิงโครนัส — คำสั่งจะถูกรับและส่งเข้าสู่การสร้างเมื่อคำตอบกลับมาเท่านั้น จากการวัด ส่วนใหญ่ตอบกลับภายใน 1-3 วินาที ประมาณ 10% เกิน 30 วินาที และนานที่สุดประมาณ 230 วินาที กรุณาตั้ง timeout ฝั่งไคลเอนต์ไว้ที่ 300 วินาทีขึ้นไป การไม่ได้รับคำตอบไม่ได้หมายความว่าไม่ได้สร้าง และอย่าลองซ้ำทันทีหลัง timeout (จะซ้ำคำสั่งและถูกหักเงินซ้ำ) หากการเชื่อมต่อขาด ให้ตรวจสอบภายหลังด้วย
GET /api/music/songsดูหัวข้อ "ระยะเวลารอและการตั้งค่า timeout" ใน ภาพรวม API ใหม่
พารามิเตอร์คำขอ
Headers
| พารามิเตอร์ | ชนิด | จำเป็น | หมายเหตุ |
|---|---|---|---|
| Authorization | string | ใช่ | Bearer YOUR_API_KEY |
| Content-Type | string | ใช่ | application/json |
พารามิเตอร์บอดี
| พารามิเตอร์ | ชนิด | จำเป็น | ค่าเริ่มต้น | หมายเหตุ |
|---|---|---|---|---|
| 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 สอบถามเพลงและประวัติ และเพลงต้องสร้างเสร็จแล้ว |
voice |
voice_id |
- | 1 | เสียงรุ่นเก่า; voice_id มาจาก API โคลนเสียงและสร้างเพลงด้วยเสียง |
image |
base64 |
- | 1 | ภาพอ้างอิง; ส่งเนื้อหา base64 รูปแบบ data:image/jpeg;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 งานหรือ 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_idsong_idจริงจะปรากฏในการตรวจสอบความคืบหน้าด้านล่าง
ตรวจสอบความคืบหน้าการรับคำสั่ง
เอนด์พอยต์: GET /api/music/requests/{request_id} (ฟรี ยืนยันตัวตนด้วยคีย์ API เดียวกัน)
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 อักขระ): คีย์เดิมส่งซ้ำจะรับเพียงครั้งเดียว ส่งซ้ำจะได้ใบรับเดิมและไม่ถูกหักเงินซ้ำ ในโหมดอะซิงโครนัสเรื่องนี้สำคัญเป็นพิเศษ - เมื่อเปิด
accept_mode=asyncค่าwait_completionจะถูกละเว้น (ใบรับคืนทันที ไม่รอเพลง) - ค่าบริการยังหักล่วงหน้าตอนรับคำสั่ง และหากสร้างไม่สำเร็จจะคืนเงินเต็มจำนวนอัตโนมัติ
- ขีดจำกัดฟิลด์ข้อความ:
descriptionรับได้ไม่เกิน 3000 อักขระ (นับเป็นอักขระ Unicode ตัวอักษรจีนหนึ่งตัวนับเป็น 1) ถ้ายาวกว่านั้นจะคืน HTTP400ทันที ไม่เข้าสู่การสร้างและไม่คิดค่าบริการ โดยข้อความผิดพลาดจะบอกจำนวนที่วัดได้ เช่นdescription must not exceed 3000 characters; received 4120เอนด์พอยต์นี้ไม่มีฟิลด์เนื้อเพลง/สไตล์ หากต้องการดูหัวข้อ "ขีดจำกัดฟิลด์ข้อความ" ใน API สร้างเพลงโหมดกำหนดเอง ส่วนข้อกำหนดทั่วไปอยู่ใน "ขีดจำกัดฟิลด์ข้อความ" ของ ภาพรวม API ใหม่ - ถ้าไม่ส่ง
referencesพฤติกรรม ราคา และคำตอบเหมือนเดิมทุกอย่าง: ผู้ที่เชื่อมต่ออยู่แล้วไม่ต้องแก้โค้ด - เมื่อแนบวัสดุอ้างอิง (โดยเฉพาะเพลงอ้างอิงหลายเพลง) ควรเปลี่ยนไปใช้โหมดใบรับคำสั่ง
accept_mode=asyncแทนการรอซิงโครนัสนาน เวลาเตรียมวัสดุขึ้นกับจำนวนและแหล่งที่มา
ขั้นตอนถัดไป
หากเมื่อคำตอบกลับมาแล้วเพลงยังไม่เสร็จ ให้ใช้ API สอบถามเพลง เพื่อดูผลลัพธ์สุดท้าย
ตัวอย่างการเชื่อมต่อ Node/Electron
หากคุณเชื่อมต่อการสร้างเพลงทั่วไปใน main process ของ Electron เซิร์ฟเวอร์ Node.js หรือไคลเอนต์เดสก์ท็อป ลำดับที่แนะนำคือ:
- เรียก
POST /api/music/createเพื่อสร้างงาน - อ่าน
song_idหรือidจากคำตอบ - เรียก
POST /api/music/queryทุก 2 วินาทีเพื่อตรวจสอบสถานะ - เมื่อผลลัพธ์มี
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 ไว้ในตัวแปรสภาพแวดล้อมของเซิร์ฟเวอร์ ในการตั้งค่าไคลเอนต์เดสก์ท็อป หรือในที่จัดเก็บที่ปลอดภัย — ห้ามใส่ในโค้ดฝั่งหน้าเว็บและห้ามคอมมิตเข้า repository
รับคีย์ API
สร้างคีย์ API ในคอนโซลหลังสมัครสมาชิก การสร้างหนึ่งครั้งราคา 0.6 หยวน ได้ 2 เพลง ดาวน์โหลดไม่จำกัด และไม่ต้องใช้เบอร์โทรศัพท์
รับคีย์ API กลับไปภาพรวม