ListenHubOpenAPI
API 参考

语音克隆

上传参考音频创建可复用的私有音色,确认后用它的 speaker ID 调用语音合成接口。

语音克隆 API 把一段录音变成可反复使用的私有音色。上传参考音频、轮询到克隆完成、确认,就得到一个 speakerId,可以像官方音色一样用在 /v1/speech/v1/tts/v1/audio/speech 上。克隆出的音色属于 API Key 对应的账号,也会出现在 GET /v1/speakers/list 的结果里。

所有端点位于 https://api.marswave.ai/openapi/v1/voice-clone,使用 Authorization: Bearer $LISTENHUB_API_KEY 鉴权。

克隆他人声音必须获得本人授权。每次创建请求都要带 consentConfirmed=true——这是你对「已获得被克隆者授权」的声明,不带就会被拒绝,声明本身会随任务存证。获取并遵守该授权是调用方的责任。

所有响应都包在 { "code": 0, "message": "", "data": { ... } } 里。code 非 0 表示错误,见 错误处理。下面的示例都从 data 取字段。

限制与费用

项目取值
参考音频1–6 个文件,单个 ≤5MB,总计 ≤20MB
语言zhenja
限流每用户每分钟 5 次创建
订阅仅付费套餐可用,免费账号确认时返回 NEED_UPGRADE
确认次数套餐周期配额内免费,超出后每次 300 积分
音色数量按套餐设上限(maxSpeakers),删除音色可释放名额
未确认任务7 天后过期——想留下音色就要确认

超出配额后,只有传了 useCredits=true 才会真的扣积分;不传则返回 NEED_CREDIT,不扣费。

两种克隆方式

两步(默认)——先上传、试听,再决定:

  1. POST /v1/voice-clone/clone 返回 taskId
  2. 轮询 GET /v1/voice-clone/clone/{taskId} 直到 statuscompleted,响应里带 demoAudioUrl,即临时音色的试听。
  3. POST /v1/voice-clone/confirm 带上名称和性别,把任务确认成永久私有音色,返回 speakerId

一键——创建时传 autoConfirm=true(连带 namegender)。之后第一次发现克隆完成的那次轮询会顺带完成确认,并在同一个响应里返回 speakerId,不需要第二次请求。

开启 autoConfirm=true 时,扣积分发生在轮询请求上。重复轮询或并发轮询不会重复扣费——确认由原子锁保护,第二次尝试会被判为已确认。

读懂轮询响应

GET /v1/voice-clone/clone/{taskId} 有三种终态,按下面顺序判断:

终态判据拿到什么
克隆失败status: "failed"errorCodeerrorMessage
克隆完成但未确认status: "completed" 且没有 speakerIddemoAudioUrl;自动确认失败时另带 confirmError
确认成功speakerIdspeakerId,可直接用于语音合成

中间那一格在 autoConfirm=true 时最容易漏:克隆成功了,但音色没保存下来——积分不足、配额用完或音色数达上限,具体原因看 confirmError。克隆结果还在,排除原因后显式调 POST /v1/voice-clone/confirm 即可。

状态含义
pending任务已创建,等待处理
processing克隆进行中
completed克隆完成——可以试听,但不代表已确认
failed克隆失败,errorMessage 说明原因

重试语义

状态码什么时候出现怎么处理
429同一账号已有一次确认在进行中,或创建超过每分钟 5 次Retry-After(默认 2 秒)后重试
503确认所依赖的组件暂时不可用Retry-After(默认 5 秒)后重试

两者都可以安全重试,都不会扣积分。

创建克隆任务

POST /v1/voice-clone/clone

请求体是 multipart/form-data,不是 JSON。多个文件就重复传 audioFiles 字段。

# 两步
curl -X POST "https://api.marswave.ai/openapi/v1/voice-clone/clone" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -F "audioFiles=@reference.mp3" \
  -F "language=zh" \
  -F "consentConfirmed=true"

