문서
음악 생성
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"))매개변수
| 매개변수 | 유형 | 참고 |
|---|---|---|
model | 문자열(필수) | 음악 모델 슬러그 — suno-v5 또는 suno-v5-5. |
prompt | 문자열(필수) | 음악 설명(또는 사용자 지정 모드에서 가사) |
instrumental | bool | true = 보컬 없음. 기본값은 false입니다. |
customMode | bool | 고급 Suno 모드 — 구성/ |
style | string | 스타일/장르 힌트(예: "로파이, 재즈, 칠") |
title | string | 트랙 제목 |
webhook_url | 문자열(https) | 비동기 전용 — 서명된 종료 이벤트를 여기로 전송합니다. 웹훅을 참조하세요. |
음악 모델
| 슬러그 | 제공자 | 참고 |
|---|---|---|
suno-v5 | Suno | Suno V5 — 보컬, 가사, 스타일 혼합 |
suno-v5-5 | Suno | Suno 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"])응답 형식
| 필드 | 유형 | 참고 |
|---|---|---|
id | string | msc_- 접두사가 붙은 작업 ID |
object | string | "music". |
status | string | queued | in_progress | completed | failed. |
model | string | 제출한 모델 슬러그 |
created_at | int | 제출을 수락한 Unix 시간(초) |
completed_at | 정수 | null | 종료 상태에 도달한 Unix 시간(초). 대기 중에는 null입니다. |
expires_at | int | 결과가 정리되는 Unix 시간(초)(약 30일 후) |
progress | int | 종료 상태 전에는 0, 이후에는 100 |
output | 객체 | null | 완료 시 {tracks[], archived}입니다. |
output. | array | 각 항목은 {url, stream_url, image_ |
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/ | 비동기식 /v1/ | |
|---|---|---|
| 적합한 용도 | 일회성 스크립트, 노트북 | 프로덕션, 모바일, 웹훅 |
| 네트워크 | 연결을 1~3분 동안 유지 | 몇 초 만에 제출하고 상태를 조회하거나 푸시 알림을 받으세요. |
| 오류 복구 | 응답을 잃으면 결과를 잃습니다. | expires_at 이전에는 언제든지 ID를 다시 조회 |
| 웹훅 | — | 서명된 music. |
응답 및 저장
각 트랙의 오디오 url와 커버 아트 image_url는 영구 files.kunavo.com 링크입니다. Kunavo가 모든 결과를 자체 CDN에 보관하므로 원본 Suno URL과 달리 만료되지 않습니다. stream_url는 Suno의 원본 스트리밍 링크로, 즉시 재생할 때 유용합니다. 모든 트랙은 /app/assets에도 표시됩니다.
output.archived는 false이고 URL은 Suno 임시 링크(약 24시간 후 만료)로 대체됩니다. 이 경우 직접 다시 호스팅하세요.