문서

문서

음악 생성

Suno V5 / V5.5 기반 텍스트 음악 생성 — 보컬, 가사, 스타일 제어. API 형식은 두 가지입니다. 트랙이 준비될 때까지 대기하는 단일 동기식 엔드포인트와, 프로덕션용 제출 후 폴링 방식의 비동기 엔드포인트 쌍(서명된 웹훅 포함)입니다.

엔드포인트: POST /v1/audio/music(동기식, 먼저 설명) 및 POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}(비동기식, 프로덕션 권장). 요청마다 트랙 두 개를 생성하며, 생성에는 약 1~3분이 걸립니다. 가격: $0.09(suno-v5)에서 생성 요청당 $0.09, suno-v5-5에서는 두 트랙에 대해 한 번 청구되며 선불 잔액에서 차감됩니다. 생성에 실패하면 요금이 청구되지 않습니다.

빠른 시작(동기식)

prompt와 Suno 모델을 전달합니다. 두 트랙이 준비될 때까지 요청 연결을 유지한 다음 영구 URL을 반환합니다.

import requests

# Synchronous: one request blocks until the tracks are ready (1-3 min).
resp = requests.post(
    "https://api.kunavo.com/v1/audio/music",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "model": "suno-v5",
        "prompt": "upbeat lofi hip hop for late-night coding, mellow piano",
        "instrumental": True,
    },
    timeout=600,  # generation can take a few minutes
)
# Suno returns ~2 tracks per request.
for track in resp.json()["data"]:
    print(track["url"], track.get("image_url"))
Suno 렌더링에는 1~3분이 걸립니다. 동기식 엔드포인트는 트랙이 준비될 때까지 서버에서 연결을 유지하며 폴링 한도는 약 6분이므로 HTTP 클라이언트에도 이에 맞는 시간 제한(≥600s)을 설정하세요. 더 오래 걸리는 요청, 프로덕션 트래픽 또는 모바일/불안정한 네트워크에서는 비동기 API를 권장합니다. 제출 요청은 몇 초 안에 반환됩니다.

매개변수

매개변수유형참고
model문자열(필수)음악 모델 슬러그 — suno-v5 또는 suno-v5-5.
prompt문자열(필수)음악 설명(또는 사용자 지정 모드에서 가사)
instrumentalbooltrue = 보컬 없음. 기본값은 false입니다.
customModebool고급 Suno 모드 — 구성/가사/스타일을 명시적으로 지정합니다.
stylestring스타일/장르 힌트(예: "로파이, 재즈, 칠")
titlestring트랙 제목
webhook_url문자열(https)비동기 전용 — 서명된 종료 이벤트를 여기로 전송합니다. 웹훅을 참조하세요.

음악 모델

슬러그제공자참고
suno-v5SunoSuno V5 — 보컬, 가사, 스타일 혼합
suno-v5-5SunoSuno V5.5 — 최신 버전, 더 높은 충실도와 더 긴 생성 시간

실시간 모델 목록 및 호출별 가격은 /models에서 확인하세요.

비동기 API(제출 + 폴링)

엔드포인트: POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}. 비디오 비동기 API와 같은 방식이므로 동일한 폴링/웹훅 코드가 여러 모달리티에서 작동합니다.

동기식 엔드포인트는 HTTP 연결을 몇 분간 유지합니다. 스크립트에는 편리하지만 모바일에서는 안정적이지 않습니다. 비동기 엔드포인트 쌍은 즉시 msc_* ID를 반환합니다. status가 completed 또는 failed가 될 때까지 GET /v1/audio/music/jobs/{id}를 폴링하세요. 모델, 가격, 영구 CDN URL은 동기식과 동일합니다.

import requests, time

# 1. Submit — returns immediately with a msc_ task id. No long-lived connection.
submit = requests.post(
    "https://api.kunavo.com/v1/audio/music/jobs",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        # Optional: retrying with the same key inside ~24h returns the
        # original task rather than submitting again.
        "Idempotency-Key": "my-song-uuid",
    },
    json={
        "model": "suno-v5",
        "prompt": "dreamy synthwave with a driving bassline",
        "title": "Midnight Drive",
    },
    timeout=60,
).json()

task_id = submit["id"]              # "msc_abc..."
status  = submit["status"]          # "queued"

