【แนะนำ】 API โปรไฟล์เสียง

อัปเดต 2026-09-18 · ทีม Suno-API

✅ แนะนำให้ใช้เส้นทางนี้สำหรับการเชื่อมต่อใหม่ จากผลการประเมินจริงของผู้ใช้จำนวนมาก เพลงที่สร้างด้วยเส้นทางนี้รักษาเสียงต้นฉบับได้ดี เสียงร้องในผลงานสำเร็จรูปจะใกล้เคียงกับเจ้าของเสียงในตัวอย่างที่คุณอัปโหลดมากกว่า จึงเป็นเส้นทางที่เราแนะนำให้ลูกค้าในตอนนี้

เปรียบเทียบ: API โคลนเสียงและสร้างเพลงด้วยเสียงที่ระบุ เดิมยังใช้ได้ แต่เมนูระบุว่า "ไม่แนะนำ" และไม่แนะนำสำหรับการเชื่อมต่อใหม่

หมายเหตุ: เอกสารนี้กล่าวถึงเฉพาะเอนด์พอยต์ที่คุณต้องเรียกใช้ ส่วนการจัดการวัสดุ การจัดคิวงาน และการตรวจสอบเนื้อหา เซิร์ฟเวอร์ทำให้อัตโนมัติ ฝั่งไคลเอนต์ไม่ต้องทำ


0. เริ่มต้นในห้านาที

แค่สี่ขั้นตอนก็ได้เพลงสำเร็จรูปสองเพลงจากตัวอย่างเสียงหนึ่งชิ้น

① สร้างเสียง    POST /api/music/voice-profile/create      → รับ voice_id (status=ready)
② คัฟเวอร์      POST /api/music/voice-profile/cover       → รับ song_id 2 รายการทันที
③ ติดตาม        POST /api/music/query                     → โพลจนถึง status=completed
④ ดาวน์โหลด     GET  /api/music/download?song_id=…&kind=mp3

ตัวอย่างน้อยที่สุด (curl):

API_KEY="sk-คีย์ของคุณ"
BASE="https://www.suno-api.io"

# ① สร้างเสียง (อัปโหลดตัวอย่างเสียง แนะนำ 10 วินาทีขึ้นไป ไม่เกิน 10MB)
curl -sS -X POST "$BASE/api/music/voice-profile/create" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@./my-voice.mp3" \
  -F "title=เสียงของฉัน" \
  -F "source_kind=upload"
# → {"success":true,"message":"","data":{"voice_id":"vp_2026…","status":"ready", …}}

# ② ใช้เสียงนี้คัฟเวอร์เพลงหนึ่งเพลง (song_clip_id = clip id ของเพลงที่จะคัฟเวอร์)
curl -sS -X POST "$BASE/api/music/voice-profile/cover" \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Create-Ui-Client-Request-Id: cover-$(date +%s)" \
  -H "Content-Type: application/json" \
  -d '{
        "model": "suno-v6",
        "voice_id": "vp_2026…",
        "song_clip_id": "5b773e9a-…",
        "lyrics": "[Verse 1]\nเนื้อเพลง…",
        "style_requirements": "โฟล์กช้า ๆ กีตาร์อะคูสติก",
        "audio_weight": 0.85,
        "max_mode": false
      }'
# → {"code":200,"message":"success","data":{"resolved_scene":"cover","clips":[{…},{…}]}}

# ③ โพล (ส่งหลาย id ครั้งเดียว คั่นด้วยเครื่องหมายจุลภาค)
curl -sS -X POST "$BASE/api/music/query" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"suno-v6","song_ids":"id1,id2"}'

# ④ ดาวน์โหลด mp3 เมื่อเสร็จ (ต้อง status=completed เท่านั้นจึงได้ไฟล์)
curl -sS -L "$BASE/api/music/download?song_id=id1&kind=mp3" \
  -H "Authorization: Bearer $API_KEY" -o song1.mp3

1. ข้อตกลงทั่วไป

1.1 โดเมนและสภาพแวดล้อม

สภาพแวดล้อม Base URL การใช้งาน
โปรดักชัน https://www.suno-api.io ทราฟฟิกลูกค้าจริง

ทุกพาธด้านล่างเป็นพาธสัมพัทธ์กับ Base URL เช่นที่อยู่เต็มของ POST /api/music/voice-profile/create คือ https://www.suno-api.io/api/music/voice-profile/create

1.2 การยืนยันตัวตน

ทุกเอนด์พอยต์ใช้เฮดเดอร์เดียวกัน โดยค่าคือ API Key ที่คุณสร้างในคอนโซล:

Authorization: Bearer sk-xxxxxxxx

1.3 รูปแบบเนื้อหาคำขอ

1.4 เปลือกคำตอบสองแบบ (ลูกค้าต้องรู้แค่สองแบบนี้)

เอนด์พอยต์กลุ่ม "จัดการเสียง" (create / create-from-clip / list / detail / delete) ใช้เปลือกงานธุรกิจ:

{ "success": true, "message": "", "data": { } }
{ "success": false, "message": "voice_id is required" }

"คัฟเวอร์ด้วยเสียง" ผ่านช่องทางสร้างเพลง ใช้เปลือกการสร้าง: สำเร็จคือ code/message/data ล้มเหลวคือออบเจกต์ error:

{ "code": 200, "message": "success", "data": { } }
{ "error": { "message": "voice not found: vp_xxx", "type": "bad_response_status_code", "param": "", "code": "bad_response_status_code" } }

วิธีตัดสิน: ดูรหัสสถานะ HTTP ก่อน แล้วดู success === false สุดท้ายดู code !== 200 หรือมี error ความล้มเหลวทางธุรกิจไม่ได้การันตีว่า HTTP จะไม่ใช่ 200 (เอนด์พอยต์จัดการเสียงเมื่อผิดพลาดยังคืน HTTP 200) จึงดูแค่รหัสสถานะไม่ได้

1.5 ความคงที่ของการเรียกซ้ำ (idempotency)

การสร้างเสียง (รวม "สร้างจากไฟล์เสียงที่มีอยู่") คงที่จริง: ภายใต้คีย์เดียวกัน การส่ง client_request_id เดิมซ้ำจะสร้างเสียงเพียงรายการเดียว ครั้งที่สองจะคืนผลลัพธ์ครั้งแรกโดยตรง (success=true, voice_id เดิม) วิธีใช้คือให้ไคลเอนต์สร้าง id เอง (เช่น UUID) แล้วใช้ค่าเดิมเมื่อลองใหม่หลังหมดเวลา