# 一键:克隆完成后直接确认
curl -X POST "https://api.marswave.ai/openapi/v1/voice-clone/clone" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -F "audioFiles=@part-1.mp3" \
  -F "audioFiles=@part-2.mp3" \
  -F "language=ja" \
  -F "consentConfirmed=true" \
  -F "autoConfirm=true" \
  -F "name=我的 API 音色" \
  -F "gender=female" \
  -F "useCredits=true"
import { readFile } from 'node:fs/promises'

const form = new FormData()
form.append('audioFiles', new Blob([await readFile('reference.mp3')]), 'reference.mp3')
form.append('language', 'zh')
form.append('consentConfirmed', 'true')

const response = await fetch('https://api.marswave.ai/openapi/v1/voice-clone/clone', {
  method: 'POST',
  headers: { Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}` },
  body: form,
})
const { data } = await response.json()
console.log('任务:', data.taskId)
import os
import requests

with open('reference.mp3', 'rb') as audio:
    response = requests.post(
        'https://api.marswave.ai/openapi/v1/voice-clone/clone',
        headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
        files=[('audioFiles', ('reference.mp3', audio, 'audio/mpeg'))],
        data={'language': 'zh', 'consentConfirmed': 'true'},
    )

data = response.json()['data']
print('任务:', data['taskId'])

请求参数

字段类型必填说明
audioFilesfile1–6 个参考音频文件,多个文件重复传该字段
languagestringzhenja
consentConfirmedboolean必须为 true,即声明已获得被克隆者授权
modestringupload(默认,也是唯一接受的值)
autoConfirmboolean让发现克隆完成的那次轮询直接确认,默认 false
namestringautoConfirm 时必填音色名称,最长 50 字符
genderstringautoConfirm 时必填malefemaleother
useCreditsboolean授权超配额后的 300 积分扣费,默认 false

返回:

{
  "code": 0,
  "message": "",
  "data": {
    "taskId": "6915bde9cca4d3c8ecb3eaf5",
    "status": "pending"
  }
}

轮询克隆任务

GET /v1/voice-clone/clone/{taskId}

curl -X GET "https://api.marswave.ai/openapi/v1/voice-clone/clone/{taskId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch(
  `https://api.marswave.ai/openapi/v1/voice-clone/clone/${taskId}`,
  { headers: { Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}` } },
)
const { data } = await response.json()

if (data.status === 'failed') throw new Error(data.errorMessage)
if (data.speakerId) console.log('可以用它合成了:', data.speakerId)
else if (data.confirmError) console.warn('克隆成功但没保存:', data.confirmError)
else if (data.demoAudioUrl) console.log('试听:', data.demoAudioUrl)
import os
import requests

response = requests.get(
    f'https://api.marswave.ai/openapi/v1/voice-clone/clone/{task_id}',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
)
data = response.json()['data']

if data['status'] == 'failed':
    raise RuntimeError(data['errorMessage'])
if data.get('speakerId'):
    print('可以用它合成了:', data['speakerId'])
elif data.get('confirmError'):
    print('克隆成功但没保存:', data['confirmError'])
elif data.get('demoAudioUrl'):
    print('试听:', data['demoAudioUrl'])

克隆完成、等待确认:

{
  "code": 0,
  "message": "",
  "data": {
    "status": "completed",
    "demoAudioUrl": "https://assets.listenhub.ai/voice-clone/demo-6915bde9.mp3"
  }
}

已确认:

{
  "code": 0,
  "message": "",
  "data": {
    "status": "completed",
    "demoAudioUrl": "https://assets.listenhub.ai/voice-clone/demo-6915bde9.mp3",
    "speakerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5"
  }
}

确认克隆任务

POST /v1/voice-clone/confirm

把已完成的任务确认成永久私有音色。同一个任务重复调用返回 ALREADY_CONFIRMED,不会二次扣费。

curl -X POST "https://api.marswave.ai/openapi/v1/voice-clone/confirm" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "taskId": "6915bde9cca4d3c8ecb3eaf5",
    "name": "我的 API 音色",
    "gender": "female",
    "useCredits": true
  }'
const response = await fetch('https://api.marswave.ai/openapi/v1/voice-clone/confirm', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ taskId, name: '我的 API 音色', gender: 'female', useCredits: true }),
})
const { data } = await response.json()
console.log('音色:', data.speakerId)
字段类型必填说明
taskIdstring已完成的克隆任务
namestring音色名称,最长 50 字符
genderstringmalefemaleother
useCreditsboolean授权超配额后的 300 积分扣费,默认 false

返回:

{
  "code": 0,
  "message": "",
  "data": { "speakerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5" }
}

用克隆音色合成语音

speakerId 填到需要音色的位置即可:

curl -X POST "https://api.marswave.ai/openapi/v1/speech" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scripts": [
      {
        "content": "这句话由我自己的克隆音色朗读。",
        "speakerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5"
      }
    ]
  }'

列出私有音色

GET /v1/voice-clone/speakers

curl -X GET "https://api.marswave.ai/openapi/v1/voice-clone/speakers" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
{
  "code": 0,
  "message": "",
  "data": {
    "speakers": [
      {
        "id": "6915c0a2cca4d3c8ecb3eb01",
        "name": "我的 API 音色",
        "speakerInnerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5",
        "language": "zh",
        "gender": "female",
        "demoAudioUrl": "https://assets.listenhub.ai/voice-clone/demo-6915bde9.mp3",
        "createdAt": "2026-07-30T09:10:11.000Z"
      }
    ],
    "quota": 2,
    "isLimitReached": false,
    "maxSpeakers": 2,
    "remainingConfirmations": 1
  }
}
字段说明
speakers[].speakerInnerId传给语音合成接口的音色 ID
quota每个订阅周期包含的确认次数
remainingConfirmations当前周期剩余确认次数
maxSpeakers套餐允许同时保留的私有音色数量
isLimitReached当前周期确认次数已用完时为 true

查看、改名与删除音色

方法路径说明
GET/v1/voice-clone/speakers/{speakerId}查看单个私有音色
PUT/v1/voice-clone/speakers/{speakerId}name 和/或 gender(至少传一个)
DELETE/v1/voice-clone/speakers/{speakerId}删除音色
# 改名
curl -X PUT "https://api.marswave.ai/openapi/v1/voice-clone/speakers/{speakerId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "旁白(中文)" }'

# 删除——释放一个 maxSpeakers 名额
curl -X DELETE "https://api.marswave.ai/openapi/v1/voice-clone/speakers/{speakerId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"

GETPUT 返回音色本身:

{
  "code": 0,
  "message": "",
  "data": {
    "id": "6915c0a2cca4d3c8ecb3eb01",
    "speakerInnerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5",
    "name": "旁白(中文)",
    "language": "zh",
    "gender": "female",
    "demoAudioUrl": "https://assets.listenhub.ai/voice-clone/demo-6915bde9.mp3",
    "createdAt": "2026-07-30T09:10:11.000Z",
    "updatedAt": "2026-07-30T10:02:44.000Z"
  }
}

DELETE 返回 { "speakerId": "..." }。删除只释放音色名额,本周期已消耗的确认次数不会退回。

错误

错误含义
NEED_UPGRADE语音克隆需要付费套餐
NEED_CREDIT配额已用完且没传 useCredits,未扣费
SPEAKER_LIMIT_REACHED私有音色数已达上限,先删一个再确认
ALREADY_CONFIRMED该任务已确认,不会二次扣费
AUDIO_DURATION_INVALID参考音频时长不符合要求
NO_VALID_SPEECH参考音频里没检测到有效人声
TASK_FAILED克隆失败,errorMessage 带具体原因

完整错误结构见 错误处理

On this page