ListenHubDocs
API 레퍼런스

가사 생성

Mureka 또는 Suno로 짧은 프롬프트에서 노래 가사를 생성하고, 완성된 후보를 작업에서 읽어옵니다.

Lyrics API는 짧은 프롬프트를 완성된 노래 가사로 바꿉니다. Music API와 같은 두 프로바이더 — Mureka와 Suno — 를 사용하며, 요청마다 provider 필드로 선택합니다. 모든 엔드포인트는 https://api.marswave.ai/openapi/v1/lyrics 아래에 있으며 Authorization: Bearer $LISTENHUB_API_KEY로 인증합니다.

생성은 언제나 작업으로 실행됩니다. POST /v1/lyrics/generate는 taskId와 상태를 반환할 뿐 가사 자체를 반환하지 않습니다. 완성된 가사는 GET /v1/lyrics/tasks/{taskId}에서 읽습니다.

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

프로바이더

provider는 mureka, suno, default(Mureka로 해석됨) 중 하나입니다. 무엇을 고르든 요청 형태는 달라지지 않고, 작업이 종료 상태에 도달하는 속도와 돌아오는 가사 후보 수만 달라집니다.

프로바이더실행 방식생성 응답의 status후보 수
mureka동기 방식. 생성 요청이 업스트림 결과를 기다립니다.success — 이미 종료 상태1개
suno콜백 방식. 업스트림이 완료되면 결과를 보내옵니다.pending보통 2개
default서비스 기본 프로바이더, 즉 Mureka로 해석됩니다.mureka와 동일1개

provider를 생략하는 것은 default를 보내는 것과 같습니다. 작업에는 실제로 실행한 프로바이더가 기록되므로, default로 만든 작업은 mureka로 읽힙니다.

작업 라이프사이클

status는 pending → generating → success 또는 failed로 전이합니다. 두 프로바이더는 이 상태 기계를 공유하며, 종료 상태에 이르기까지 머무는 시간만 다릅니다.

  1. POST /v1/lyrics/generate가 202와 함께 taskId, 초기 status를 반환합니다.
  2. Mureka에서는 초기 상태가 이미 success이므로 작업을 한 번 조회하면 가사를 읽을 수 있습니다. Suno에서는 pending이므로 GET /v1/lyrics/tasks/{taskId}를 몇 초 간격으로 폴링합니다.
  3. success이면 variants를, failed이면 errorMessage를 읽습니다.

Suno에는 가사 조회 엔드포인트가 없어 콜백이 success에 이르는 유일한 경로입니다. Suno 작업은 30분 동안 갱신이 없으면 failed로 처리되고 크레딧이 전액 환불되며, 이후에는 복구되지 않습니다.

가사 생성

POST /v1/lyrics/generate

프롬프트로 가사 작업을 시작합니다. JSON으로 전송합니다.

curl -X POST "https://api.marswave.ai/openapi/v1/lyrics/generate" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A hopeful anthem about leaving a small town at dawn",
    "provider": "suno"
  }'
const response = await fetch(
  'https://api.marswave.ai/openapi/v1/lyrics/generate',
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.LISTENHUB_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      prompt: 'A hopeful anthem about leaving a small town at dawn',
      provider: 'suno',
    }),
  }
);
const { data } = await response.json();
console.log('Task:', data.taskId, data.status);
import os
import requests

response = requests.post(
    'https://api.marswave.ai/openapi/v1/lyrics/generate',
    headers={'Authorization': f'Bearer {os.environ["LISTENHUB_API_KEY"]}'},
    json={
        'prompt': 'A hopeful anthem about leaving a small town at dawn',
        'provider': 'suno',
    },
)
data = response.json()['data']
print('Task:', data['taskId'], data['status'])

요청 파라미터:

필드타입필수설명
promptstring예가사의 소재. 최대 200자 — 초과하면 검증 단계에서 거부되며 크레딧은 예약되지 않습니다
providerstring아니오mureka, suno, default 중 하나. 기본값은 default이며 Mureka로 해석됩니다

응답 예시:

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

생성 응답에는 두 프로바이더 모두 taskId와 status만 담기며 가사는 들어 있지 않습니다. 작업이 이미 success인 Mureka에서도 마찬가지입니다. 가사는 작업을 조회해 variants에서 읽으세요.

