ListenHubOpenAPI
API 레퍼런스

ListenHub Voice

텍스트, 참조 보이스, 이미지를 음성과 효과음으로 엔드투엔드 비동기 생성하고, 작업을 폴링해 완성된 오디오를 가져옵니다.

ListenHub Voice API는 오디오를 엔드투엔드로 생성합니다 — 일반 내레이션, 효과음, 단일 보이스 음성, 다중 화자 대화, 참조 클립을 이용한 보이스 클로닝, 이미지-투-오디오까지 지원합니다. 생성은 비동기입니다. 요청을 제출한 뒤 완료될 때까지 작업을 폴링(polling)합니다. 모든 엔드포인트는 https://api.marswave.ai/openapi/v1/listenhub-voice 아래에 있으며 Authorization: Bearer $LISTENHUB_API_KEY 로 인증합니다.

ListenHub Voice는 현재 기간 한정 무료입니다. 무료 기간이 끝나면 추후 공지에 따라 과금이 재개됩니다.

모든 응답은 { "code": 0, "message": "", "data": { ... } } 로 감싸집니다. code 가 0이 아니면 오류입니다 — 오류 처리를 참고하세요. 아래 예시는 모두 data 에서 필드를 읽습니다.

모델과 제한

항목
modellistenhub-voice-1.0 (기본값이자 유일하게 지원되는 값)
레이트 리밋사용자당 분당 5회, /generate 에 적용
text최대 1400자
voices1–3개 항목 (일반 텍스트 / 효과음일 때는 생략)
durationHint1–110초 (크레딧 예상치 + 목표 길이 힌트)

보이스(voices)

voices 는 누가 말할지를 결정합니다. 각 항목은 다음 두 종류 중 하나입니다.

type필수 필드설명
speakerid내장 보이스 — ListenHub 보이스 코드 또는 플랫폼 voice_type. 이 타입에는 url 을 보내지 마세요.
referenceurl보이스를 클로닝할 커스텀 참조 오디오 URL(http/https). 최대 30초, ≤10MB, wav/mp3/pcm/ogg_opus. 이 타입에는 id 를 보내지 마세요.

다중 화자 대화의 경우 2–3개의 보이스를 나열하고, text 의 각 줄 앞에 @音频1, @音频2, … 를 붙여 순서대로 보이스에 대사를 배정합니다. voices 를 완전히 생략하면 일반 내레이션이나 순수 효과음이 생성됩니다.

voicesimage 는 함께 쓸 수 없습니다 — 최대 하나만 보내세요. 둘 다 포함한 요청은 거부됩니다. speaker 항목은 id 만, reference 항목은 url 만 담아야 합니다. 섞어서 보내면 33004(잘못된 파라미터)가 반환됩니다.

비동기 작업 라이프사이클

  1. POST /v1/listenhub-voice/generate 로 생성 요청을 제출합니다. 응답에는 taskId 와 초기 statuspending 이 담깁니다.
  2. GET /v1/listenhub-voice/tasks/{taskId} 를 폴링합니다. statuspendinggeneratinguploadingsuccess 순으로 진행됩니다.
  3. success 가 되면 audioUrl 을 읽고, failed 가 되면 errorMessage 를 읽습니다.
상태의미
pending생성됨. 생성 요청 제출을 대기 중입니다.
generating생성 진행 중. audioUrl 은 아직 사용할 수 없습니다.
uploading생성 완료. 오디오를 스토리지로 전송하는 중입니다.
success완료. audioUrl 을 사용할 수 있습니다.
failed어느 단계에서 실패. errorMessage 가 이유를 설명하며, 예약된 크레딧은 환불됩니다.

ListenHub Voice 작업 생성

POST /v1/listenhub-voice/generate

텍스트(선택적으로 보이스 또는 참조 이미지 포함)를 제출해 엔드투엔드 오디오 생성을 시작합니다. JSON을 전송합니다. taskId 와 함께 202 를 반환합니다.

# Plain text / sound effects (no voices)
curl -X POST "https://api.marswave.ai/openapi/v1/listenhub-voice/generate" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "A gentle rain falls on a quiet street at midnight.",
    "durationHint": 20
  }'

# Single voice (speaker)
curl -X POST "https://api.marswave.ai/openapi/v1/listenhub-voice/generate" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "Welcome to ListenHub. Here is your daily briefing.",
    "voices": [{ "type": "speaker", "id": "zh_female_warm" }]
  }'