การส่งคัฟเวอร์ไม่ทำการตัดข้อมูลซ้ำระดับคำขอ (เป็นการสร้างที่มีค่าใช้จ่าย) จึงควรทราบสองเรื่อง:

  1. ตัวระบุการส่งอยู่ในเฮดเดอร์ X-Create-Ui-Client-Request-Id: <id การส่งของคุณ> มันจะถูกเขียนลงบันทึกงานฝั่งเซิร์ฟเวอร์เพื่อให้ตรวจสอบย้อนหลังได้ แต่ไม่ป้องกันการคิดเงินซ้ำ
  2. หมดเวลา ≠ ล้มเหลว คำขออาจถูกรับไปแล้วและกำลังสร้าง ควรตรวจด้วย GET /api/music/songs?p=1&page_size=20 (พารามิเตอร์แบ่งหน้าคือ p / page_size และเขียนแบบเข้ากันได้คือ ps) ก่อนลองใหม่ ว่ามีเพลงใหม่ที่ generation_type=voice_profile_cover โผล่มาหรือยัง ถ้าไม่มีจึงส่งซ้ำ

เนื้อหาของ create และ create-from-clip ก็มีฟิลด์ client_request_id (ดู §3, §4)

1.6 ภาพรวมค่าบริการ

การกระทำ เอนด์พอยต์ ราคา หมายเหตุ
สร้างเสียง (ปกติ) POST /api/music/voice-profile/create ฟรี อัปโหลดตัวอย่างไม่กินโควตา Suno
สร้างเสียง (จากไฟล์เสียงที่มีอยู่) POST /api/music/voice-profile/create-from-clip ฟรี เซิร์ฟเวอร์แค่ลงทะเบียนอ้างอิงวัสดุ ไม่ต้องอัปโหลดซ้ำ
โคลนแบบเสริม เหมือนกัน enhanced=true ตาม "ราคาอัปโหลดแบบเสริม" (ค่าเริ่มต้น 10 หยวนต่อครั้ง) ไม่รอผล ล้มเหลวคืนเงินอัตโนมัติ
คัฟเวอร์ด้วยเสียง POST /api/music/voice-profile/cover 1.2 หยวนต่อครั้ง, เมื่อ max_mode=true 2.4 หยวนต่อครั้ง หนึ่งครั้งคืน 2 เพลง
สอบถาม / รายการ / รายละเอียด / ลบ — ฟรี
ดาวน์โหลด (เอาลิงก์ตรงเอง) audio_url ในคำตอบ ฟรี เล่นที่อยู่ที่ออกให้
ดาวน์โหลด (แปลง wav / เนื้อเพลง ฯลฯ) POST /api/music/free2 0.2 หยวนต่อเพลงที่สำเร็จ ดู §8

ราคาอ่านได้ทุกเมื่อจากเอนด์พอยต์สาธารณะ จึงไม่ควรเขียนตายตัว (ดู §9):

curl -sS https://www.suno-api.io/api/pricing/catalog | jq '.data.catalog.meta'
# {
#   "generation_price": "0.6",
#   "voice_generation_price": "1.2",      ← ราคาพื้นฐานของการคัฟเวอร์ด้วยเสียง
#   "max_mode_factor": "2",
#   "enhanced_upload_price": "10",        ← ราคาโคลนแบบเสริม
#   "voice_auto_verify_price": "5",
#   "voice_long_term_clone_price": "5"
# }

การคัฟเวอร์ใช้รูปแบบหักล่วงหน้า + คืนเงินเมื่อล้มเหลว:

1.7 พจนานุกรมสถานะ

status ของเสียง:

ค่า ความหมาย ใช้คัฟเวอร์ได้
ready พร้อมใช้ ✅
processing เกิดเฉพาะโคลนแบบเสริม (enhanced=true) กำลังประมวลผล ❌ (รอ ready)
failed สร้างไม่สำเร็จ ดู error_message; โคลนแบบเสริมคืนเงินแล้ว ❌

status ของเพลง (ค่าที่เอนด์พอยต์สอบถามคืนมา):

ค่า ความหมาย ดาวน์โหลดได้
submitted / queued / processing กำลังสร้าง (อาจมีสตรีมฟังตัวอย่างแล้ว) ❌
completed เสร็จ ✅
failed ล้มเหลว คืนค่าบริการแล้ว ❌

2. ภาพรวมเอนด์พอยต์

# เมธอด พาธ หน้าที่ ค่าบริการ
1 POST /api/music/voice-profile/create สร้างเสียง (อัปโหลด / URL / base64) ฟรี (ยกเว้น enhanced=true)
2 POST /api/music/voice-profile/create-from-clip สร้างเสียงจากไฟล์เสียงที่มีอยู่ ฟรี
3 GET /api/music/voice-profile/list รายการเสียง ฟรี
4 GET /api/music/voice-profile/{voice_id} รายละเอียดเสียง (รวมความคืบหน้าโคลนแบบเสริม) ฟรี
5 POST /api/music/voice-profile/delete ลบเสียง ฟรี
6 POST /api/music/voice-profile/cover คัฟเวอร์ด้วยเสียง / ร้องเพลงใหม่ 1.2 หยวน (MAX 2.4)
7 POST /api/music/query สอบถามสถานะเพลงแบบกลุ่ม ฟรี
8 GET /api/music/songs/{song_id} รายละเอียดเพลงเดียว ฟรี
9 GET /api/music/download ดาวน์โหลดไฟล์สำเร็จรูป ฟรี (mp3/ลิงก์เล่น)
10 POST /api/music/free2 แปลง wav / เนื้อเพลง ฯลฯ 0.2 หยวนต่อเพลงที่สำเร็จ
11 POST /api/music/free2/cached ขอที่อยู่ดาวน์โหลดที่เก็บถาวรแล้ว ฟรี
12 GET /api/music/songs รายการผลงานของฉัน (แบ่งหน้า) ฟรี

3. สร้างเสียง

POST /api/music/voice-profile/create

ลงทะเบียนไฟล์เสียงร้องหนึ่งช่วงเป็น "เสียง" แล้วได้ voice_id สำหรับแพลตฟอร์ม เสียงคือ "ไฟล์เสียงหนึ่งไฟล์ + clip ของมันในคลัง" ดังนั้นเมื่อสร้างสำเร็จ ไฟล์เสียงต้นฉบับจะถูกเก็บถาวร (ใช้คัฟเวอร์ต่อไป)

3.1 รูปแบบอินพุตสามแบบ (เลือกหนึ่ง)

แบบ A: อัปโหลดไฟล์ multipart (แนะนำ)

