Dokumentation
Musikgenerierung
Text zu Musik mit Suno V5 / V5.5 — Gesang, Liedtexte und Stilsteuerung. Zwei API-Formate: ein einzelner synchroner Endpunkt, der blockiert, bis die Tracks bereitstehen, und ein asynchrones Submit-and-Poll-Paar (mit signierten Webhooks) für den Produktionseinsatz.
Endpunkte: POST /v1/audio/music (synchron, zuerst behandelt) und POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id} (asynchron, für den Produktionseinsatz empfohlen). Jede Anfrage generiert zwei Tracks; die Generierung dauert etwa 1–3 Minuten. Preis: $0.09 pro Generierungsanfrage bei suno-v5, $0.09 bei suno-v5-5 — beide Tracks werden einmalig aus einem vorausbezahlten Guthaben abgerechnet; eine fehlgeschlagene Generierung wird nicht berechnet.
Schnellstart (synchron)
Übergeben Sie ein prompt und ein Suno-Modell. Die Anfrage bleibt offen, bis beide Tracks bereitstehen; anschließend werden ihre permanenten URLs zurückgegeben.
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"))Parameter
| Parameter | Typ | Hinweise |
|---|---|---|
model | String (erforderlich) | Ein Musikmodell-Slug — suno-v5 oder suno-v5-5. |
prompt | String (erforderlich) | Beschreibung der Musik (oder im benutzerdefinierten Modus der Liedtext). |
instrumental | bool | true = kein Gesang. Standardwert false. |
customMode | bool | Erweiterter Suno-Modus — Struktur, Liedtexte und Stil explizit steuern. |
style | string | Hinweis zu Stil oder Genre, z. B. „lofi, jazz, chill“. |
title | string | Tracktitel. |
webhook_url | Zeichenfolge (https) | Nur asynchron — hier ein signiertes Abschlusssignal senden. Siehe Webhooks. |
Musikmodelle
| Slug | Anbieter | Hinweise |
|---|---|---|
suno-v5 | Suno | Suno V5 — Gesang, Liedtexte, Stilüberblendung. |
suno-v5-5 | Suno | Suno V5.5 — neueste Version, höhere Klangtreue und längere Generierungen. |
Unter /models finden Sie die aktuelle Liste und die Preise pro Aufruf.
Asynchrone API (Submit + Poll)
Endpunkte: POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}. Entspricht der asynchronen Video-API, sodass derselbe Polling- und Webhook-Code für beide Modalitäten funktioniert.
Der synchrone Endpunkt hält eine HTTP-Verbindung minutenlang offen — praktisch für Skripte, aber unzuverlässig auf Mobilgeräten. Das asynchrone Endpunktpaar gibt sofort eine msc_*-ID zurück. Fragen Sie GET /v1/audio/music/jobs/{id} wiederholt ab, bis status den Status completed oder failed hat. Modelle, Preise und permanente CDN-URLs sind dieselben.
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"])Antwortformat
| Feld | Typ | Hinweise |
|---|---|---|
id | string | Aufgaben-ID mit Präfix msc_. |
object | string | "music". |
status | string | queued | in_progress | completed | failed. |
model | string | Der übermittelte Modell-Slug. |
created_at | int | Unix-Zeit in Sekunden, zu der wir die Übermittlung angenommen haben. |
completed_at | int | null | Unix-Zeit in Sekunden beim Abschluss — bei ausstehenden Aufgaben null. |
expires_at | int | Unix-Zeit in Sekunden, ab der das Ergebnis bereinigt wird (~30 Tage). |
progress | int | Bis zum Abschluss 0, danach 100. |
output | object | null | {tracks[], archived} bei abgeschlossenem Vorgang. |
output. | array | Jeder Eintrag: {url, stream_url, image_url}. url / image_url sind dauerhafte CDN-Links. |
error | object | null | {code, message} bei fehlgeschlagenem Vorgang. |
Header und Konventionen
Idempotency-Key(optional, ≤128 Zeichen) — wird derselbe Schlüssel im selben Konto zweimal verwendet, wird die ursprüngliche Aufgabe zurückgegeben, statt ein Duplikat zu erstellen.POST /v1/audio/music/jobsgibt bei einer neuen Übermittlung 202 Accepted und bei der erneuten Ausgabe eines Ergebnisses mithilfe eines Idempotenzschlüssels 200 OK zurück.GETist auf den jeweiligen Inhaber beschränkt: Wird eine Aufgabe abgefragt, die zu einem anderen Konto gehört, wird 404 zurückgegeben.- Empfohlenes Polling-Intervall: 5 s, schrittweise verlängert bis auf 30 s.
Webhooks
Übergeben Sie bei der Übermittlung webhook_url (https). Kunavo sendet dann beim Abschluss der Aufgabe ein signiertes Ereignis music.completed / music.failed per POST. Die Zustellung erfolgt mit Wiederholungsversuchen und schrittweise verlängerten Intervallen. Das Feld data des Ereignisses entspricht exakt der oben gezeigten GET-Antwort.
# 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... } }HMAC-SHA256 über {timestamp}.{rawBody} und wird als X-Kunavo-Webhook-Signature: sha256=<hex> gesendet. Das Verfahren entspricht den Video-Webhooks, sodass ein Verifizierer für beide genügt.Wann welche Variante verwenden
| Synchron /v1/ | Asynchron /v1/ | |
|---|---|---|
| Am besten geeignet für | Einmalige Skripte, Notebooks | Produktion, Mobilgeräte, Webhooks |
| Netzwerk | Hält die Verbindung 1–3 Minuten offen | In Sekunden einreichen; abfragen oder Push-Benachrichtigungen erhalten |
| Fehlerbehebung | Antwort verloren = Ergebnis verloren | ID jederzeit vor Ablauf von expires_at erneut abfragen |
| Webhooks | — | Signierte music. |
Antwort und Speicherung
Der url-Link (Audio) und der image_url-Link (Coverbild) jedes Tracks sind permanente files.kunavo.com-Links. Kunavo archiviert jedes Ergebnis auf dem eigenen CDN; anders als die ursprünglichen Suno-URLs laufen sie deshalb nie ab. stream_url ist der ursprüngliche Suno-Streaming-Link (praktisch für sofortige Wiedergabe). Jeder Track erscheint außerdem in /app/assets.
output.archived false und die URLs verweisen auf die temporären Suno-Links (die nach etwa 24 Stunden ablaufen) — hosten Sie sie in diesem Fall selbst erneut.