# Voice cloning from a reference clip
curl -X POST "https://api.marswave.ai/openapi/v1/listenhub-voice/generate" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text": "@音频1 Hi there! @音频2 Hello, how can I help?",
    "voices": [
      { "type": "reference", "url": "https://example.com/host.mp3" },
      { "type": "speaker", "id": "zh_male_calm" }
    ]
  }'
const response = await fetch(
  'https://api.marswave.ai/openapi/v1/listenhub-voice/generate',
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      text: 'Welcome to ListenHub. Here is your daily briefing.',
      voices: [{ type: 'speaker', id: 'zh_female_warm' }],
      durationHint: 20,
    }),
  },
)
const { data } = await response.json()
console.log('Task ID:', data.taskId)
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/listenhub-voice/generate',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'text': 'Welcome to ListenHub. Here is your daily briefing.',
        'voices': [{'type': 'speaker', 'id': 'zh_female_warm'}],
        'durationHint': 20,
    },
)
data = response.json()['data']
print('Task ID:', data['taskId'])

이미지-투-오디오의 경우 voices 대신 image 객체를 보냅니다(둘은 함께 쓸 수 없습니다).

{
  "text": "Describe this scene as a short narrated clip.",
  "image": { "url": "https://example.com/scene.jpg" }
}

요청 파라미터:

필드타입필수설명
modelstring아니요listenhub-voice-1.0. 기본값은 listenhub-voice-1.0
textstring읽어줄 스크립트. 최대 1400자. @音频N 접두사로 대화 대사를 보이스에 배정합니다
voicesarray아니요1–3개의 보이스 항목(보이스 참고). 일반 텍스트 / 효과음일 때는 생략합니다. image 와 함께 쓸 수 없습니다
imageobject아니요이미지-투-오디오용 참조 이미지. url(http/https) 또는 data(Base64, data:image/...;base64, 접두사 포함 가능) 중 정확히 하나만 지정합니다. 이미지 1장, ≤10MB, jpeg/png/webp. voices 와 함께 쓸 수 없습니다
audioConfigobject아니요출력 튜닝(아래 참고)
durationHintnumber아니요목표 길이, 1110 초. 크레딧 예상치를 결정하고 모델에 힌트를 줍니다
watermarkboolean아니요오디오 워터마크 추가

audioConfig 필드:

필드타입필수설명
speechRatenumber아니요말하기 속도, -50100
loudnessRatenumber아니요음량, -50100
pitchRatenumber아니요음높이, -1212
formatstring아니요mp3(기본값), wav, pcm, ogg_opus

202 를 반환합니다.

{
  "code": 0,
  "message": "",
  "data": {
    "taskId": "68e780390fc5c9a54f695a7e",
    "status": "pending"
  }
}

단일 작업 조회

GET /v1/listenhub-voice/tasks/{taskId}

단일 작업을 가져옵니다. 생성 요청을 제출한 뒤 폴링하는 엔드포인트입니다.