Content-Type: multipart/form-data

file=<ข้อมูลไบนารีเสียง>      # จำเป็น
title=<ชื่อเสียง>              # ไม่บังคับ ถ้าว่างจะใช้ชื่อไฟล์ตัดนามสกุล
file_name=<ชื่อไฟล์เดิม>
source_file_name=<ชื่อไฟล์เดิม>
source_kind=upload|record     # ไม่บังคับ เครื่องหมายที่มา (อัปโหลด / อัดเสียง) ค่าเริ่มต้น upload
enhanced=false|true           # ไม่บังคับ true = โคลนแบบเสริม (ดู §3.5)
client_request_id=<คีย์กันซ้ำ>  # ไม่บังคับ
voice_id=<ID ที่กำหนดเอง>       # ไม่บังคับ ปกติไม่ใช้
curl -sS -X POST "https://www.suno-api.io/api/music/voice-profile/create" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@./my-voice.mp3;type=audio/mpeg" \
  -F "file_name=my-voice.mp3" \
  -F "source_file_name=my-voice.mp3" \
  -F "title=เสียงของฉัน" \
  -F "source_kind=upload"

แบบ B: JSON + URL ไฟล์เสียงสาธารณะ

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": "เสียงของฉัน"
      }'

แบบ C: JSON + base64

{
  "file_base64": "data:audio/mpeg;base64,//uQxAAA…",
  "file_name": "my-voice.mp3",
  "title": "เสียงของฉัน"
}

3.2 ข้อกำหนดของไฟล์เสียง

หัวข้อ ข้อกำหนด หมายเหตุ
ขนาด ≤ 10MB เกินกำหนดเกตเวย์จะตัดเนื้อหา ทำให้ดูเหมือน "ถูก Suno ปฏิเสธ" ควรบีบอัดหรือตัดให้สั้นก่อน
ความยาว อย่างน้อย 6 วินาที แนะนำ 10–60 วินาที ต่ำกว่า 6 วินาทีแพลตฟอร์มจะปฏิเสธ: Uploaded audio is too short (currently 2.4 seconds). Minimum duration is 6 seconds.
รูปแบบ mp3 / wav / m4a / aac / flac / ogg ตัดสินจากนามสกุลไฟล์
เนื้อหา เสียงร้องสะอาด หลีกเลี่ยงผลงานคัฟเวอร์หรือเพลงต้นฉบับที่มีดนตรีประกอบ เสียงที่เหมือนบันทึกในคลังมากจะถูกปฏิเสธ: This audio matches an existing recording in our catalog. (วัดผล)

3.3 คำตอบ

{
  "success": true,
  "message": "",
  "data": {
    "voice_id": "vp_20260926080618509168500DXXrxe",
    "clip_id": "91cc5935-389f-4193-b56b-cc796c15562d",
    "song_id": "91cc5935-389f-4193-b56b-cc796c15562d",
    "account_id": "acc_1790085275308",
    "title": "เสียงของฉัน",
    "source_file_name": "my-voice.mp3",
    "audio_url": "https://suno-api-p-1437223057.cos.ap-guangzhou.myqcloud.com/create-ui/voice-source/2026/09/26/xxx.mp3",
    "image_url": "https://cdn2.suno.ai/image_91cc5935-389f-4193-b56b-cc796c15562d.jpeg",
    "duration_s": 29.18,
    "enhanced": false,
    "source_kind": "upload",
    "status": "ready",
    "client_request_id": "",
    "created_at": 1790409978,
    "updated_at": 1790409998
  }
}

คำอธิบายฟิลด์ (create / list / detail ใช้ชุดฟิลด์เดียวกัน):

ฟิลด์ ชนิด คำอธิบาย
voice_id string ID เสียง ใช้คัฟเวอร์ต่อไป
clip_id / song_id string clip id ของไฟล์เสียงนี้ฝั่ง Suno (สองค่าเท่ากัน) ใช้ตรวจสอบ
account_id string ตัวระบุบัญชีที่รองรับ (ใช้ตรวจสอบ ไคลเอนต์ไม่ต้องสนใจ)
title string ชื่อเสียง
source_file_name string ชื่อไฟล์เดิม
audio_url string ลิงก์ตรงระยะยาวของไฟล์เสียงต้นฉบับ ใช้ฟังตัวอย่างได้ เก็บถาวร
image_url string ภาพปกเสียง (ที่ Suno สร้างให้ไฟล์เสียงร้อง) ถ้าไม่มีปกคีย์นี้จะไม่ปรากฏเลย
duration_s number ความยาวตัวอย่างเสียง (วินาที)
enhanced bool สร้างด้วยโคลนแบบเสริมหรือไม่
source_kind string upload / record / clip (จากไฟล์เสียงที่มีอยู่)
status string ready / processing / failed
error_message string สาเหตุล้มเหลว ปรากฏเฉพาะ failed
task_id number หมายเลขงานเบื้องหลังของโคลนแบบเสริม มีค่าเฉพาะ enhanced=true
pre_consumed_quota number โควตาหักล่วงหน้า (มีค่าเฉพาะโคลนแบบเสริม)
created_at / updated_at number วินาทีแบบ Unix

created_at / updated_at เป็นตราเวลาระดับวินาที (10 หลัก) ไม่ใช่มิลลิวินาที

3.4 ข้อผิดพลาดที่พบบ่อย

HTTP message สาเหตุและวิธีแก้
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. ตัวอย่างคล้ายบันทึกในคลังมาก เปลี่ยนเป็นเสียงร้องแห้งที่สะอาด
200 upload succeeded without clip or account identity คำตอบจากแพลตฟอร์มผิดปกติ ลองใหม่
200 audio file exceeds 30 MB limit เกินขีดจำกัดเซิร์ฟเวอร์ (ฝั่งลูกค้าให้คุมที่ 10MB)
401 invalid token API Key ผิด

3.5 โคลนแบบเสริม (enhanced=true)

ใช้กับกรณี "ตัวอย่างเสียงมีเนื้อเพลงที่มีลิขสิทธิ์ / ต้องอัปโหลดแบบเสริม" ราคาตามราคาอัปโหลดแบบเสริม (ค่าเริ่มต้น 10 หยวนต่อครั้ง ล้มเหลวคืนเงินอัตโนมัติ):

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"

4. สร้างเสียงจากไฟล์เสียงที่มีอยู่

ถ้าไม่อยากอัปโหลดใหม่: คัดลอกไฟล์เสียงที่คุณอัปโหลดแล้วหรือสร้างแล้วมาเป็นเสียงได้เลย ฟรีและกันซ้ำ

