API tải lên và cover trong một bước
Mô tả endpoint
Tải lên và cover trong một bước gửi một tệp âm thanh hoặc URL âm thanh và tạo ra phiên bản cover mới từ âm thanh nguồn đó.
Endpoint: POST /api/music/upload-cover
Tính phí: Có phí, hiện mặc định 0,6 ¥ mỗi lần gọi. Endpoint này là "tải lên rồi cover", không phải tải lên ảnh bìa. Số tiền thực trừ tuân theo cấu hình giá hiện tại trong phần quản trị.
Max Mode / Variety: endpoint này hỗ trợ hai tham số tùy chọn max_mode và variety (0-4). Khi bật
max_mode, lần gọi này bị tính gấp đôi (0,6 → 1,2 ¥ mỗi lần); variety không phát sinh phí thêm.
Ý nghĩa và cách gửi xem mục "Tham số nâng cao" trong
Tổng quan API mới.
Thời gian chờ và timeout (quan trọng): đây là endpoint đồng bộ — đơn chỉ được tiếp nhận và đưa vào tạo nhạc khi phản hồi trả về. Theo đo đạc, phần lớn yêu cầu trả về trong 1-3 giây, khoảng 10% mất hơn 30 giây và lâu nhất khoảng 230 giây. Hãy đặt timeout phía client từ 300 giây trở lên; không nhận được phản hồi không có nghĩa là chưa tạo gì, và đừng thử lại ngay sau khi timeout (sẽ trùng đơn và bị tính phí hai lần). Nếu kết nối bị ngắt, hãy kiểm tra lại sau bằng
GET /api/music/songs. Xem "Thời gian chờ và thiết lập timeout" trong Tổng quan API mới.
Khi âm thanh lớn, nên tách "tải lên" và "cover" thành hai bước (khuyến nghị)
Endpoint này yêu cầu đưa toàn bộ âm thanh vào phần thân yêu cầu: âm thanh càng lớn thì phần thân càng lớn, và chỉ một lần mạng chập chờn hay timeout là cắt ngang đường truyền, sau đó máy chủ trả về
unexpected end of JSON input(HTTP 400, không tính phí).Khi âm thanh vượt khoảng 8 MB, mạng không ổn định hoặc cùng một tư liệu nguồn sẽ được dùng lại, hãy chuyển sang dạng hai bước:
POST /api/music/upload-sourcetải âm thanh nguồn lên trước — miễn phí, có thể thử lại bất cứ lúc nào — và trả vềclip_id;POST /api/music/generate-from-sourcedùngclip_idđó để bắt đầu cover — phần thân của bước tính phí chỉ khoảng 250 byte.Xem API tải lên âm thanh nguồn, API cover từ clip nguồn và "Tệp lớn và yêu cầu bị cắt" ở cuối trang này.
Tham số yêu cầu
Headers
| Tham số | Kiểu | Bắt buộc | Ghi chú |
|---|---|---|---|
| Authorization | string | có | Bearer YOUR_API_KEY |
| Content-Type | string | có | application/json |
Tham số body
| Tham số | Kiểu | Bắt buộc | Mặc định | Ghi chú |
|---|---|---|---|---|
| model | string | không | suno-v6 | Tên model phía khách hàng: suno-v6, suno-v6-wild hoặc suno-v6-mini |
| file_url | string | không | - | URL âm thanh nguồn |
| file_base64 | string | không | - | Âm thanh dạng Base64 |
| file_name | string | không | - | Tên tệp |
| prompt | string | không | - | Lời mới hoặc hướng chuyển thể |
| style | string | không | - | Thẻ phong cách |
| title | string | không | - | Tiêu đề |
| negativeTags | string | không | - | Phong cách phủ định |
| instrumental | boolean | không | false | Bài có phải nhạc không lời hay không |
| waitAudio | boolean | không | false | Có chờ âm thanh hoàn tất hay không |
| cover_start_s | number | không | - | Giây bắt đầu của đoạn được cover |
| cover_end_s | number | không | - | Giây kết thúc của đoạn được cover |
| audio_weight | number | không | - | Mức phụ thuộc vào âm thanh tham chiếu, khoảng 0.0-1.0; chỉ gửi được khi có âm thanh tham chiếu |
cover_start_s và cover_end_s tính bằng giây và có thể là số thập phân; thời điểm bắt đầu phải nhỏ hơn thời điểm kết thúc và không được vượt quá độ dài âm thanh nguồn. Nếu bỏ cả hai trường thì dùng toàn bộ âm thanh. audio_weight được ánh xạ tới metadata.control_sliders.audio_weight của Suno và điều khiển mức mà kết quả dựa vào âm thanh tham chiếu; nhận giá trị 0.0-1.0 và chỉ được gửi kèm khi yêu cầu có âm thanh tham chiếu hợp lệ trong file_url hoặc file_base64. 0 là giá trị hợp lệ; bỏ trường nghĩa là "không chỉ định" và giữ hành vi mặc định của Suno. instrumental và waitAudio phải là boolean JSON, không phải chuỗi.
Endpoint tải lên mặc định trả về bất đồng bộ. Khi clips[].status trong phản hồi là pending thì audio_url rỗng là bình thường và không có nghĩa là tải lên hay cover đã thất bại; hãy lưu song_id thật được trả về và gọi endpoint truy vấn bài hát cho đến khi hoàn tất rồi mới đọc địa chỉ âm thanh.
Ví dụ yêu cầu
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": "Lời mới hoặc hướng chuyển thể",
"style": "Mandopop, acoustic guitar",
"title": "Bản cover",
"negativeTags": "noise, low quality",
"audio_weight": 0.5,
"instrumental": false,
"waitAudio": false,
"cover_start_s": 0,
"cover_end_s": 60
}'
Phản hồi
{
"code": 200,
"message": "success",
"data": {
"upload": {
"clip_id": "uploaded_clip_id",
"status": "complete"
},
"clips": [
{
"song_id": "new_clip_id",
"song_title": "Bản cover",
"status": "pending"
}
]
}
}
Tệp lớn và yêu cầu bị cắt
Khuyến nghị: tách tải lên và cover thành hai bước
Endpoint làm một lần (endpoint này) gộp tải lên và tạo nhạc vào một bước: phần thân lớn nằm ở bước duy nhất đó, nên khi bị cắt bạn không biết có tạo được gì hay không và cũng khó biết có bị tính phí hay không.
| Bước 1 tải lên | Bước 2 cover | |
|---|---|---|
| Endpoint | POST /api/music/upload-source |
POST /api/music/generate-from-source |
| Tính phí | Miễn phí (chỉ tải lên, không tạo nhạc) | 0,6 ¥ mỗi lần gọi; 1,2 ¥ mỗi lần gọi khi bật Max Mode |
| Phần thân yêu cầu | Chính âm thanh (base64 / multipart), hoặc chỉ một liên kết qua file_url |
Khoảng 250 byte (chỉ một sourceClipId) |
| Trả về | clip_id (clip ID của âm thanh nguồn) |
data.clips[].song_id (kết quả tạo ra) |
| Nếu thất bại | Cứ thử lại, không tính phí và không tạo tác vụ tạo nhạc | Đặt timeout phía client ≥300 giây; khi timeout hãy kiểm tra bằng /api/music/songs trước, đừng thử lại ngay |
| Dùng lại tư liệu nguồn | Cùng clip_id còn dùng được cho gia hạn / thay thế / tách nhạc cụ |
Mỗi lần đều phải tải âm thanh lên lại |
Kết luận: âm thanh trên khoảng 8 MB, mạng không ổn định hoặc cùng một tư liệu dùng nhiều lần → dùng dạng hai bước; âm thanh rất nhỏ và mạng ổn định → endpoint này tiện hơn.
400 unexpected end of JSON input nghĩa là gì
Nghĩa là JSON mà máy chủ nhận được không đầy đủ (không phải sai tham số, cũng không phải vấn đề quyền hay số dư). Các nguyên nhân thường gặp, xếp theo mức độ khả dĩ:
- Phần thân lớn bị cắt giữa đường truyền: tầng vào ghi lại cả "client khai báo gửi bao nhiêu byte" và "thực tế nhận được bao nhiêu". Trường hợp đo được: client khai 14,17 MB nhưng chỉ nhận 11,8–12,4 MB, và cả ba yêu cầu đều dừng ở khoảng 1,6–1,7 giây; số byte thiếu mỗi lần một khác, cho thấy đứt đường truyền chứ không phải giới hạn cố định (máy chủ không giới hạn kích thước phần thân).
Content-Lengthkhông khớp với số byte thực gửi: trong Node.js, dùng.lengthcủa chuỗi (số ký tự UTF-16) làm độ dài sẽ tính sai khi nội dung có tiếng Trung hoặc văn bản nhiều byte khác.- Ghi phần thân bằng chuỗi thay vì Buffer, nên số byte ghi ra không khớp với khai báo.
Cả ba trường hợp đều xảy ra trước khi tính phí, nên không phát sinh chi phí.
Danh sách tự kiểm tra phía client
-
Content-Lengthlấy từBuffer.byteLength(json, 'utf8')(hoặcBuffer.from(json).length) — không dùngjson.length; - Phần thân yêu cầu ghi bằng Buffer, không ghi bằng chuỗi;
- Timeout socket / yêu cầu ≥ 300 giây;
- Khi âm thanh lớn hơn khoảng 8 MB: dùng
file_url(phần thân chỉ vài trăm byte), hoặc dùng tải lên multipart củaupload-source, hoặc chuyển thẳng sang dạng hai bước; - Với yêu cầu multipart, không tự đặt
Content-Type(để client tự thêm boundary); - In ra "số byte thực gửi" và so với
Content-Length; - Ở dạng hai bước, xác nhận bước 1 đã trả về
clip_idvớistatushoàn tất rồi mới gửi bước 2.
Lỗi thường gặp
| Lỗi | Ý nghĩa | Cần làm gì |
|---|---|---|
unexpected end of JSON input |
Phần thân yêu cầu không đầy đủ (bị cắt) | Làm theo danh sách tự kiểm tra ở trên, hoặc chuyển sang dạng hai bước |
invalid character '-' in numeric literal |
Đã gửi phần thân multipart tới endpoint JSON | Không dùng multipart ở endpoint JSON và không tự đặt Content-Type |
one of file_path, file_base64, file_url, or multipart file is required |
Chưa kèm âm thanh | Bổ sung file_base64 / file_url / file multipart |
model is required |
Phần thân là JSON hợp lệ nhưng rỗng (ví dụ {}) |
Gửi ít nhất model |
Invalid request: Invalid request, ... |
Thông báo bọc ngoài của lỗi phân tích phần thân | Đọc nửa sau để biết nguyên nhân cụ thể (thường là một trong các mục trên) |
Endpoint liên quan: API tải lên âm thanh nguồn (bước 1), API cover từ clip nguồn (bước 2).
Lấy khóa API
Tạo khóa API trong bảng điều khiển sau khi đăng ký. Mỗi lần tạo tốn 0,6 ¥ và trả về 2 bản nhạc, tải xuống không giới hạn và không cần số điện thoại.
Lấy khóa API Quay lại tổng quan