curl -X GET "https://api.marswave.ai/openapi/v1/listenhub-voice/tasks/{taskId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch(
  `https://api.marswave.ai/openapi/v1/listenhub-voice/tasks/${taskId}`,
  { headers: { Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}` } },
)
const { data } = await response.json()
console.log('Status:', data.status)
if (data.status === 'success') console.log('Audio:', data.audioUrl)
import os
import requests

response = requests.get(
    f'https://api.marswave.ai/openapi/v1/listenhub-voice/tasks/{task_id}',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
)
data = response.json()['data']
print('Status:', data['status'])
if data['status'] == 'success':
    print('Audio:', data['audioUrl'])

성공한 작업:

{
  "code": 0,
  "message": "",
  "data": {
    "id": "68e780390fc5c9a54f695a7e",
    "status": "success",
    "model": "listenhub-voice-1.0",
    "params": {
      "text": "Welcome to ListenHub. Here is your daily briefing.",
      "voices": [{ "type": "speaker", "id": "zh_female_warm" }]
    },
    "audioUrl": "https://assets.listenhub.ai/listenhub-voice/68e780390fc5c9a54f695a7e.mp3",
    "audioDuration": 18.4,
    "creditCharged": 12,
    "creditRefunded": 0,
    "createdAt": 1730000000000,
    "updatedAt": 1730000040000
  }
}

작업 응답 필드:

필드타입설명
idstring작업 ID
statusstringpending, generating, uploading, success, failed 중 하나
modelstringlistenhub-voice-1.0
paramsobject제출한 요청의 에코(민감한 이미지/오디오 페이로드는 제거됨. 인라인 이미지는 { "hasData": true } 로 표시되며 thumbnailUrl 이 붙을 수 있음)
audioUrlstring완성된 오디오 URL. statussuccess 일 때만 반환
audioDurationnumber오디오 길이(초 단위, 과금 기준 길이)
creditChargednumber실제로 청구된 크레딧(아직 청구되지 않았으면 0)
creditRefundednumber실패 시 환불된 크레딧(정산 대조용)
errorMessagestring실패 사유. statusfailed 일 때만 반환
createdAtnumber생성 시각(밀리초 타임스탬프)
updatedAtnumber최종 수정 시각(밀리초 타임스탬프)

작업 목록 조회

GET /v1/listenhub-voice/tasks

내 ListenHub Voice 작업을 최신순으로 나열합니다.

curl -X GET "https://api.marswave.ai/openapi/v1/listenhub-voice/tasks?page=1&pageSize=20&status=success" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch(
  'https://api.marswave.ai/openapi/v1/listenhub-voice/tasks?page=1&pageSize=20',
  { headers: { Authorization: `Bearer ${process.env.LISTENHUB_API_KEY}` } },
)
const { data } = await response.json()
console.log(`${data.total} tasks, showing ${data.items.length}`)
import os
import requests

response = requests.get(
    'https://api.marswave.ai/openapi/v1/listenhub-voice/tasks',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    params={'page': 1, 'pageSize': 20},
)
data = response.json()['data']
print(data['total'], 'tasks, showing', len(data['items']))

쿼리 파라미터:

필드타입필수설명
pageinteger아니요페이지 번호, 최소 1. 기본값은 1
pageSizeinteger아니요페이지당 항목 수, 1100. 기본값은 20
statusstring아니요pending, generating, uploading, success, failed 로 필터링
keywordstring아니요작업의 text 에 대한 부분 일치 검색. 최대 64자

응답:

{
  "code": 0,
  "message": "",
  "data": {
    "items": [
      {
        "id": "68e780390fc5c9a54f695a7e",
        "status": "success",
        "model": "listenhub-voice-1.0",
        "audioUrl": "https://assets.listenhub.ai/listenhub-voice/68e780390fc5c9a54f695a7e.mp3",
        "audioDuration": 18.4,
        "creditCharged": 12,
        "creditRefunded": 0,
        "createdAt": 1730000000000,
        "updatedAt": 1730000040000
      }
    ],
    "page": 1,
    "pageSize": 20,
    "total": 1
  }
}

각 item은 단일 작업 조회와 동일한 필드를 가집니다.

오류

비즈니스 오류는 HTTP 400 과 함께 최상위 code 필드에 구체적인 코드를 담아 반환됩니다.

코드의미
33001작업을 찾을 수 없음(또는 현재 API 사용자 소유가 아님)
33002speaker 보이스 항목에 해당하는 화자를 찾을 수 없음
33003생성 서비스를 사용할 수 없음
33004잘못된 파라미터(예: voicesimage 를 함께 전송, 보이스 항목에 idurl 혼용)
33005보이스가 너무 많음(최대 3개)
33006크레딧 부족
33007레이트 리밋 초과
33008생성 타임아웃
33009사용자별 동시 실행 한도 도달
HTTP 상태의미
400잘못된 파라미터 또는 비즈니스 오류 — 위의 33xxx 코드를 참고
429레이트 리밋 초과(/generate 에서 사용자당 5 RPM)

크레딧

크레딧은 제출 시점에 예약되고, success 시 확정되며, 실패 시 자동으로 환불됩니다. 각 작업은 정산 대조를 위해 creditCharged(실제 청구액)와 creditRefunded(실패 시 환불액)를 보고합니다. 과금 기준 길이는 audioDuration 입니다. 실시간 잔액은 GET /v1/user/subscription으로 확인하고, 크레딧과 기능의 대응 관계는 요금을 참고하세요.

이 페이지의 내용