POST /api/music/voice-profile/create-from-clip
Content-Type: application/json

{
  "source_song_id": "97ee62fe-56cd-473f-a2f5-c66ac0766a2e",
  "title": "Xu Qing Qiang",
  "client_request_id": "vp-clip-1789…"
}

คำตอบคือทุกฟิลด์ใน §3.3 บวกอีกสองฟิลด์แบบอ่านอย่างเดียว:

ฟิลด์ คำอธิบาย
reused true = ไฟล์เสียงนี้เป็นเสียงของคุณอยู่แล้วและถูกนำมาใช้ซ้ำ
source_type ที่มาของไฟล์เสียง: generate / custom_generate / voice_generate / upload_source / enhanced_upload
{
  "success": true,
  "data": {
    "voice_id": "vp_20260926081712557959800Z5gvlt",
    "clip_id": "97ee62fe-56cd-473f-a2f5-c66ac0766a2e",
    "title": "Xu Qing Qiang",
    "status": "ready",
    "enhanced": true,
    "reused": true,
    "source_type": "enhanced_upload"
  }
}

ข้อผิดพลาด (message ตามต้นฉบับ แนะนำให้แสดงตรง ๆ หรือแปล):

message ความหมาย
source audio not found clip ไม่มีอยู่หรือไม่ใช่ของคุณ
source audio is invalid ไฟล์เสียงนั้นยังสร้างอยู่ / เป็นผลผลิตรอบกลาง ยังใช้ไม่ได้
source_song_id is required ไม่ได้ส่ง source_song_id

5. รายการ / รายละเอียด / ลบเสียง

5.1 รายการ

GET /api/music/voice-profile/list
GET /api/music/voice-profile/list?include_deleted=true
{
  "success": true,
  "message": "",
  "data": {
    "items": [ { "voice_id": "vp_…", "title": "เสียงของฉัน", "status": "ready", "audio_url": "…", "image_url": "…" } ],
    "total": 1
  }
}

ฟิลด์เหมือน §3.3 ทั้งหมด ค่าเริ่มต้นจะไม่คืนเสียงที่ถูกลบ

5.2 รายละเอียด

GET /api/music/voice-profile/{voice_id}

คืนออบเจกต์เสียงหนึ่งรายการ (data เป็นออบเจกต์เอง ไม่ใช่อาร์เรย์) เมื่อโคลนแบบเสริมกำลังทำงาน จะมีเพิ่ม:

ฟิลด์ คำอธิบาย
progress_percent จำนวนเต็ม 0–100
progress_stage ตัวระบุขั้น เช่น media_preparing
progress_message ข้อความความคืบหน้าสำหรับแสดงต่อผู้ใช้

5.3 ลบ

POST /api/music/voice-profile/delete
Content-Type: application/json

{ "voice_id": "vp_2026…" }
{ "success": true, "message": "", "data": { "voice_id": "vp_2026…", "status": "deleted" } }

6. คัฟเวอร์ด้วยเสียง (เอนด์พอยต์หลัก)

POST /api/music/voice-profile/cover
Content-Type: application/json

หนึ่งครั้งสร้าง 2 เพลง (เหมือนการสร้างปกติ)

6.1 สองสถานการณ์

สถานการณ์ เงื่อนไข คำอธิบาย
A คัฟเวอร์เพลงที่ระบุ ส่ง song_clip_id ร้องเพลงนั้นด้วยเสียงของคุณ (ทำนอง / จังหวะ / ท่อน ตามต้นฉบับ เปลี่ยนเสียงร้องเป็นของคุณ)
B ร้องเพลงใหม่ด้วยเสียง ไม่ส่ง song_clip_id ให้แค่เสียง + เนื้อเพลง (ไม่บังคับ) + ความต้องการด้านสไตล์ ให้โมเดลแต่งทำนองใหม่ตามสไตล์แล้วร้อง

resolved_scene ในคำตอบจะสะท้อน cover หรือ sing เพื่อยืนยันว่าใช้เส้นทางไหน

6.2 ฟิลด์คำขอ

ฟิลด์ ชนิด จำเป็น ค่าเริ่มต้น คำอธิบาย
model string ใช่ — ชื่อโมเดลสำหรับลูกค้า ดู §6.5 ไม่ส่งจะได้ model is required (HTTP 500)
voice_id string อย่างใดอย่างหนึ่ง — ID เสียง (vp_…) ต้อง status=ready
voice_clip_id string อย่างใดอย่างหนึ่ง — ใช้ clip id ของเสียงโดยตรงก็ได้ ถ้าส่งทั้งคู่จะใช้ voice_id
song_clip_id string ไม่ ว่าง clip id (song_id) ของเพลงที่จะคัฟเวอร์ ไม่ส่ง = สถานการณ์ B
lyrics string ไม่ ว่าง เนื้อเพลงทั้งหมด ส่งทีละตัวอักษร ไม่ดัดแปลงหรือตัดทอน; ≤ 3000 ตัวอักษร
cover_requirements string ไม่ ว่าง ความต้องการคัฟเวอร์ (ภาษาธรรมชาติ) เช่น "ออกเสียงชัดขึ้น" จะถูกต่อเข้ากับพรอมป์ตคงที่
style_requirements string ไม่ ว่าง ความต้องการด้านสไตล์ เช่น "โฟล์กช้า ๆ กีตาร์อะคูสติก"
title string ไม่ ว่าง ชื่อเพลงสองเพลงนี้ในเวิร์กสเปซ (มีผลกับ song_title ที่คืนในการสอบถามภายหลัง)
negative_tags string ไม่ ว่าง สไตล์ที่ตัดออก เช่น อีเลกทรอนิก, แรป; ≤ 1000 ตัวอักษร
vocal_gender string ไม่ ว่าง m / f (รับ male / female ด้วย) ว่าง = ไม่จำกัด
duration number ไม่ ว่าง ความยาวที่ต้องการ (วินาที) จำนวนเต็ม 1–480 ว่าง = แพลตฟอร์มกำหนดเอง ค่าต่ำสุดจริงของแพลตฟอร์มประมาณ 30 วินาที: ใส่ค่าน้อยกว่านั้น ผลวัดก็ยังได้ประมาณ 30 วินาที
audio_weight number ไม่ 0.85 Audio Influence ค่าทศนิยม 0–1 ยิ่งสูงยิ่งใกล้ตัวอย่างเสียง
style_weight number ไม่ ว่าง อิทธิพลของสไตล์ ทศนิยม 0–1
weirdness_constraint number ไม่ ว่าง ความสร้างสรรค์ ทศนิยม 0–1 (ถ้าหน้าจอใช้เปอร์เซ็นต์ให้หาร 100)
variety number ไม่ ว่าง ความหลากหลาย จำนวนเต็ม 0–4 (ไม่ใช่เปอร์เซ็นต์) รองรับเฉพาะตระกูล v6
max_mode boolean ไม่ false Max Mode ราคา ×2
client_request_id string ไม่ ว่าง ตัวระบุการส่ง เขียนลงบันทึกงานฝั่งเซิร์ฟเวอร์เพื่อตรวจสอบ (ไม่ตัดข้อมูลซ้ำ)

