首页 / 博客 / Suno API Python 调用示例:生成、轮询与下载
API

Suno API Python 调用示例:生成、轮询与下载

用 Python 调用 Suno API:提交生成、轮询任务,处理 401/403/429 与超时,完成后获取 MP3 或 WAV,并附可直接运行的 requests 示例。

Python 编辑器与音乐波形连接到云端音乐引擎

图:Pexels

直接答案:用 Python 调 Suno API,只需要一个 API Key 和三个步骤:向 /api/music/create 提交生成,把返回的 song_id 放到 /api/music/query 轮询,状态完成后再调用下载接口取 MP3 或 WAV。不要在生成中反复提交同一请求,否则可能重复计费。

开始前需要准备什么

  • 一个在 Suno-API 控制台创建的 API Key。
  • Python 3.9 或更高版本,以及 requests。
  • 能访问 https://www.suno-api.io 的网络。
pip install requests

正确的调用顺序

  1. 提交生成:POST /api/music/create。描述、模型和可选参数放在 JSON 请求体里。
  2. 拿到任务 ID:响应里可能立即返回两条 clip,也可能先返回占位任务;真正用于查询的是最终 song_id。
  3. 轮询状态:POST /api/music/query,建议每次间隔 3–5 秒。
  4. 完成后取地址:调用 /api/music/download-url,再下载 MP3/WAV。
  5. 及时转存:上游音频地址可能是临时地址;需要长期保存时,下载到自己的对象存储。

可直接运行的 Python 示例

import os
import time
import requests

BASE = "https://www.suno-api.io"
API_KEY = os.environ["SUNO_API_KEY"]
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def post_json(path, payload):
    response = requests.post(
        BASE + path,
        headers=HEADERS,
        json=payload,
        timeout=120,
    )
    if response.status_code == 429:
        retry_after = int(response.headers.get("Retry-After", "15"))
        time.sleep(retry_after)
        return post_json(path, payload)
    response.raise_for_status()
    return response.json()


def extract_clips(payload):
    data = payload.get("data") or {}
    return data.get("clips") or payload.get("clips") or []


def generate_and_download(description):
    submitted = post_json("/api/music/create", {
        "description": description,
        "model": "suno-v6",
    })

    clips = extract_clips(submitted)
    if not clips:
        raise RuntimeError("生成响应中没有 clips,请检查接口返回或客户端请求 ID")

    song_id = clips[0]["song_id"]
    deadline = time.time() + 8 * 60

    while time.time() < deadline:
        result = post_json("/api/music/query", {"song_id": song_id})
        data = result.get("data") or {}
        status = str(data.get("status", "")).lower()

        if status in {"complete", "completed", "playable"}:
            break
        if status in {"failed", "error"}:
            raise RuntimeError(result)

        time.sleep(4)
    else:
        raise TimeoutError("任务等待超过 8 分钟,请稍后用 song_id 继续查询")

    media = post_json("/api/music/download-url", {
        "song_id": song_id,
        "kind": "song",
    })
    media_data = media.get("data") or {}
    media_url = media_data.get("url") or media_data.get("audio_url")
    if not media_url:
        raise RuntimeError("任务已完成,但下载响应没有媒体地址")

    file_response = requests.get(media_url, timeout=180)
    file_response.raise_for_status()
    with open("output.mp3", "wb") as fh:
        fh.write(file_response.content)
    return song_id, "output.mp3"


if __name__ == "__main__":
    print(generate_and_download("温暖的中文流行,钢琴前奏,女声"))

401、403、429 分别怎么处理

状态含义正确处理
401Key 错误、缺失或没有带 Bearer检查请求头,不要在 URL 参数里传 Key
403余额、账号状态或权限问题先看返回的 error,不要立即重试提交
429请求频率或轮询过快遵循 Retry-After,并使用指数退避
5xx上游或平台暂时异常保留 song_id 和请求 ID,先查询或联系支持

不要重复扣费的三个原则

  • 提交接口和查询接口分开;轮询只调查询接口。
  • 网络超时后先确认服务端是否已经创建任务,再决定是否重试提交。
  • 同一业务请求使用稳定的 client_request_id,方便平台侧做幂等与排查。

常见问题

Python 生成一首歌要等多久?

常见情况是几分钟内完成,但高峰期可能更久。不要用很短的单次请求超时判断失败;提交超时与最终生成超时是两件事。

为什么查询成功却没有音频地址?

任务还在 pending、submitted 或 processing 时,媒体字段为空是正常情况。等状态变成 completed 或 playable 后再获取。

音频地址能长期保存吗?

不要把临时的上游地址当作永久链接。需要长期交付时,完成下载后转存到你自己的对象存储,并在业务数据库中保存新地址。

继续阅读:Node.js 调用示例、任务轮询与超时处理、快速开始、歌曲查询 API。

0.6 元一次,固定出 2 首,下载不限次

官方原版 Suno 引擎,支持最新 V6,MP3 与 WAV 均可下载。注册不需要手机号。