文档

文档

音乐生成

使用 Suno V5 / V5.5 将文本生成音乐,支持人声、歌词和风格控制。提供两种 API 形式:一种是单次调用的同步端点,会一直等待直至曲目就绪;另一种是适用于生产环境的提交并轮询式异步 API(支持签名 webhook)。

端点:POST /v1/audio/music(同步,首先介绍),以及 POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}(异步,推荐用于生产环境)。每个请求生成两首曲目;生成约需 1–3 分钟。价格:在 suno-v5 上每个生成请求 $0.09,在 suno-v5-5 上为 $0.09 ——两首曲目只收取一次费用,从预付余额中扣除;生成失败不收费。

快速开始(同步)

传入一个 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字符串(必填)音乐模型 slug —— suno-v5 或 suno-v5-5。
prompt字符串(必填)音乐描述(自定义模式下为歌词)。
instrumentalbooltrue = 无人声。默认值为 false。
customModeboolSuno 高级模式 ——明确设置曲目结构 / 歌词 / 风格。
stylestring风格 / 流派提示,例如“lofi, jazz, chill”。
titlestring曲目标题。
webhook_urlstring(https)仅限异步 ——在此推送签名的终态事件。请参阅 Webhooks。

音乐模型

标识符(slug)提供商备注
suno-v5SunoSuno V5 ——支持人声、歌词和风格融合。
suno-v5-5SunoSuno V5.5 ——最新版本,保真度更高,生成时长更长。

请查看 /models,获取当前模型列表和每次调用的定价。

异步 API(提交 + 轮询)

端点:POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}。结构与异步视频 API 相同,因此相同的轮询 / webhook 代码可用于不同模态。

同步端点会将 HTTP 连接保持数分钟 ——适合脚本,但在移动网络上不可靠。异步端点组合会立即返回一个 msc_* ID;你可以轮询 GET /v1/audio/music/jobs/{id},直到 status 变为 completed 或 failed。模型、定价和永久 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"])

响应格式

字段类型备注
idstring以 msc_ 为前缀的任务 ID。
objectstring"music".
statusstringqueued | in_progress | completed | failed。
modelstring提交时指定的模型 slug。
created_atint我们接受提交请求时的 Unix 秒数。
completed_atint | null进入终态时的 Unix 秒数 ——任务待处理时为 null。
expires_atint提交后满 30 天时的 Unix 秒数:至少在此之前都可以轮询该任务。其结果 URL 不会过期。
progressint进入终态前为 0,之后为 100。
outputobject | null完成时返回 {tracks[], archived}。
output.tracksarray每条记录包含:{url, stream_url, image_url}。url / image_url 是永久 CDN 链接。
errorobject | null失败时返回 {code, message}。

请求头与约定

  • Idempotency-Key(可选,≤128 个字符)——在同一账户中使用相同密钥重复提交时,会返回原任务,而不会创建重复任务。
  • 新提交时,POST /v1/audio/music/jobs 返回 202 Accepted;幂等密钥重放结果时,则返回 200 OK。
  • GET 的作用范围限定于所属账户:查询属于其他账户的任务会返回 404。
  • 建议的轮询间隔:5 s,随后逐渐延长至 30 s。

Webhook 回调

提交时传入 webhook_url(https),任务进入终态时,Kunavo 会立即向该地址 POST 一个带签名的 music.completed / music.failed 事件,并通过重试和退避机制进行投递。事件的 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> 发送。生成签名的方式与视频 webhook 相同,因此一个验证器即可处理两者。

何时使用哪种方式

同步 /v1/audio/music异步 /v1/audio/music/jobs
适用场景一次性脚本、笔记本生产环境、移动端、webhook
网络连接保持 1-3 分钟几秒内提交;轮询或接收推送
故障恢复丢失响应 = 丢失结果expires_at 到期前随时重新查询该 ID
Webhook 回调—已签名的 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 小时后过期)——此时请自行重新托管。

接下来