แนะนำให้ส่งเฮดเดอร์ X-Create-Ui-Client-Request-Id: <id การส่งเดียวกัน> ด้วย: มีแต่มันที่จะถูกเขียนลงบันทึกงานฝั่งเซิร์ฟเวอร์ และเป็นคีย์หลักในการตรวจสอบย้อนหลัง (ดู §1.5)

ข้อควรระวังหน่วย: audio_weight / style_weight / weirdness_constraint เป็นทศนิยม 0–1 variety เป็นจำนวนเต็ม 0–4 duration เป็นวินาที ถ้าใช้ปนกันจะถูกปฏิเสธหรือผลผิดปกติ

เนื้อเพลงในสถานการณ์ B ไม่บังคับ (โมเดลจัดการเอง) แต่ถ้าต้องการให้ร้องเนื้อหาที่กำหนดต้องส่ง lyrics

6.3 คำตอบ

{
  "code": 200,
  "message": "success",
  "data": {
    "voice_id": "vp_20260926081712557959800Z5gvlt",
    "voice_clip_id": "97ee62fe-56cd-473f-a2f5-c66ac0766a2e",
    "song_clip_id": "5b773e9a-a035-4134-a4a4-29c9961d3ccb",
    "resolved_scene": "cover",
    "model": "suno-v6",
    "audio_weight": 0.85,
    "clips": [
      {
        "song_id": "0f2a…",
        "status": "processing",
        "song_title": "",
        "model_version": "suno-v6",
        "audio_url": "",
        "play_url": "https://media.suno-api.io/play/0f2a…?expires=…&signature=…",
        "lyrics": "",
        "description": "[งาน] นี่คือการคัฟเวอร์ … (ส่วนโครงสร้างคงที่ของเซิร์ฟเวอร์ + ความต้องการคัฟเวอร์ / สไตล์ที่คุณกรอก)"
      },
      {
        "song_id": "7c91…",
        "status": "processing",
        "model_version": "suno-v6",
        "audio_url": ""
      }
    ],
    "source_updates": []
  }
}

จุดสำคัญ:

  1. ระบุผลงานสำเร็จรูปด้วย clips[].song_id (เอนด์พอยต์นี้ไม่คืนฟิลด์ id)
  2. ได้ song_id 2 รายการทันที แต่ตอนนั้น status ยังเป็น processing (แค่หมายถึงถูกรับแล้ว) และ audio_url ว่าง ต้องโพลถึง completed จึงดาวน์โหลดได้ play_url เป็นสตรีมฟังตัวอย่างของแพลตฟอร์ม อาจปรากฏตั้งแต่ขั้นส่ง และจะหมดอายุ
  3. description คือพรอมป์ตที่เซิร์ฟเวอร์ส่งจริงครั้งสุดท้าย (ส่วนโครงสร้างคงที่ + cover_requirements / style_requirements ที่คุณกรอก) ใช้ตรวจสอบผลได้ดี
  4. source_updates เป็นผลจัดการวัสดุของเซิร์ฟเวอร์ ไคลเอนต์ไม่ต้องสนใจ
  5. title ที่คุณส่งจะถูกเขียนลงบันทึกงานฝั่งเซิร์ฟเวอร์ และแสดงเป็น song_title ในการสอบถามภายหลัง ส่วน clips[].song_title ในคำตอบตอนส่งมักว่าง เป็นเรื่องปกติ

6.4 ข้อผิดพลาด

{ "error": { "message": "เสียงนี้ไม่มีอยู่หรือถูกลบแล้ว (voice_id=vp_xxx)…", "type": "new_api_error", "param": "", "code": "invalid_request" } }
HTTP message สาเหตุ
500 model is required เนื้อหาขาด model (ฟิลด์จำเป็นสำหรับเลือกช่องทาง)
400 voice_id is required and must be a ready voice ไม่ได้ส่ง voice_id หรือส่งค่าตัวแทน / เสียงที่ยังไม่พร้อม
400 เสียงนี้ไม่มีอยู่หรือถูกลบแล้ว (voice_id=vp_xxx)… เสียงถูกลบ ไม่มีอยู่ หรือไม่ใช่ของบัญชีปัจจุบัน เปลี่ยนไปใช้เสียงอื่นหรือสร้างใหม่
400 เสียงนี้ถูกลบแล้ว (voice_id=vp_xxx)… เมื่อส่งวัสดุตรงด้วย voice_clip_id แล้วเสียงของวัสดุนั้นถูกลบ วิธีแก้เหมือนข้างบน
400 voice is not ready yet (status=processing) เสียงยังสร้างอยู่ รอ ready แล้วลองใหม่
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 หน่วยสไลเดอร์ผิด (ส่งเป็นเปอร์เซ็นต์)
400 duration must be an integer between 1 and 480 seconds ความยาวไม่ใช่จำนวนเต็ม 1–480
400 vocal_gender must be one of m, f, male, female ค่าเพศไม่ถูกต้อง
400 variety must be an integer between 0 and 4 / variety is only supported on v6 models ค่าความหลากหลายหรือโมเดลไม่รองรับ

ยอดเงินไม่พอจะคืนข้อผิดพลาดการคิดเงินทันทีตอนส่ง และไม่ทิ้งงานค้างครึ่งทาง

6.5 โมเดลที่ใช้ได้ (ชื่อสำหรับลูกค้า)

ชื่อโมเดล คำอธิบาย
suno-v6 ค่าเริ่มต้น แนะนำ
suno-v6-wild ปล่อยอิสระกว่า
suno-v6-mini เบา

ใช้ชื่อโมเดลสำหรับลูกค้า (ตามข้างบน) ส่วน chirp-* เป็นชื่อภายในของแพลตฟอร์ม ไม่ควรใช้ตรง ๆ


7. ติดตามความคืบหน้า

7.1 สอบถามแบบกลุ่ม (แนะนำ)

POST /api/music/query
Content-Type: application/json

