API อัปโหลดแล้วคัฟเวอร์ในครั้งเดียว
คำอธิบายเอนด์พอยต์
อัปโหลดแล้วคัฟเวอร์ในครั้งเดียวใช้ส่งไฟล์เสียงหรือ URL เสียง แล้วสร้างเวอร์ชันคัฟเวอร์ใหม่จากเสียงต้นทางนั้น
เอนด์พอยต์: POST /api/music/upload-cover
ค่าบริการ: มีค่าใช้จ่าย ปัจจุบันค่าเริ่มต้น 0.6 หยวนต่อครั้ง เอนด์พอยต์นี้คือ «อัปโหลดแล้วคัฟเวอร์» ไม่ใช่การอัปโหลดภาพปก ยอดหักจริงเป็นไปตามการตั้งราคาในระบบหลังบ้านปัจจุบัน
Max Mode / Variety: เอนด์พอยต์นี้รองรับพารามิเตอร์ทางเลือก max_mode และ variety (0-4) เมื่อเปิด
max_mode ครั้งนี้จะคิดค่าบริการเป็น 2 เท่า (0.6 → 1.2 หยวนต่อครั้ง) ส่วน variety ไม่มีค่าใช้จ่ายเพิ่ม
ความหมายและวิธีส่งดูได้ในหัวข้อ "พารามิเตอร์ขั้นสูง" ของ
ภาพรวม API ใหม่
ระยะเวลารอและ timeout (สำคัญ): เอนด์พอยต์นี้เป็นแบบซิงโครนัส — คำสั่งจะถูกรับและส่งเข้าสู่การสร้างเมื่อคำตอบกลับมาเท่านั้น จากการวัด ส่วนใหญ่ตอบกลับภายใน 1-3 วินาที ประมาณ 10% เกิน 30 วินาที และนานที่สุดประมาณ 230 วินาที กรุณาตั้ง timeout ฝั่งไคลเอนต์ไว้ที่ 300 วินาทีขึ้นไป การไม่ได้รับคำตอบไม่ได้หมายความว่าไม่ได้สร้าง และอย่าลองซ้ำทันทีหลัง timeout (จะซ้ำคำสั่งและถูกหักเงินซ้ำ) หากการเชื่อมต่อขาด ให้ตรวจสอบภายหลังด้วย
GET /api/music/songsดูหัวข้อ "ระยะเวลารอและการตั้งค่า timeout" ใน ภาพรวม API ใหม่
เมื่อไฟล์เสียงใหญ่ ควรแยก «อัปโหลด» กับ «คัฟเวอร์» เป็นสองขั้น (แนะนำ)
เอนด์พอยต์นี้ต้องใส่เสียงทั้งไฟล์ลงในเนื้อคำขอ: เสียงยิ่งใหญ่ เนื้อคำขอยิ่งใหญ่ และเพียงการสั่นของเครือข่ายหรือ timeout ครั้งเดียวก็ตัดการรับส่งกลางทางได้ จากนั้นเซิร์ฟเวอร์จะคืน
unexpected end of JSON input(HTTP 400 ไม่คิดค่าใช้จ่าย)เมื่อเสียงเกินประมาณ 8MB เครือข่ายไม่เสถียร หรือต้องใช้ซ้ำวัสดุต้นทางเดิม ให้เปลี่ยนไปใช้แบบสองขั้น:
POST /api/music/upload-sourceอัปโหลดเสียงต้นทางก่อน — ฟรี ลองใหม่ได้ทุกเมื่อ — แล้วได้clip_idมาPOST /api/music/generate-from-sourceใช้clip_idนั้นเริ่มคัฟเวอร์ — เนื้อคำขอของขั้นที่คิดเงินมีเพียงประมาณ 250 ไบต์ดู API อัปโหลดเสียงต้นทาง, API คัฟเวอร์จากคลิปต้นทาง และหัวข้อ «ไฟล์ใหญ่และคำขอที่ถูกตัด» ท้ายหน้านี้
พารามิเตอร์คำขอ
Headers
| พารามิเตอร์ | ชนิด | จำเป็น | หมายเหตุ |
|---|---|---|---|
| Authorization | string | ใช่ | Bearer YOUR_API_KEY |
| Content-Type | string | ใช่ | application/json |
พารามิเตอร์บอดี
| พารามิเตอร์ | ชนิด | จำเป็น | ค่าเริ่มต้น | หมายเหตุ |
|---|---|---|---|---|
| model | string | ไม่ | suno-v6 | ชื่อโมเดลสำหรับลูกค้า: suno-v6, suno-v6-wild หรือ suno-v6-mini |
| file_url | string | ไม่ | - | URL ของเสียงต้นทาง |
| file_base64 | string | ไม่ | - | เสียงแบบ Base64 |
| file_name | string | ไม่ | - | ชื่อไฟล์ |
| prompt | string | ไม่ | - | เนื้อเพลงใหม่หรือทิศทางการดัดแปลง |
| style | string | ไม่ | - | แท็กสไตล์ |
| title | string | ไม่ | - | ชื่อเพลง |
| negativeTags | string | ไม่ | - | สไตล์เชิงลบ |
| instrumental | boolean | ไม่ | false | เป็นเพลงบรรเลงหรือไม่ |
| waitAudio | boolean | ไม่ | false | รอให้เสียงเสร็จสิ้นหรือไม่ |
| cover_start_s | number | ไม่ | - | วินาทีเริ่มต้นของช่วงที่จะคัฟเวอร์ |
| cover_end_s | number | ไม่ | - | วินาทีสิ้นสุดของช่วงที่จะคัฟเวอร์ |
| audio_weight | number | ไม่ | - | ระดับการพึ่งพาเสียงอ้างอิง ช่วง 0.0-1.0 ส่งได้เฉพาะเมื่อระบุเสียงอ้างอิง |
cover_start_s และ cover_end_s มีหน่วยเป็นวินาที ใส่ทศนิยมได้ เวลาเริ่มต้นต้องน้อยกว่าเวลาสิ้นสุด และห้ามเกินความยาวของเสียงต้นทาง หากเว้นทั้งสองฟิลด์จะใช้เสียงทั้งไฟล์ audio_weight จะแมปไปยัง metadata.control_sliders.audio_weight ของ Suno และควบคุมว่าผลลัพธ์พึ่งพาเสียงอ้างอิงมากเพียงใด รับค่า 0.0-1.0 และใส่ได้เฉพาะเมื่อในคำขอมีเสียงอ้างอิงที่ใช้ได้ใน file_url หรือ file_base64 ค่า 0 ถือว่าใช้ได้ การเว้นฟิลด์หมายถึง «ไม่ระบุ» และใช้พฤติกรรมเริ่มต้นของ Suno ต่อ instrumental และ waitAudio ต้องส่งค่าบูลีน JSON ไม่ใช่สตริง
เอนด์พอยต์อัปโหลดคืนค่าแบบอะซิงโครนัสโดยค่าเริ่มต้น เมื่อ clips[].status ในคำตอบเป็น pending การที่ audio_url ว่างเป็นเรื่องปกติ และไม่ได้หมายความว่าการอัปโหลดหรือคัฟเวอร์ล้มเหลว กรุณาเก็บ song_id จริงที่ได้มา แล้วใช้เอนด์พอยต์ค้นหาเพลงไล่ถามจนกว่าจะเสร็จก่อนอ่านที่อยู่เสียง
ตัวอย่างคำขอ
curl -X POST https://www.suno-api.io/api/music/upload-cover \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno-v6",
"file_url": "https://example.com/source.mp3",
"file_name": "source.mp3",
"prompt": "เนื้อเพลงใหม่หรือทิศทางการดัดแปลง",
"style": "Mandopop, acoustic guitar",
"title": "เวอร์ชันคัฟเวอร์",
"negativeTags": "noise, low quality",
"audio_weight": 0.5,
"instrumental": false,
"waitAudio": false,
"cover_start_s": 0,
"cover_end_s": 60
}'
คำตอบ
{
"code": 200,
"message": "success",
"data": {
"upload": {
"clip_id": "uploaded_clip_id",
"status": "complete"
},
"clips": [
{
"song_id": "new_clip_id",
"song_title": "เวอร์ชันคัฟเวอร์",
"status": "pending"
}
]
}
}
ไฟล์ใหญ่และคำขอที่ถูกตัด
วิธีที่แนะนำ: แยกอัปโหลดและคัฟเวอร์เป็นสองขั้น
เอนด์พอยต์แบบครั้งเดียว (ตัวนี้) รวมอัปโหลดและสร้างไว้ในขั้นเดียว: เนื้อคำขอขนาดใหญ่อยู่ในขั้นเดียวเท่านั้น เมื่อขาดกลางทางจึงไม่รู้ว่าสร้างไปแล้วหรือยัง และตัดสินใจยากว่าถูกหักเงินหรือไม่
| ขั้นที่ 1 อัปโหลด | ขั้นที่ 2 คัฟเวอร์ | |
|---|---|---|
| เอนด์พอยต์ | POST /api/music/upload-source |
POST /api/music/generate-from-source |
| ค่าบริการ | ฟรี (อัปโหลดเท่านั้น ไม่สร้าง) | 0.6 หยวนต่อครั้ง; เปิด Max Mode เป็น 1.2 หยวนต่อครั้ง |
| เนื้อคำขอ | ตัวเสียง (base64 / multipart) หรือ file_url ส่งแค่ลิงก์ |
ประมาณ 250 ไบต์ (ส่งแค่ sourceClipId ตัวเดียว) |
| สิ่งที่คืน | clip_id (clip ID ของเสียงต้นทาง) |
data.clips[].song_id (ผลลัพธ์ที่สร้าง) |
| ถ้าล้มเหลว | ลองใหม่ได้เลย ไม่คิดค่าใช้จ่ายและไม่เกิดงานสร้าง | ตั้ง timeout ฝั่งไคลเอนต์ ≥300 วินาที; เมื่อ timeout ให้ตรวจด้วย /api/music/songs ก่อน อย่าลองซ้ำทันที |
| ใช้วัสดุซ้ำ | clip_id เดียวกันใช้ต่อกับ extend / replace / แยกแทร็กได้ |
ต้องอัปโหลดเสียงใหม่ทุกครั้ง |
สรุป: เสียงเกินประมาณ 8MB เครือข่ายไม่เสถียร หรือวัสดุเดียวกันใช้หลายครั้ง → ใช้แบบสองขั้น; เสียงเล็กมากและเครือข่ายเสถียร → เอนด์พอยต์นี้สะดวกกว่า
400 unexpected end of JSON input คืออะไร
ความหมายคือ JSON ที่เซิร์ฟเวอร์ได้รับไม่ครบถ้วน (ไม่ใช่ใส่พารามิเตอร์ผิด ไม่ใช่ปัญหาสิทธิ์หรือยอดคงเหลือ) สาเหตุที่พบบ่อย เรียงตามโอกาส:
- เนื้อคำขอขนาดใหญ่ถูกตัดกลางการรับส่ง: ชั้นเชื่อมต่อบันทึกทั้ง «ไคลเอนต์ประกาศว่าจะส่งกี่ไบต์» และ «รับมาถึงจริงกี่ไบต์» เคสที่วัดได้: ไคลเอนต์ประกาศ 14.17MB แต่มาถึงจริงเพียง 11.8–12.4MB และคำขอทั้งสามครั้งหยุดที่ประมาณ 1.6–1.7 วินาที จำนวนไบต์ที่ขาดแตกต่างกันทุกครั้ง แสดงว่าเป็นการรับส่งที่ขาดกลางทาง ไม่ใช่ขีดจำกัดตายตัว (เซิร์ฟเวอร์ไม่ได้จำกัดขนาดเนื้อคำขอ)
Content-Lengthไม่ตรงกับจำนวนไบต์ที่ส่งจริง: ใน Node.js การใช้.lengthของสตริง (จำนวนอักขระ UTF-16) เป็นความยาวจะคำนวณผิดเมื่อเนื้อหามีภาษาจีนหรือข้อความหลายไบต์- เขียนบอดีเป็นสตริงแทน Buffer ทำให้จำนวนไบต์ที่เขียนไม่ตรงกับที่ประกาศ
ทั้งสามกรณีเกิดก่อนขั้นคิดเงิน จึงไม่เกิดค่าใช้จ่าย
เช็กลิสต์ตรวจสอบฝั่งไคลเอนต์
-
Content-Lengthได้จากBuffer.byteLength(json, 'utf8')(หรือBuffer.from(json).length) — อย่าใช้json.length - เขียนเนื้อคำขอเป็น Buffer ไม่ใช่สตริง
- timeout ของ socket / คำขอ ≥ 300 วินาที
- เมื่อเสียงเกินประมาณ 8MB: เปลี่ยนไปใช้
file_url(เนื้อคำขอเพียงไม่กี่ร้อยไบต์) หรือใช้ multipart ของupload-sourceหรือไปใช้แบบสองขั้นเลย - คำขอ multipart อย่าตั้ง
Content-Typeเอง (ให้ไคลเอนต์ใส่ boundary ให้) - พิมพ์ «จำนวนไบต์ที่ส่งจริง» แล้วเทียบกับ
Content-Length - ในแบบสองขั้น ให้ยืนยันว่าขั้นที่ 1 คืน
clip_idและstatusเป็นสถานะเสร็จแล้วก่อนส่งขั้นที่ 2
ข้อผิดพลาดที่พบบ่อย
| ข้อผิดพลาด | ความหมาย | วิธีจัดการ |
|---|---|---|
unexpected end of JSON input |
เนื้อคำขอไม่ครบถ้วน (ถูกตัด) | ทำเช็กลิสต์ข้างบน หรือเปลี่ยนไปใช้แบบสองขั้น |
invalid character '-' in numeric literal |
ส่งบอดี multipart ไปยังเอนด์พอยต์ JSON | อย่าใช้ multipart กับเอนด์พอยต์ JSON และอย่าตั้ง Content-Type เอง |
one of file_path, file_base64, file_url, or multipart file is required |
ไม่ได้แนบเสียง | เพิ่ม file_base64 / file_url / file แบบ multipart |
model is required |
เนื้อคำขอเป็น JSON ที่ถูกต้องแต่ว่างเปล่า (เช่น {}) |
ส่ง model มาอย่างน้อยหนึ่งค่า |
Invalid request: Invalid request, ... |
ข้อความห่อของกรณีแยกวิเคราะห์เนื้อคำขอไม่สำเร็จ | อ่านครึ่งหลังเพื่อดูสาเหตุเฉพาะ (มักเป็นข้อใดข้อหนึ่งข้างบน) |
เอนด์พอยต์ที่เกี่ยวข้อง: API อัปโหลดเสียงต้นทาง (ขั้นที่ 1), API คัฟเวอร์จากคลิปต้นทาง (ขั้นที่ 2)
รับคีย์ API
สร้างคีย์ API ในคอนโซลหลังสมัครสมาชิก การสร้างหนึ่งครั้งราคา 0.6 หยวน ได้ 2 เพลง ดาวน์โหลดไม่จำกัด และไม่ต้องใช้เบอร์โทรศัพท์
รับคีย์ API กลับไปภาพรวม