Documentation

Documentation

Génération musicale

Génération de musique à partir de texte avec Suno V5 / V5.5 — voix, paroles et contrôle du style. Deux formats d’API : un point de terminaison synchrone unique qui attend que les pistes soient prêtes, et une paire asynchrone de soumission et d’interrogation (avec webhooks signés) pour la production.

Points de terminaison : POST /v1/audio/music (synchrone, présenté en premier) et POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id} (asynchrone, recommandé pour la production). Chaque requête génère deux pistes ; la génération dure environ 1–3 minutes. Prix : $0.09 par demande de génération sur suno-v5, $0.09 sur suno-v5-5 — les deux pistes sont facturées une seule fois, depuis un solde prépayé, et une génération échouée n’est pas facturée.

Démarrage rapide (synchrone)

Transmettez un prompt et un modèle Suno. La requête reste ouverte jusqu’à ce que les deux pistes soient prêtes, puis renvoie leurs URL permanentes.

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"))
Le rendu Suno prend 1–3 minutes. Côté serveur, le point de terminaison synchrone maintient la connexion ouverte jusqu’à ce que les pistes soient prêtes, avec un délai maximal d’interrogation d’environ 6 minutes ; réglez donc le délai d’attente de votre client HTTP en conséquence (≥600s). Pour les opérations plus longues, le trafic de production ou les réseaux mobiles ou peu fiables, privilégiez l’API asynchrone : la soumission renvoie une réponse en quelques secondes.

Paramètres

ParamètreTypeRemarques
modelchaîne (obligatoire)Un slug de modèle musical — suno-v5 ou suno-v5-5.
promptchaîne (obligatoire)Description de la musique (ou paroles en mode personnalisé).
instrumentalbooltrue = sans voix. Valeur par défaut : false.
customModeboolMode Suno avancé — contrôlez explicitement la structure, les paroles et le style.
stylestringIndication de style ou de genre, par exemple « lofi, jazz, chill ».
titlestringTitre de la piste.
webhook_urlchaîne (https)Mode asynchrone uniquement — envoyez ici un événement terminal signé. Voir Webhooks.

Modèles musicaux

SlugFournisseurRemarques
suno-v5SunoSuno V5 — voix, paroles et fusion de styles.
suno-v5-5SunoSuno V5.5 — le plus récent, avec une fidélité supérieure et des générations plus longues.

Consultez /models pour obtenir la liste à jour et les tarifs par appel.

API asynchrone (soumettre + interroger)

Points de terminaison : POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}. Reprend le fonctionnement de l’API vidéo asynchrone ; le même code d’interrogation et de webhook fonctionne donc pour les deux modalités.

Le point de terminaison synchrone maintient une connexion HTTP ouverte pendant plusieurs minutes — pratique pour les scripts, mais peu fiable sur mobile. La paire asynchrone renvoie immédiatement un identifiant msc_* ; interrogez GET /v1/audio/music/jobs/{id} jusqu’à ce que status soit completed ou failed. Mêmes modèles, mêmes tarifs et mêmes URL CDN permanentes.

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"])

Structure de la réponse

ChampTypeRemarques
idstringIdentifiant de tâche préfixé par msc_.
objectstring"music".
statusstringen attente | en cours | terminée | échouée.
modelstringSlug du modèle envoyé.
created_atintHorodatage Unix (secondes) de l’acceptation de la soumission.
completed_atint | nullHorodatage Unix (secondes) de la fin de la tâche ; null tant qu’elle est en attente.
expires_atintHorodatage Unix (secondes) après lequel le résultat est purgé (environ 30 jours).
progressint0 jusqu’à la fin, puis 100.
outputobject | null{tracks[], archived} une fois terminé.
output.tracksarrayChaque élément : {url, stream_url, image_url}. url / image_url sont des liens CDN permanents.
errorobject | null{code, message} en cas d’échec.

En-têtes et conventions

  • Idempotency-Key (facultatif, ≤128 caractères) — soumettre une deuxième fois avec la même clé sur le même compte renvoie la tâche d’origine au lieu d’en créer un doublon.
  • POST /v1/audio/music/jobs renvoie 202 Accepted lors d’une nouvelle soumission et 200 OK lorsqu’une clé d’idempotence rejoue un résultat.
  • GET est limité au propriétaire : interroger une tâche appartenant à un autre compte renvoie 404.
  • Fréquence d’interrogation recommandée : 5 s, avec un délai progressif jusqu’à 30 s.

Webhooks

Transmettez webhook_url (https) lors de la soumission ; Kunavo envoie alors par POST un événement terminal signé music.completed / music.failed dès que la tâche se termine, avec des tentatives répétées et un délai progressif. Le champ data de l’événement correspond exactement à la charge utile GET ci-dessus.

# 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... } }
La signature est HMAC-SHA256 sur {timestamp}.{rawBody}, envoyée dans X-Kunavo-Webhook-Signature: sha256=<hex>. Même méthode que pour les webhooks vidéo : un seul vérificateur suffit pour les deux.

Quel format choisir ?

Synchrone /v1/audio/musicAsynchrone /v1/audio/music/jobs
Idéal pourScripts ponctuels, notebooksProduction, mobile, webhooks
RéseauMaintient la connexion ouverte pendant 1-3 minEnvoyez en quelques secondes ; interrogez ou recevez une notification
Récupération après échecPerdre la réponse = perdre le résultatRéinterrogez l’identifiant à tout moment avant expires_at
Webhooks—Événements signés music.completed / music.failed

Réponse et stockage

Le url (audio) et le image_url (illustration de couverture) de chaque piste sont des liens permanents files.kunavo.com — Kunavo archive chaque résultat sur son propre CDN ; contrairement aux URL Suno brutes, ils n’expirent donc jamais. stream_url est le lien de diffusion en continu original de Suno (pratique pour une lecture immédiate). Chaque piste apparaît également dans /app/assets.

En cas d’échec de l’archivage, output.archived vaut false et les URL renvoient aux liens temporaires de Suno (qui expirent au bout d’environ 24 h) ; dans ce cas, hébergez-les vous-même.

Étapes suivantes