{ "model": "suno-v6", "song_ids": "id1,id2" }
[
  {
    "song_id": "0f2a…",
    "song_title": "เสือสองตัว",
    "status": "completed",
    "audio_url": "https://suno-api-hk-1437223057.cos.ap-hongkong.myqcloud.com/assets/0f2a…-mp3.mp3",
    "cover_url": "https://cdn2.suno.ai/image_0f2a….jpeg",
    "duration": 115.15,
    "model_version": "suno-v6",
    "generation_type": "voice_profile_cover",
    "play_url": "https://media.suno-api.io/play/…?expires=…&signature=…",
    "lyrics": "[Verse 1]…",
    "prompt": "[Verse 1]…",
    "description": "[งาน] นี่คือการคัฟเวอร์ … (พรอมป์ตสุดท้ายของเซิร์ฟเวอร์)",
    "style_tags": "…",
    "created_at": "2026-09-25T18:19:09.918Z",
    "video_url": ""
  }
]
ฟิลด์ คำอธิบาย
status ดู §1.7 ต้องเป็น completed จึงนับว่าเสร็จ
audio_url ลิงก์ตรง mp3 มีค่าเมื่อ completed เท่านั้น
cover_url ที่อยู่ภาพปก
duration ความยาวจริง (วินาที)
generation_type เพลงจากคัฟเวอร์ด้วยเสียงจะเป็น voice_profile_cover เสมอ
play_url ที่อยู่ฟังตัวอย่างแบบมีลายเซ็น (หมดอายุ)
song_title ชื่อของงาน (คือ title ที่ส่ง ถ้าไม่ส่งเซิร์ฟเวอร์จะใส่ให้)
lyrics / prompt เนื้อเพลงสำเร็จรูป / เนื้อเพลงต้นฉบับ
description พรอมป์ตที่เซิร์ฟเวอร์ส่งจริงครั้งสุดท้าย (รวมส่วนโครงสร้างคงที่)
style_tags คำอธิบายสไตล์สุดท้าย
created_at สตริง ISO 8601 (ระวังต่างจากวินาทีแบบ Unix ของเอนด์พอยต์รายละเอียด)

คำแนะนำการโพล: ทุก 5–10 วินาที หมดเวลารวม 10–15 นาที (บัญชี "เย็น" ที่ช้าที่สุดวัดได้ประมาณ 4 นาทีครึ่ง น้อยมากที่นานกว่า) อย่าตัดสินว่าเสร็จจาก audio_url ว่าง ให้ดู status

หมายเหตุความเข้ากันได้: เอนด์พอยต์นี้ใช้ song_id เป็นตัวระบุ ในคำตอบยุคแรกบางรายการมีฟิลด์ id จึงควรเขียนเป็น row.song_id || row.id

7.2 รายละเอียดเพลงเดียว

GET /api/music/songs/{song_id}
{
  "success": true,
  "data": {
    "song_id": "0f2a…",
    "title": "เสือสองตัว",
    "status": "completed",
    "generation_type": "voice_profile_cover",
    "model": "suno-v6",
    "duration": 115.15,
    "audio_url": "https://…/assets/0f2a…-mp3.mp3",
    "image_url": "https://cdn2.suno.ai/image_0f2a….jpeg",
    "wav_url": "https://www.suno-api.io/api/music/download?song_id=0f2a…&kind=wav",
    "video_url": "https://www.suno-api.io/api/music/download?song_id=0f2a…&kind=video",
    "created_at": 1790411012,
    "completed_at": 1790411500,
    "parameters": {
      "prompt": "[Verse 1]…",
      "style_tags": "…",
      "title": "เสือสองตัว",
      "model": "suno-v6",
      "generation_type": "voice_profile_cover",
      "source_song_id": "5b773e9a-…"
    },
    "parameter_retention": {
      "core_parameters_available": true,
      "extended_parameters_available": false,
      "sources": ["suno_tasks"],
      "unavailable_fields": ["negative_tags", "vocal_gender", "style_weight", "weirdness_constraint"]
    }
  }
}

7.3 ผลงานของฉัน

GET /api/music/songs?p=1&page_size=20
GET /api/music/songs?status=completed&q=คำค้น

พารามิเตอร์แบ่งหน้า: p (เลขหน้า เริ่มที่ 1) / page_size (จำนวนต่อหน้า เขียนแบบเข้ากันได้คือ ps) เสริมได้ด้วย status และ q (คำค้นในชื่อเพลง) ค่าเริ่มต้นเรียงตามเวลาสร้างจากใหม่ไปเก่า

{
  "success": true,
  "data": {
    "page": 1,
    "page_size": 20,
    "total": 42,
    "items": [
      {
        "song_id": "0f2a…",
        "title": "เสือสองตัว",
        "status": "completed",
        "generation_type": "voice_profile_cover",
        "model": "suno-v6",
        "duration": 115.15,
        "audio_url": "https://…/assets/0f2a…-mp3.mp3",
        "image_url": "https://cdn2.suno.ai/image_0f2a….jpeg",
        "created_at": 1790411012,
        "completed_at": 1790411500
      }
    ]
  }
}

ใช้ generation_type=voice_profile_cover แยก "เพลงที่เกิดจากคัฟเวอร์ด้วยเสียง" ออกจากผลการสร้างอื่นได้


8. ดาวน์โหลดผลงาน

8.1 เอา mp3 ตรง ๆ (แนะนำ ฟรี)

ทำได้ทั้งสามวิธี เลือกอย่างหนึ่ง:

  1. ใช้ audio_url จากผลการสอบถาม (ลิงก์ตรงไปยังออบเจกต์สตอเรจ สะดวกที่สุด)
  2. GET /api/music/download?song_id=<id>&kind=mp3 → คืนสตรีมไบต์เสียงโดยตรง (Content-Disposition มีชื่อไฟล์แล้ว)
  3. POST /api/music/download-url (ขอที่อยู่ชั่วคราวแบบมีลายเซ็น)
curl -sS -L "https://www.suno-api.io/api/music/download?song_id=0f2a…&kind=mp3" \
  -H "Authorization: Bearer $API_KEY" -o song.mp3

ค่า kind: mp3 (เทียบเท่า song) / playback (เล่นแบบสตรีม) / wav / video / lyrics / timestamped_lyrics timestamped_lyrics (.lrc) ปัจจุบันรองรับเฉพาะบางเพลง ถ้าล้มเหลวให้ใช้ API เนื้อเพลงมีมาร์กเวลา สร้างเอง คำตอบเป็นสตรีมไบต์ของไฟล์ Content-Type และ Content-Disposition (ชื่อไฟล์) พร้อมแล้ว ส่วน wav_url / video_url ที่ GET /api/music/songs/{song_id} คืนมาคือทางเข้าเดียวกันแบบ kind=wav|video