# 2. Poll until terminal. Recommended cadence: 5s, backing off to 30s.
while status not in ("completed", "failed"):
    time.sleep(5)
    r = requests.get(
        f"https://api.kunavo.com/v1/audio/music/jobs/{task_id}",
        headers={"Authorization": f"Bearer {API_KEY}"},
        timeout=30,
    ).json()
    status = r["status"]

if status == "failed":
    raise RuntimeError(r["error"]["message"])
for track in r["output"]["tracks"]:
    print(track["url"])

응답 형식

필드유형참고
idstringmsc_- 접두사가 붙은 작업 ID
objectstring"music".
statusstringqueued | in_progress | completed | failed.
modelstring제출한 모델 슬러그
created_atint제출을 수락한 Unix 시간(초)
completed_at정수 | null종료 상태에 도달한 Unix 시간(초). 대기 중에는 null입니다.
expires_atint결과가 정리되는 Unix 시간(초)(약 30일 후)
progressint종료 상태 전에는 0, 이후에는 100
output객체 | null완료 시 {tracks[], archived}입니다.
output.tracksarray각 항목은 {url, stream_url, image_url}입니다. url / image_url은 영구 CDN 링크입니다.
error객체 | null실패 시 {code, message}입니다.

헤더 및 규칙

  • Idempotency-Key(선택 사항, ≤128자) — 같은 계정에서 동일한 키로 두 번 제출하면 중복 작업을 생성하는 대신 기존 작업을 반환합니다.
  • POST /v1/audio/music/jobs는 새 제출일 때 202 Accepted를 반환하고, 멱등성 키로 기존 결과를 재요청하면 200 OK를 반환합니다.
  • GET는 소유자별로 제한됩니다. 다른 계정에 속한 작업을 조회하면 404가 반환됩니다.
  • 권장 폴링 간격: 5초, 이후 최대 30초까지 늘립니다.

웹훅

제출할 때 webhook_url(https)를 전달하면 작업이 종료되는 즉시 Kunavo가 서명된 music.completed / music.failed 이벤트를 POST합니다. 재시도 및 백오프 방식으로 전달됩니다. 이벤트의 data 필드는 위 GET 페이로드와 정확히 동일합니다.

# Pass webhook_url on submit to be pushed a signed event on terminal —
# instead of (or alongside) polling:
#   {"model": "suno-v5", "prompt": "...", "webhook_url": "https://you.com/hook"}
#
# Verify the HMAC signature on your receiver (Flask shown):
import hmac, hashlib
from flask import request, abort

def verify(secret: str) -> dict:
    ts  = request.headers["X-Kunavo-Webhook-Timestamp"]
    sig = request.headers["X-Kunavo-Webhook-Signature"]   # "sha256=<hex>"
    raw = request.get_data(as_text=True)
    expected = "sha256=" + hmac.new(
        secret.encode(), f"{ts}.{raw}".encode(), hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, sig):
        abort(401)
    return request.get_json()

# Event body:
#   { "id": "evt_...", "object": "event",
#     "type": "music.completed" | "music.failed",
#     "created_at": 1700000000,
#     "data": { ...the GET /v1/audio/music/jobs/{id} payload... } }
서명은 {timestamp}.{rawBody}에 대한 HMAC-SHA256이며 X-Kunavo-Webhook-Signature: sha256=<hex>로 전송됩니다. 비디오 웹훅과 같은 방식이므로 검증기를 하나만 두고 둘 다 처리할 수 있습니다.

사용 방식 선택

동기식 /v1/audio/music비동기식 /v1/audio/music/jobs
적합한 용도일회성 스크립트, 노트북프로덕션, 모바일, 웹훅
네트워크연결을 1~3분 동안 유지몇 초 만에 제출하고 상태를 조회하거나 푸시 알림을 받으세요.
오류 복구응답을 잃으면 결과를 잃습니다.expires_at 이전에는 언제든지 ID를 다시 조회
웹훅—서명된 music.completed / music.failed 이벤트

응답 및 저장

각 트랙의 오디오 url와 커버 아트 image_url는 영구 files.kunavo.com 링크입니다. Kunavo가 모든 결과를 자체 CDN에 보관하므로 원본 Suno URL과 달리 만료되지 않습니다. stream_url는 Suno의 원본 스트리밍 링크로, 즉시 재생할 때 유용합니다. 모든 트랙은 /app/assets에도 표시됩니다.

아카이빙에 실패하면 output.archived는 false이고 URL은 Suno 임시 링크(약 24시간 후 만료)로 대체됩니다. 이 경우 직접 다시 호스팅하세요.

다음 단계