欢迎使用 Suno API
Suno API 让您能够使用最先进的AI模型创建高质量的AI生成音乐、歌词和音频内容。无论您是在构建音乐应用、自动化创意工作流程,还是开发音频内容,我们的API都为音乐生成和音频处理提供了全面的工具。生成音乐
创建带或不带歌词的原创音乐曲目
延长音乐
无缝延长现有音乐曲目
生成歌词
从文本提示创建创意歌词
音乐视频
将音频轨道转换为可视化音乐视频
上传翻唱
将上传的音频转换为新风格
上传扩展
上传音频文件并无缝扩展
人声分离
从音乐中分离人声和伴奏
WAV转换
将音频转换为高质量WAV格式
获取歌词
获取带时间戳的同步歌词
添加伴奏
为现有音频轨道添加伴奏元素
添加人声
为器乐音乐生成人声轨道
增强音乐风格
使用V4_5对话式提示词增强风格描述
身份验证
所有 API 请求都需要使用 Bearer 令牌进行身份验证。请从 API 密钥管理页面 获取您的 API 密钥。请妥善保管您的 API 密钥,切勿公开分享。如果怀疑密钥泄露,请立即重置。
API 基础 URL
https://apibox.erweima.ai
身份验证请求头
Authorization: Bearer YOUR_API_KEY
快速开始指南
第一步:生成您的第一个音乐曲目
从一个简单的音乐生成请求开始:curl -X POST "https://apibox.erweima.ai/api/v1/generate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "一首平静舒缓的钢琴曲,带有柔和的旋律",
"customMode": false,
"instrumental": true,
"model": "V4_5ALL",
"callBackUrl": "https://your-app.com/callback",
"vocalGender": "m",
"styleWeight": 0.65,
"weirdnessConstraint": 0.3,
"audioWeight": 0.7
}'
const response = await fetch('https://apibox.erweima.ai/api/v1/generate', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: '一首平静舒缓的钢琴曲,带有柔和的旋律',
customMode: false,
instrumental: true,
model: 'V4_5ALL',
callBackUrl: 'https://your-app.com/callback',
vocalGender: 'm',
styleWeight: 0.65,
weirdnessConstraint: 0.3,
audioWeight: 0.7
})
});
const data = await response.json();
console.log('任务ID:', data.data.taskId);
import requests
url = "https://apibox.erweima.ai/api/v1/generate"
headers = {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {
"prompt": "一首平静舒缓的钢琴曲,带有柔和的旋律",
"customMode": False,
"instrumental": True,
"model": "V4_5ALL",
"callBackUrl": "https://your-app.com/callback",
"vocalGender": "m",
"styleWeight": 0.65,
"weirdnessConstraint": 0.3,
"audioWeight": 0.7
}
response = requests.post(url, json=payload, headers=headers)
result = response.json()
print(f"任务ID: {result['data']['taskId']}")
<?php
$url = 'https://apibox.erweima.ai/api/v1/generate';
$headers = [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json'
];
$payload = [
'prompt' => '一首平静舒缓的钢琴曲,带有柔和的旋律',
'customMode' => false,
'instrumental' => true,
'model' => 'V4_5ALL',
'callBackUrl' => 'https://your-app.com/callback',
'vocalGender' => 'm',
'styleWeight' => 0.65,
'weirdnessConstraint' => 0.3,
'audioWeight' => 0.7
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo "任务ID: " . $result['data']['taskId'];
?>
第二步:检查任务状态
使用返回的任务ID检查生成状态:curl -X GET "https://apibox.erweima.ai/api/v1/generate/record-info?taskId=YOUR_TASK_ID" \
-H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch(`https://apibox.erweima.ai/api/v1/generate/record-info?taskId=${taskId}`, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
});
const result = await response.json();
if (result.data.status === 'SUCCESS') {
console.log('生成完成!');
console.log('音频轨道:', result.data.response.data);
} else if (result.data.status === 'PENDING') {
console.log('正在生成中...');
} else {
console.log('生成失败:', result.data.status);
}
import requests
import time
def check_task_status(task_id, api_key):
url = f"https://apibox.erweima.ai/api/v1/generate/record-info?taskId={task_id}"
headers = {"Authorization": f"Bearer {api_key}"}
response = requests.get(url, headers=headers)
result = response.json()
status = result['data']['status']
if status == 'SUCCESS':
print("生成完成!")
tracks = result['data']['response']['data']
for i, track in enumerate(tracks):
print(f"音轨 {i+1}: {track['audio_url']}")
return tracks
elif status == 'PENDING':
print("正在生成中...")
return None
else:
print(f"生成失败: {status}")
return None
# 轮询直到完成
task_id = "YOUR_TASK_ID"
while True:
tracks = check_task_status(task_id, "YOUR_API_KEY")
if tracks:
break
time.sleep(30) # 等待30秒后再次检查
响应格式
成功响应:{
"code": 200,
"msg": "success",
"data": {
"taskId": "5c79****be8e"
}
}
{
"code": 200,
"msg": "success",
"data": {
"taskId": "5c79****be8e",
"status": "SUCCESS",
"response": {
"data": [
{
"id": "8551****662c",
"audio_url": "https://example.cn/****.mp3",
"stream_audio_url": "https://example.cn/****",
"image_url": "https://example.cn/****.jpeg",
"prompt": "一首平静舒缓的钢琴曲",
"title": "宁静钢琴",
"tags": "平静, 舒缓, 钢琴",
"duration": 198.44,
"createTime": "2025-01-01 00:00:00"
}
]
}
}
}
核心功能
- 文本转音乐:输入文字描述,生成相应的音乐作品
- 延长音乐:基于现有音频,无缝创建更长版本
- 生成歌词:从创意提示生成结构化歌词内容
- 上传翻唱:上传音频文件,转换为不同的音乐风格
- 上传扩展:上传音频文件并在保持风格的同时无缝扩展
- 人声分离:将音乐分离为人声、伴奏等独立轨道,支持高级干声分离
- 格式转换:支持WAV等多种高质量音频格式输出
- 音乐视频:将音频转换为视觉化的音乐视频
- 添加人声:为现有的器乐音乐生成人声轨道
- 添加伴奏:为人声轨道创建器乐伴奏
- 风格增强:使用V4_5+对话式提示词提升和优化现有音乐的风格特色
- 带时间戳歌词:获取同步歌词用于卡拉OK式应用
AI 模型
为您的需求选择合适的模型:V4_5ALL
扩展功能支持更长的歌词(5000字符)和风格描述(1000字符)
V4
改进的人声最长4分钟,增强的人声质量
V4_5
更好的歌曲结构最长1分钟,改进的歌曲组织
V4_5PLUS
更丰富的音色最长8分钟,新的创作方式
V5
最新模型增强的质量和功能
V5_5
个性化声线释放你的声音:定制模型,贴合你的独特品味 — 适用接口下与 V5 参数与限制一致
生成模式
boolean
必填
控制参数复杂度:
false: 简单模式,仅需要提示词true: 高级模式,需要风格和标题
boolean
必填
决定音乐是否包含人声:
true: 仅纯音乐(无歌词)false: 包含人声/歌词
关键参数
string
必填
对所需音乐的文本描述。请具体说明流派、情绪和乐器。字符限制:
- 非自定义模式:500字符
- 自定义模式(V4):3000字符
- 自定义模式(V4_5, V4_5PLUS, V5, V5_5 & V4_5ALL):5000字符
string
音乐风格规范(仅自定义模式)。示例: 爵士、古典、电子、流行、摇滚、嘻哈字符限制:
- V4:200字符
- V4_5, V4_5PLUS, V5, V5_5 & V4_5ALL:1000字符
string
生成音乐曲目的标题(仅自定义模式)。最大长度: 80字符
完整工作流程示例
以下是一个生成带歌词音乐并等待完成的完整示例:- JavaScript
- Python
class SunoAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://apibox.erweima.ai/api/v1';
}
async generateMusic(prompt, options = {}) {
const response = await fetch(`${this.baseUrl}/generate`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt,
customMode: options.customMode || false,
instrumental: options.instrumental || false,
model: options.model || 'V4_5ALL',
style: options.style,
title: options.title,
negativeTags: options.negativeTags,
callBackUrl: options.callBackUrl || 'https://your-app.com/callback',
vocalGender: options.vocalGender,
styleWeight: options.styleWeight,
weirdnessConstraint: options.weirdnessConstraint,
audioWeight: options.audioWeight
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(`生成失败: ${result.msg}`);
}
return result.data.taskId;
}
async extendMusic(audioId, options = {}) {
const response = await fetch(`${this.baseUrl}/generate/extend`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
audioId,
defaultParamFlag: options.defaultParamFlag || false,
model: options.model || 'V4_5ALL',
prompt: options.prompt,
style: options.style,
title: options.title,
continueAt: options.continueAt,
callBackUrl: options.callBackUrl || 'https://your-app.com/callback',
vocalGender: options.vocalGender,
styleWeight: options.styleWeight,
weirdnessConstraint: options.weirdnessConstraint,
audioWeight: options.audioWeight
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(`延长失败: ${result.msg}`);
}
return result.data.taskId;
}
async generateLyrics(prompt, callBackUrl) {
const response = await fetch(`${this.baseUrl}/lyrics`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt,
callBackUrl
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(`歌词生成失败: ${result.msg}`);
}
return result.data.taskId;
}
async addVocals(uploadUrl, prompt, style, title, negativeTags, options = {}) {
const response = await fetch(`${this.baseUrl}/generate/add-vocals`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
uploadUrl,
prompt,
style,
title,
negativeTags,
model: options.model || 'V4_5PLUS',
callBackUrl: options.callBackUrl || 'https://your-app.com/callback',
vocalGender: options.vocalGender,
styleWeight: options.styleWeight,
weirdnessConstraint: options.weirdnessConstraint,
audioWeight: options.audioWeight
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(`添加人声失败: ${result.msg}`);
}
return result.data.taskId;
}
async addInstrumental(uploadUrl, title, tags, negativeTags, options = {}) {
const response = await fetch(`${this.baseUrl}/generate/add-instrumental`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
uploadUrl,
title,
tags,
negativeTags,
model: options.model || 'V4_5PLUS',
callBackUrl: options.callBackUrl || 'https://your-app.com/callback',
vocalGender: options.vocalGender,
styleWeight: options.styleWeight,
weirdnessConstraint: options.weirdnessConstraint,
audioWeight: options.audioWeight
})
});
const result = await response.json();
if (result.code !== 200) {
throw new Error(`添加伴奏失败: ${result.msg}`);
}
return result.data.taskId;
}
async waitForCompletion(taskId, maxWaitTime = 600000) { // 最长等待10分钟
const startTime = Date.now();
while (Date.now() - startTime < maxWaitTime) {
const status = await this.getTaskStatus(taskId);
if (status.status === 'SUCCESS') {
return status.response;
} else if (status.status.includes('FAILED') || status.status === 'SENSITIVE_WORD_ERROR') {
throw new Error(`生成失败: ${status.errorMessage || status.status}`);
}
// 等待10秒后再次检查
await new Promise(resolve => setTimeout(resolve, 10000));
}
throw new Error('生成超时');
}
async getTaskStatus(taskId) {
const response = await fetch(`${this.baseUrl}/generate/record-info?taskId=${taskId}`, {
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
});
const result = await response.json();
return result.data;
}
async getRemainingCredits() {
const response = await fetch(`${this.baseUrl}/generate/credit`, {
headers: {
'Authorization': `Bearer ${this.apiKey}`
}
});
const result = await response.json();
return result.data.credits;
}
}
// 使用示例
async function main() {
const api = new SunoAPI('YOUR_API_KEY');
try {
// 检查剩余积分
const credits = await api.getRemainingCredits();
console.log(`剩余积分: ${credits}`);
// 生成带歌词的音乐
console.log('开始生成音乐...');
const taskId = await api.generateMusic(
'一首关于童年回忆的怀旧民谣',
{
customMode: true,
instrumental: false,
model: 'V4_5',
style: '民谣, 原声吉他, 怀旧',
title: '童年梦想'
}
);
// 等待完成
console.log(`任务ID: ${taskId}。等待完成...`);
const result = await api.waitForCompletion(taskId);
console.log('音乐生成成功!');
console.log('生成的曲目:');
result.data.forEach((track, index) => {
console.log(`曲目 ${index + 1}:`);
console.log(` 标题: ${track.title}`);
console.log(` 音频URL: ${track.audio_url}`);
console.log(` 时长: ${track.duration}秒`);
console.log(` 标签: ${track.tags}`);
});
// 延长第一个曲目
const firstTrack = result.data[0];
console.log('\n延长第一个曲目...');
const extendTaskId = await api.extendMusic(firstTrack.id, {
defaultParamFlag: true,
prompt: '继续一个充满希望的副歌',
style: '民谣, 振奋',
title: '童年梦想延长版',
continueAt: 60,
model: 'V4_5'
});
const extendResult = await api.waitForCompletion(extendTaskId);
console.log('音乐延长成功!');
console.log('延长曲目URL:', extendResult.data[0].audio_url);
} catch (error) {
console.error('错误:', error.message);
}
}
main();
import requests
import time
class SunoAPI:
def __init__(self, api_key):
self.api_key = api_key
self.base_url = 'https://apibox.erweima.ai/api/v1'
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
def generate_music(self, prompt, **options):
data = {
'prompt': prompt,
'customMode': options.get('customMode', False),
'instrumental': options.get('instrumental', False),
'model': options.get('model', 'V4_5ALL'),
'callBackUrl': options.get('callBackUrl', 'https://your-app.com/callback')
}
if options.get('style'):
data['style'] = options['style']
if options.get('title'):
data['title'] = options['title']
if options.get('negativeTags'):
data['negativeTags'] = options['negativeTags']
if options.get('vocalGender'):
data['vocalGender'] = options['vocalGender']
if options.get('styleWeight'):
data['styleWeight'] = options['styleWeight']
if options.get('weirdnessConstraint'):
data['weirdnessConstraint'] = options['weirdnessConstraint']
if options.get('audioWeight'):
data['audioWeight'] = options['audioWeight']
response = requests.post(f'{self.base_url}/generate',
headers=self.headers, json=data)
result = response.json()
if result['code'] != 200:
raise Exception(f"生成失败: {result['msg']}")
return result['data']['taskId']
def extend_music(self, audio_id, **options):
data = {
'audioId': audio_id,
'defaultParamFlag': options.get('defaultParamFlag', False),
'model': options.get('model', 'V4_5ALL'),
'callBackUrl': options.get('callBackUrl', 'https://your-app.com/callback')
}
if options.get('prompt'):
data['prompt'] = options['prompt']
if options.get('style'):
data['style'] = options['style']
if options.get('title'):
data['title'] = options['title']
if options.get('continueAt'):
data['continueAt'] = options['continueAt']
if options.get('vocalGender'):
data['vocalGender'] = options['vocalGender']
if options.get('styleWeight'):
data['styleWeight'] = options['styleWeight']
if options.get('weirdnessConstraint'):
data['weirdnessConstraint'] = options['weirdnessConstraint']
if options.get('audioWeight'):
data['audioWeight'] = options['audioWeight']
response = requests.post(f'{self.base_url}/generate/extend',
headers=self.headers, json=data)
result = response.json()
if result['code'] != 200:
raise Exception(f"延长失败: {result['msg']}")
return result['data']['taskId']
def generate_lyrics(self, prompt, callback_url):
data = {
'prompt': prompt,
'callBackUrl': callback_url
}
response = requests.post(f'{self.base_url}/lyrics',
headers=self.headers, json=data)
result = response.json()
if result['code'] != 200:
raise Exception(f"歌词生成失败: {result['msg']}")
return result['data']['taskId']
def add_vocals(self, upload_url, prompt, style, title, negative_tags, **options):
data = {
'uploadUrl': upload_url,
'prompt': prompt,
'style': style,
'title': title,
'negativeTags': negative_tags,
'model': options.get('model', 'V4_5PLUS'),
'callBackUrl': options.get('callBackUrl', 'https://your-app.com/callback')
}
if options.get('vocalGender'):
data['vocalGender'] = options['vocalGender']
if options.get('styleWeight'):
data['styleWeight'] = options['styleWeight']
if options.get('weirdnessConstraint'):
data['weirdnessConstraint'] = options['weirdnessConstraint']
if options.get('audioWeight'):
data['audioWeight'] = options['audioWeight']
response = requests.post(f'{self.base_url}/generate/add-vocals',
headers=self.headers, json=data)
result = response.json()
if result['code'] != 200:
raise Exception(f"添加人声失败: {result['msg']}")
return result['data']['taskId']
def add_instrumental(self, upload_url, title, tags, negative_tags, **options):
data = {
'uploadUrl': upload_url,
'title': title,
'tags': tags,
'negativeTags': negative_tags,
'model': options.get('model', 'V4_5PLUS'),
'callBackUrl': options.get('callBackUrl', 'https://your-app.com/callback')
}
if options.get('vocalGender'):
data['vocalGender'] = options['vocalGender']
if options.get('styleWeight'):
data['styleWeight'] = options['styleWeight']
if options.get('weirdnessConstraint'):
data['weirdnessConstraint'] = options['weirdnessConstraint']
if options.get('audioWeight'):
data['audioWeight'] = options['audioWeight']
response = requests.post(f'{self.base_url}/generate/add-instrumental',
headers=self.headers, json=data)
result = response.json()
if result['code'] != 200:
raise Exception(f"添加伴奏失败: {result['msg']}")
return result['data']['taskId']
def wait_for_completion(self, task_id, max_wait_time=600):
start_time = time.time()
while time.time() - start_time < max_wait_time:
status = self.get_task_status(task_id)
if status['status'] == 'SUCCESS':
return status['response']
elif 'FAILED' in status['status'] or status['status'] == 'SENSITIVE_WORD_ERROR':
error_msg = status.get('errorMessage', status['status'])
raise Exception(f"生成失败: {error_msg}")
time.sleep(10) # 等待10秒
raise Exception('生成超时')
def get_task_status(self, task_id):
response = requests.get(f'{self.base_url}/generate/record-info?taskId={task_id}',
headers={'Authorization': f'Bearer {self.api_key}'})
return response.json()['data']
def get_remaining_credits(self):
response = requests.get(f'{self.base_url}/generate/credit',
headers={'Authorization': f'Bearer {self.api_key}'})
return response.json()['data']['credits']
# 使用示例
def main():
api = SunoAPI('YOUR_API_KEY')
try:
# 检查剩余积分
credits = api.get_remaining_credits()
print(f'剩余积分: {credits}')
# 生成带歌词的音乐
print('开始生成音乐...')
task_id = api.generate_music(
'一首关于童年回忆的怀旧民谣',
customMode=True,
instrumental=False,
model='V4_5',
style='民谣, 原声吉他, 怀旧',
title='童年梦想'
)
# 等待完成
print(f'任务ID: {task_id}。等待完成...')
result = api.wait_for_completion(task_id)
print('音乐生成成功!')
print('生成的曲目:')
for i, track in enumerate(result['data']):
print(f"曲目 {i + 1}:")
print(f" 标题: {track['title']}")
print(f" 音频URL: {track['audio_url']}")
print(f" 时长: {track['duration']}秒")
print(f" 标签: {track['tags']}")
# 延长第一个曲目
first_track = result['data'][0]
print('\n延长第一个曲目...')
extend_task_id = api.extend_music(
first_track['id'],
defaultParamFlag=True,
prompt='继续一个充满希望的副歌',
style='民谣, 振奋',
title='童年梦想延长版',
continueAt=60,
model='V4_5'
)
extend_result = api.wait_for_completion(extend_task_id)
print('音乐延长成功!')
print(f"延长曲目URL: {extend_result['data'][0]['audio_url']}")
except Exception as error:
print(f'错误: {error}')
if __name__ == '__main__':
main()
状态码和任务状态
处理中
任务正在等待处理或正在生成中
部分完成
歌词/文本生成成功完成
部分完成
第一个曲目生成完成
完成
所有曲目生成成功
错误
创建任务失败
错误
生成音频失败
错误
内容因敏感词被过滤
HTTP 状态码
成功
请求成功
参数错误
请求参数错误或缺失
未授权
没有访问权限,检查API密钥
未找到
请求方式或路径错误
调用限制
调用超过限制
内容过长
提示词或主题过长
积分不足
账户积分不足
维护中
网站维护中
服务器错误
服务器内部错误
最佳实践
提示词工程
提示词工程
- 具体说明流派、情绪和乐器
- 使用描述性形容词获得更好的风格控制
- 包含节拍和能量水平描述
- 参考音乐时代或特定艺术家进行风格指导
模型选择
模型选择
- V4_5ALL:最适合需要更长歌词和风格描述的项目
- V4:当人声质量最重要时选择
- V4_5:用于更好的歌曲结构,最长1分钟
- V4_5PLUS:选择最高质量和最长的曲目
性能优化
性能优化
- 使用回调而不是频繁轮询
- 从非自定义模式开始满足简单需求
- 实施适当的错误处理以应对生成失败
- 缓存生成内容,因为文件14-15天后到期
内容指南
内容指南
- 避免在提示中使用受版权保护的材料
- 使用原创歌词和音乐描述
- 注意歌词内容的内容政策
- 测试提示变化以避免敏感词过滤器
错误处理
内容政策违反(代码 400)
内容政策违反(代码 400)
try {
const taskId = await api.generateMusic('受版权保护的歌词');
} catch (error) {
if (error.data.code === 400) {
console.log('请仅使用原创内容');
}
}
积分不足(代码 429)
积分不足(代码 429)
try {
const taskId = await api.generateMusic('原创作品');
} catch (error) {
if (error.data.code === 429) {
console.log('请为您的账户添加更多积分');
}
}
速率限制(代码 405)
速率限制(代码 405)
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function generateWithRetry(prompt, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await api.generateMusic(prompt, options);
} catch (error) {
if (error.data.code === 405 && i < maxRetries - 1) {
await delay(Math.pow(2, i) * 1000); // 指数退避
continue;
}
throw error;
}
}
}
支持
需要帮助吗?我们的技术支持团队随时为您提供帮助。
- 邮箱: support@api.box
- 文档: 查看详细的API文档和示例
- API状态: 查看我们的状态页面了解实时API健康状况
准备开始创作令人惊叹的AI音乐了吗?获取您的API密钥,立即开始创作!