8.2 แปลง wav / เนื้อเพลง / ข้อมูลเมตา (มีค่าใช้จ่าย)

POST /api/music/free2
Content-Type: application/json

{ "song_ids": ["0f2a…"], "files": ["mp3", "wav", "lyrics"] }
{
  "success": true,
  "data": {
    "songs": [
      { "song_id": "0f2a…", "files": [ { "type": "mp3", "url": "https://…" }, { "type": "wav", "url": "https://…" } ] }
    ],
    "requested_songs": 1,
    "succeeded_songs": 1,
    "price": 0.2
  }
}

9. สอบถามราคา

GET /api/pricing/catalog

เอนด์พอยต์สาธารณะ ไม่ต้องยืนยันตัวตน ราคาต่อหน่วยที่ต้องแสดงต่อลูกค้าอยู่ใน data.catalog.meta (สตริง):

คีย์ ความหมาย ค่าปัจจุบัน
generation_price สร้างเพลงทั่วไป 0.6
voice_generation_price ราคาพื้นฐานของการคัฟเวอร์ด้วยเสียง 1.2
max_mode_factor ตัวคูณ Max Mode 2
enhanced_upload_price โคลนแบบเสริม / อัปโหลดแบบเสริม 10
voice_auto_verify_price ตรวจสอบเสียงอัตโนมัติ 5
voice_long_term_clone_price โคลนเสียงระยะยาว 5

ราคาถูกปรับในหลังบ้าน ควรอ่านแบบเรียลไทม์ ไม่ควรเขียนตายในไคลเอนต์ ค่าบริการคัฟเวอร์จริง = voice_generation_price × (ถ้า max_mode เป็นจริงคูณ max_mode_factor อีก)


10. ข้อจำกัดและข้อควรระวัง

  1. ขนาดอัปโหลด: ≤ 10MB (เซิร์ฟเวอร์รับได้มากกว่า แต่เกตเวย์ทางเข้าจะตัดเนื้อหาขนาดใหญ่ที่ 10MiB ทำให้ดูเหมือน "ถูก Suno ปฏิเสธ" จึงควรกันไว้ก่อนที่ฝั่งคุณ)
  2. ความยาวตัวอย่าง: อย่างน้อย 6 วินาที แนะนำ 10–60 วินาที สั้นเกินไปแพลตฟอร์มจะปฏิเสธ
  3. เนื้อหาตัวอย่าง: เสียงร้องสะอาด หลีกเลี่ยงสิ่งที่คล้ายบันทึกที่มีอยู่ (การเทียบกับคลังจะปฏิเสธ)
  4. ขีดจำกัดข้อความ: lyrics ≤ 3000 ตัวอักษร แนะนำให้ style_requirements / negative_tags / title อยู่ใน 1000 / 1000 / 100 ตัวอักษรตามลำดับ (ความต้องการสไตล์และคัฟเวอร์จะถูกต่อเข้าไปในพรอมป์ต จึงควรรวมกันไม่เกิน 3000 ตัวอักษร)
  5. เนื้อเพลงไม่ถูกดัดแปลง: ส่งอะไรก็ร้องอย่างนั้น (ตรงตัวอักษร) ไม่ตัดทอนในเครื่อง
  6. แต่ละเพลงให้ 2 ผลงานเสมอ ไม่ควรคิดว่าจะได้เพลงเดียว
  7. ไฟล์เสียงต้นฉบับเก็บถาวร: ลบเสียงก็ไม่ล้างไฟล์ต้นฉบับ เพื่อให้คัฟเวอร์ต่อไปใช้ได้และตรวจสอบความสอดคล้องได้
  8. เสียงต้อง ready: เสียงที่ processing ใช้คัฟเวอร์ไม่ได้
  9. เวลาหมดของคำขอ: บัญชี "เย็น" ส่งครั้งแรกช้าสุดที่วัดได้ประมาณ 4 นาทีครึ่ง ควรตั้งเวลาหมดของไคลเอนต์ ≥ 6 นาที คัฟเวอร์ไม่ตัดข้อมูลซ้ำระดับคำขอ หลังหมดเวลาให้ตรวจก่อนว่ามีเพลงใหม่เกิดแล้วหรือยัง (§1.5) จึงตัดสินใจส่งซ้ำ
  10. ความเป็นเจ้าของเสียง: เสียงเป็นของผูสร้าง คัฟเวอร์รับเฉพาะเสียงที่พร้อมและไม่ถูกลบ ถ้าไม่มีอยู่ ถูกลบ หรือไม่ใช่ของบัญชีนี้ จะคืน 400: เสียงนี้ไม่มีอยู่หรือถูกลบแล้ว (voice_id=…)

11. คำถามที่พบบ่อย (FAQ)

ถาม 1. สร้างเสียงมีค่าใช้จ่ายไหม? การสร้างปกติและ "สร้างจากไฟล์เสียงที่มีอยู่" ฟรี มีค่าใช้จ่ายเฉพาะคัฟเวอร์ (1.2 หยวน / MAX 2.4 หยวน) และโคลนแบบเสริม (ค่าเริ่มต้น 10 หยวน)

ถาม 2. ใช้เพลงสำเร็จรูปที่มีดนตรีประกอบเป็นตัวอย่างเสียงได้ไหม? ไม่แนะนำ สิ่งที่มีดนตรีหรือคล้ายบันทึกในคลังมากจะถูกแพลตฟอร์มปฏิเสธ (This audio matches an existing recording in our catalog.) ควรใช้เสียงร้องล้วนแบบแห้ง

ถาม 3. ทำไมส่งคัฟเวอร์แล้ว audio_url ว่าง? การส่งหมายถึงถูกรับแล้วเท่านั้น status ยังเป็น processing ต้องโพล /api/music/query ถึง status=completed จึงจะมีที่อยู่เล่น/ดาวน์โหลดได้

ถาม 4. สถานการณ์ B (ไม่ส่ง song_clip_id) ต้องส่งเนื้อเพลงไหม? ไม่บังคับ ถ้าต้องการให้ร้องเนื้อหาที่กำหนดให้ส่ง lyrics ถ้าไม่ส่งโมเดลจัดการเอง แต่ควบคุมได้น้อยกว่า

ถาม 5. ไฟล์เสียงที่ลูกค้าอัปโหลดเองใช้เป็นเสียงได้เลยไหม? ได้ ผ่านรูปแบบ file_url ของ create หรืออัปโหลดเป็นเพลงก่อนแล้วเรียก create-from-clip

