ListenHubOpenAPI
API リファレンス

ボイスクローン

参照音声をアップロードして再利用できるプライベートボイスを作成し、確認したうえで、その speaker ID を音声合成・TTS エンドポイントで使います。

ボイスクローン API は、短い録音を再利用できるプライベートボイスに変えます。参照音声をアップロードし、クローンが完了するまでポーリングして結果を確認すると speakerId が得られ、他のボイスと同じように /v1/speech/v1/tts/v1/audio/speech で使えます。クローンしたボイスは API キーに紐づくアカウントに属し、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 ファイル、1 ファイル ≤5MB、合計 ≤20MB
言語zhenja
レート制限ユーザーごとに 1 分あたり 5 回の作成リクエスト
プラン有料プランのみ — 無料プランで確認すると NEED_UPGRADE が返ります
確認回数プランの期間ごとのクォータ内は無料、超過後は 1 回につき 300 クレジット
保存できるボイス数プランごとの上限(maxSpeakers)。ボイスを削除すると枠が 1 つ空きます
未確認のタスク7 日後に期限切れ — ボイスを残すには確認が必要です

クォータを超えた後は、useCredits=true を渡した場合にのみ確認でクレジットが消費されます。渡さない場合はリクエストが NEED_CREDIT を返し、課金は発生しません。

2 つのクローン方法

2 ステップ(デフォルト) — アップロードし、プレビューを試聴してから決めます:

  1. POST /v1/voice-clone/clonetaskId を返します。
  2. statuscompleted になるまで GET /v1/voice-clone/clone/{taskId} をポーリングします。レスポンスには一時ボイスのプレビューである demoAudioUrl が含まれます。
  3. 名前と性別を添えて POST /v1/voice-clone/confirm を呼ぶと、タスクが永続的なプライベートボイスになり、その speakerId が返ります。

ワンショット — 作成時に autoConfirm=true(および namegender)を指定します。クローンの完了を最初に検知したポーリングがそのままボイスの確認まで行い、同じレスポンスで speakerId を返します。2 回目のリクエストは不要です。

autoConfirm=true の場合、クレジットが消費されるのはポーリングリクエストです。ポーリングを繰り返しても並行して実行しても二重課金は起きません。確認はアトミックなロックで保護されており、2 回目の試行は確認済みとして拒否されます。

ポーリングレスポンスの読み方

GET /v1/voice-clone/clone/{taskId} には 3 つの終了形があります。次の順序で判定してください:

結果判定方法得られるもの
クローン失敗status: "failed"errorCodeerrorMessage
クローン完了・未確認status: "completed" かつ speakerId なしdemoAudioUrl。自動確認に失敗した場合は confirmError
確認済みspeakerId ありspeakerId。音声合成エンドポイントですぐ使えます

autoConfirm=true のときに見落としやすいのが真ん中の行です。クローンは成功したのにボイスの保存に失敗した状態で、原因はクレジット不足、クォータの使い切り、ボイス数の上限到達のいずれかです。どれなのかは confirmError が示します。クローン結果は残っているので、原因を解消してから POST /v1/voice-clone/confirm を明示的に呼んでください。

ステータス意味
pendingタスクを作成済み、処理待ち
processingクローン処理中
completedクローン完了 — プレビューは利用可能、ただし確認済みとは限らない
failedクローン失敗。理由は errorMessage が説明します

リトライ

ステータス発生する条件対処方法
429同じアカウントで別の確認が処理中、または作成が 1 分あたり 5 回を超えたRetry-After(デフォルト 2 秒)待ってからリトライ
503確認処理が依存するコンポーネントが一時的に利用できないRetry-After(デフォルト 5 秒)待ってからリトライ

どちらも安全にリトライできます。いずれもクレジットは消費しません。

クローンタスクを作成する

POST /v1/voice-clone/clone

JSON ではなく multipart/form-data で送信します。ファイルが複数ある場合は audioFiles フィールドをファイルの数だけ繰り返します。

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

# One-shot: clone and confirm in the same flow
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=My API Voice" \
  -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', 'en')
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('Task:', 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': 'en', 'consentConfirmed': 'true'},
    )

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

リクエストパラメータ

フィールド必須説明
audioFilesfileはい1–6 個の参照音声ファイル。複数ある場合はフィールドを繰り返します
languagestringはいzhenja のいずれか
consentConfirmedbooleanはいtrue 必須 — クローンされる本人の同意を得ていることの宣言です
modestringいいえupload(デフォルトであり、唯一受け付ける値)
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('Ready to speak with:', data.speakerId)
else if (data.confirmError) console.warn('Cloned but not saved:', data.confirmError)
else if (data.demoAudioUrl) console.log('Preview:', 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('Ready to speak with:', data['speakerId'])
elif data.get('confirmError'):
    print('Cloned but not saved:', data['confirmError'])
elif data.get('demoAudioUrl'):
    print('Preview:', 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": "My API Voice",
    "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: 'My API Voice', gender: 'female', useCredits: true }),
})
const { data } = await response.json()
console.log('Speaker:', data.speakerId)
フィールド必須説明
taskIdstringはい完了したクローンタスク
namestringはいボイス名。最大 50 文字
genderstringはいmalefemaleother のいずれか
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": "This sentence is spoken by my own cloned voice.",
        "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": "My API Voice",
        "speakerInnerId": "voice-clone-6915bde9cca4d3c8ecb3eaf5",
        "language": "en",
        "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音声合成・TTS エンドポイントに渡す ID
quotaサブスクリプション期間ごとに含まれる確認回数
remainingConfirmations現在の期間に残っている確認回数
maxSpeakersプランで同時に保持できるプライベートボイスの数
isLimitReached今期の確認回数を使い切ると true

ボイスの取得・名前変更・削除

メソッドパス説明
GET/v1/voice-clone/speakers/{speakerId}プライベートボイスを 1 件取得
PUT/v1/voice-clone/speakers/{speakerId}namegender を更新(少なくとも一方を送信)
DELETE/v1/voice-clone/speakers/{speakerId}ボイスを削除
# Rename
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": "Narrator (EN)" }'

# Delete — frees one slot against 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": "Narrator (EN)",
    "language": "en",
    "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プライベートボイスの保有数が上限に達しています。先に 1 つ削除してください
ALREADY_CONFIRMEDこのタスクは確認済みです。二重課金はありません
AUDIO_DURATION_INVALID参照音声が短すぎるか長すぎます
NO_VALID_SPEECH参照音声から発話が検出されませんでした
TASK_FAILEDクローンに失敗しました。詳細は errorMessage に入ります

エラーレスポンス全体の構造は エラー処理 を参照してください。

このページの内容