이 엔드포인트는 레이트 리밋에 설명된 생성 요청 제한에 포함됩니다.

작업 목록 조회

GET /v1/lyrics/tasks

가사 작업을 최신순으로 나열합니다.

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

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

쿼리 파라미터:

필드타입필수설명
pageinteger아니오페이지 번호, 최소 1. 기본값 1
pageSizeinteger아니오페이지당 항목 수, 1–100. 기본값 20
statusstring아니오pending, generating, success, failed로 필터링

data가 담는 것은 배열이 아니라 한 페이지입니다. items에 작업이 들어가며(구조는 작업 조회 참고), page, pageSize, total이 함께 반환됩니다.

작업 조회

GET /v1/lyrics/tasks/{taskId}

단일 작업을 조회합니다. Suno에 제출한 뒤 폴링하는 엔드포인트이며, 두 프로바이더 모두 가사는 여기서 읽습니다.

curl -X GET "https://api.marswave.ai/openapi/v1/lyrics/tasks/{taskId}" \
  -H "Authorization: Bearer $LISTENHUB_API_KEY"
const response = await fetch(
  `https://api.marswave.ai/openapi/v1/lyrics/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(data.variants[0].text);
import os
import requests

response = requests.get(
    f'https://api.marswave.ai/openapi/v1/lyrics/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(data['variants'][0]['text'])

응답 예시:

{
  "code": 0,
  "message": "",
  "data": {
    "id": "68e780390fc5c9a54f695a7e",
    "provider": "suno",
    "status": "success",
    "params": {
      "prompt": "A hopeful anthem about leaving a small town at dawn"
    },
    "variants": [
      {
        "title": "Dawn Highway",
        "text": "Suitcase on the porch light\nEngine turning over slow\n...",
        "status": "complete",
        "errorMessage": ""
      },
      {
        "title": "First Light Out",
        "text": "The bus stop hums awake\nI count the streetlamps one last time\n...",
        "status": "complete",
        "errorMessage": ""
      }
    ],
    "creditCost": 2,
    "errorMessage": "",
    "createdAt": 1730000000000,
    "updatedAt": 1730000021000
  }
}

작업 응답 필드:

필드타입설명
idstring작업 ID
providerstring실제로 작업을 실행한 프로바이더: mureka 또는 suno
statusstringpending, generating, success, failed
params.promptstring제출한 프롬프트 반환값
variantsarray생성된 가사. 작업이 성공하기 전까지는 비어 있음
variants[].titlestring제안된 곡 제목
variants[].textstring생성된 가사 본문
variants[].statusstringcomplete 또는 failed. 성공한 작업에도 실패한 후보가 섞여 있을 수 있습니다
variants[].errorMessagestring해당 후보가 실패한 이유, 그 외에는 빈 문자열
creditCostnumber차감된 크레딧. 작업이 성공하기 전까지는 0
errorMessagestring실패 사유(status가 failed일 때만)
createdAtnumber생성 시각(밀리초 타임스탬프)
updatedAtnumber마지막 갱신 시각(밀리초 타임스탬프)

작업은 소유자 기준으로 분리됩니다. 다른 계정의 작업을 조회하면 작업 대신 오류가 반환됩니다.

크레딧

가사 생성은 요청당 고정 2 크레딧입니다 — 프로바이더와 무관하게 동일하며, 후보가 몇 개 돌아오든 달라지지 않습니다.

크레딧은 작업 생성 시 예약되고 성공하면 확정됩니다. 업스트림이 요청을 거부한 경우, 작업이 실패한 경우, Suno 작업이 타임아웃된 경우에는 전액 환불됩니다. 따라서 success에 도달하지 못한 작업에는 비용이 발생하지 않으며 creditCost는 0으로 유지됩니다.

실시간 잔액은 GET /v1/user/subscription으로 확인하고, 전체 크레딧 기준은 요금을 참고하세요.

SDK 및 CLI

API 키 경로에서 Lyrics API는 현재 HTTP 직접 호출만 가능합니다. OpenAPIClient SDK와 listenhub openapi CLI 모두 아직 이 엔드포인트들을 감싸지 않습니다. listenhub lyrics 명령과 ListenHubClient의 가사 메서드는 같은 엔드포인트를 호출하지만, API 키가 아니라 계정 로그인으로 인증합니다.

이 페이지의 내용