ถาม 6. ล้มเหลวแล้วคืนเงินไหม? คำขอที่ถูกปฏิเสธทันที (พารามิเตอร์ผิด / แพลตฟอร์มแจ้งข้อผิดพลาด) ไม่คิดเงิน ตามผลวัด ส่วนงานที่ถูกรับแล้วแต่สุดท้ายล้มเหลวจะคืนยอดที่หักล่วงหน้า เมื่อล้มเหลวขั้นสุดท้าย งานจะคืน status=failed และ error_message

ถาม 7. ลบเสียงแล้วเพลงที่เคยสร้างด้วยเสียงนั้นยังฟังได้ไหม? ได้ การลบมีผลเฉพาะว่าเสียงนั้นจะใช้คัฟเวอร์ใหม่ได้หรือไม่

ถาม 8. คัฟเวอร์ได้ยาวเท่าไรต่อครั้ง? duration ส่ง 1–480 วินาที ถ้าไม่ส่งแพลตฟอร์มจะกำหนดจากเพลงต้นฉบับ / วัสดุ ระวังผลงานสำเร็จรูปของแพลตฟอร์มสั้นสุดประมาณ 30 วินาที: ใส่ค่าน้อยกว่า 30 วินาที ผลวัดยังได้ 29.96 / 29.76 วินาที


ภาคผนวก A: ตัวอย่างการเรียกครบชุด (Node.js มีการโพลและดาวน์โหลด)

const BASE = "https://www.suno-api.io";
const KEY = process.env.SUNO_API_KEY;
const H = { Authorization: `Bearer ${KEY}` };

// ① สร้างเสียง (multipart)
async function createVoice(filePath, title) {
  const fd = new FormData();
  fd.set("file", new Blob([await (await import("node:fs/promises")).readFile(filePath)], { type: "audio/mpeg" }), "my-voice.mp3");
  fd.set("file_name", "my-voice.mp3");
  fd.set("source_file_name", "my-voice.mp3");
  fd.set("title", title);
  fd.set("client_request_id", `vp-create-${Date.now()}`);
  const res = await fetch(`${BASE}/api/music/voice-profile/create`, { method: "POST", headers: H, body: fd });
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
  return body.data; // { voice_id, status, audio_url, ... }
}

// ② คัฟเวอร์
async function cover(voiceId, songClipId, lyrics) {
  const submissionId = `vp-cover-${Date.now()}`;
  const res = await fetch(`${BASE}/api/music/voice-profile/cover`, {
    method: "POST",
    headers: { ...H, "Content-Type": "application/json", "X-Create-Ui-Client-Request-Id": submissionId },
    body: JSON.stringify({
      model: "suno-v6",
      voice_id: voiceId,
      song_clip_id: songClipId || "",
      lyrics: lyrics || "",
      style_requirements: "โฟล์กช้า ๆ กีตาร์อะคูสติก",
      audio_weight: 0.85,
      max_mode: false,
      client_request_id: submissionId,
    }),
  });
  const body = await res.json();
  if (body.error) throw new Error(body.error.message);
  return body.data; // { resolved_scene, clips: [{ song_id, status }] }
}

// ③ โพลจนเสร็จ (ทุก 5 วินาที สูงสุด 15 นาที)
async function waitUntilCompleted(songIds) {
  const deadline = Date.now() + 15 * 60 * 1000;
  while (Date.now() < deadline) {
    const res = await fetch(`${BASE}/api/music/query`, {
      method: "POST",
      headers: { ...H, "Content-Type": "application/json" },
      body: JSON.stringify({ model: "suno-v6", song_ids: songIds.join(",") }),
    });
    const songs = await res.json(); // อาร์เรย์เปล่า
    if (songs.every((s) => s.status === "completed" || s.status === "failed")) return songs;
    await new Promise((r) => setTimeout(r, 5000));
  }
  throw new Error("timeout waiting for cover");
}

// ④ ดาวน์โหลด
async function download(songId, outPath) {
  const res = await fetch(`${BASE}/api/music/download?song_id=${encodeURIComponent(songId)}&kind=mp3`, { headers: H });
  if (!res.ok) throw new Error(`download failed: ${res.status}`);
  (await import("node:fs/promises")).writeFile(outPath, Buffer.from(await res.arrayBuffer()));
}

const voice = await createVoice("./my-voice.mp3", "เสียงของฉัน");
const result = await cover(voice.voice_id, "5b773e9a-a035-4134-a4a4-29c9961d3ccb", "[Verse 1]\nเนื้อเพลง…");
const ids = result.clips.map((c) => c.song_id);
const songs = await waitUntilCompleted(ids);
for (const [i, s] of songs.entries()) {
  if (s.status === "completed") await download(s.song_id, `./out-${i}.mp3`);
}

ภาคผนวก B: บันทึกการเปลี่ยนแปลง

วันที่ การเปลี่ยนแปลง
2026-10-15 ระบุความหมายของการลบให้ชัดเจน (§5.3) คัฟเวอร์ด้วย voice_id ที่ "ถูกลบ / ไม่มีสิทธิ์" จะคืน 400 ก่อนหักเงินล่วงหน้า พร้อมปรับตารางข้อผิดพลาดและ FAQ ให้สอดคล้อง (ควบคู่กับประตูลบเสียงที่เปิดใช้ในวันเดียวกัน)
2026-10-13 เพิ่มคำอธิบาย "ทำไมจึงแนะนำเส้นทางนี้" ที่ต้นเรื่อง: จากผลประเมินจริงของผู้ใช้จำนวนมาก เพลงที่สร้างด้วยเส้นทางนี้รักษาเสียงต้นฉบับได้ดีกว่า
2026-09-26 ฉบับแรก: สร้างเสียง (สามรูปแบบอินพุต) / สร้างจากไฟล์เสียงที่มีอยู่ / รายการ รายละเอียด ลบ / คัฟเวอร์ด้วยเสียง (สถานการณ์ A, B) / สอบถามความคืบหน้า / ดาวน์โหลด / อ่านราคา พร้อมหลักฐานจากการวัดผล
ถัดไปAPI เสริมสไตล์

รับคีย์ API

สร้างคีย์ API ในคอนโซลหลังสมัครสมาชิก การสร้างหนึ่งครั้งราคา 0.6 หยวน ได้ 2 เพลง ดาวน์โหลดไม่จำกัด และไม่ต้องใช้เบอร์โทรศัพท์

รับคีย์ API กลับไปภาพรวม