Dokumentasi

Dokumentasi

Pembuatan musik

Konversi teks ke musik dengan Suno V5 / V5.5 — vokal, lirik, dan kontrol gaya. Dua bentuk API: endpoint sinkron sekali panggil yang menunggu hingga trek siap, serta pasangan API asinkron submit-and-poll (dengan webhook bertanda tangan) untuk penggunaan produksi.

Endpoint: POST /v1/audio/music (sinkron, dibahas terlebih dahulu), serta POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id} (asinkron, disarankan untuk penggunaan produksi). Setiap permintaan menghasilkan dua trek; proses pembuatan berlangsung sekitar 1–3 menit. Harga: $0.09 per permintaan pembuatan di suno-v5, $0.09 di suno-v5-5 — kedua trek ditagih sekali, dari saldo prabayar, dan pembuatan yang gagal tidak ditagih.

Mulai cepat (sinkron)

Kirim prompt dan model Suno. Permintaan akan terus terbuka hingga kedua trek siap, lalu mengembalikan URL permanennya.

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"))
Proses render Suno memerlukan 1–3 menit. Endpoint sinkron mempertahankan koneksi terbuka di sisi server hingga trek siap, dengan batas polling sekitar 6 menit, jadi atur batas waktu klien HTTP Anda agar sesuai (≥600s). Untuk proses yang lebih lama, lalu lintas produksi, atau jaringan seluler/tidak andal, pilih API asinkron — pengiriman permintaan selesai dalam hitungan detik.

Parameter

ParameterTipeCatatan
modelstring (wajib)Slug model musik — suno-v5 atau suno-v5-5.
promptstring (wajib)Deskripsi musik (atau lirik, dalam mode kustom).
instrumentalbooltrue = tanpa vokal. Default false.
customModeboolMode Suno lanjutan — atur struktur / lirik / gaya secara eksplisit.
stylestringPetunjuk gaya / genre, misalnya "lofi, jazz, chill".
titlestringJudul trek.
webhook_urlstring (https)Khusus asinkron — kirim event terminal bertanda tangan ke sini. Lihat Webhooks.

Model musik

SlugPenyediaCatatan
suno-v5SunoSuno V5 — vokal, lirik, dan perpaduan gaya.
suno-v5-5SunoSuno V5.5 — terbaru, dengan fidelitas lebih tinggi dan generasi yang lebih panjang.

Periksa /models untuk daftar langsung dan harga per panggilan.

API asinkron (submit + poll)

Endpoint: POST /v1/audio/music/jobs + GET /v1/audio/music/jobs/{id}. Mengikuti pola API video asinkron, sehingga kode polling / webhook yang sama berfungsi untuk semua modalitas.

Endpoint sinkron mempertahankan koneksi HTTP terbuka selama beberapa menit — praktis untuk skrip, tetapi tidak andal di jaringan seluler. Pasangan endpoint asinkron segera mengembalikan ID msc_*; lakukan polling pada GET /v1/audio/music/jobs/{id} hingga status bernilai completed atau failed. Model, harga, dan URL CDN permanen tetap sama.

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

Bentuk respons

KolomTipeCatatan
idstringID tugas berawalan msc_.
objectstring"music".
statusstringqueued | in_progress | completed | failed.
modelstringSlug model yang Anda kirim.
created_atintDetik Unix saat kami menerima permintaan.
completed_atint | nullDetik Unix saat status menjadi terminal — null selama masih tertunda.
expires_atintDetik Unix, 30 hari setelah pengiriman: tugas dapat di-polling setidaknya sampai saat itu. URL hasilnya tidak kedaluwarsa.
progressint0 hingga status terminal, lalu 100.
outputobject | null{tracks[], archived} saat selesai.
output.tracksarrayMasing-masing: {url, stream_url, image_url}. url / image_url adalah tautan CDN permanen.
errorobject | null{code, message} saat gagal.

Header dan konvensi

  • Idempotency-Key (opsional, ≤128 karakter) — mengirimkan permintaan dua kali dengan kunci yang sama pada akun yang sama akan mengembalikan tugas asli, bukan membuat duplikat.
  • POST /v1/audio/music/jobs mengembalikan 202 Accepted pada pengiriman baru dan 200 OK saat kunci idempotensi memutar ulang hasil.
  • GET dibatasi pada pemilik: permintaan untuk tugas milik akun lain mengembalikan 404.
  • Jeda polling yang disarankan: 5 s, bertambah secara bertahap hingga 30 s.

Webhook

Saat mengirim, berikan webhook_url (https), lalu Kunavo mengirim POST event music.completed / music.failed bertanda tangan segera setelah tugas mencapai status terminal — dengan pengiriman ulang dan jeda bertahap. Kolom data pada event persis sama dengan payload GET di atas.

# 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... } }
Tanda tangan dihitung sebagai HMAC-SHA256 atas {timestamp}.{rawBody}, dan dikirim sebagai X-Kunavo-Webhook-Signature: sha256=<hex>. Caranya sama dengan webhook video, sehingga satu verifier dapat menangani keduanya.

Kapan menggunakan yang mana

Sinkron /v1/audio/musicAsinkron /v1/audio/music/jobs
Paling cocok untukSkrip sekali jalan, notebookProduksi, seluler, webhook
JaringanMempertahankan koneksi selama 1-3 menitKirim dalam hitungan detik; lakukan polling atau terima dorongan
Pemulihan kegagalanKehilangan respons = kehilangan hasilKirim ulang kueri ID kapan saja sebelum expires_at
Webhook—music.completed / music.failed bertanda tangan

Respons dan penyimpanan

url (audio) dan image_url (sampul) untuk setiap trek adalah tautan permanen files.kunavo.com — Kunavo mengarsipkan setiap hasil ke CDN miliknya sendiri, sehingga berbeda dari URL Suno mentah, tautan tersebut tidak pernah kedaluwarsa. stream_url adalah tautan streaming asli Suno (berguna untuk pemutaran langsung). Setiap trek juga muncul di /app/assets.

Jika pengarsipan gagal, output.archived bernilai false dan URL akan beralih ke tautan sementara Suno (yang kedaluwarsa setelah sekitar 24 jam) — jika demikian, host sendiri hasilnya.

Langkah selanjutnya