Canzoni sperimentali e materiche, con voce
- Fino a 5 immagini di riferimento
- Testi scritti da te
- Musica
Lo chiami con il nome di modello suno/v6-wild/text-to-audio su POST /jobs/createTask, da 11 crediti per generazione (0,11 USD). I nuovi account ricevono 30 crediti gratuiti per provarlo prima nel Playground.
suno/v6-wild/text-to-audioPOST https://api.popnow.ai/api/v1/jobs/createTask# 1. Create the task. Keep the Idempotency-Key if you retry after a network error.
export IDEMPOTENCY_KEY="$(uuidgen)"
curl -X POST https://api.popnow.ai/api/v1/jobs/createTask \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $IDEMPOTENCY_KEY" \
-d '{
"model": "suno/v6-wild/text-to-audio",
"input": {
"prompt": "Calm ambient pads with a slow rising motif"
}
}'
# 2. Copy data.taskId from the response, then poll until state is succeeded, failed, canceled or expired.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $POPNOW_API_KEY"// Node 18+ (or any runtime with fetch). Keep the API key on your server.
const BASE = "https://api.popnow.ai/api/v1";
const headers = { Authorization: `Bearer ${process.env.POPNOW_API_KEY}` };
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function call(path, init = {}) {
const res = await fetch(BASE + path, { ...init, headers: { ...headers, ...init.headers } });
const body = await res.json();
if (body.code !== 200) throw new Error(`${body.code} ${body.msg}`);
return body.data;
}
const { taskId } = await call("/jobs/createTask", {
method: "POST",
headers: { "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
"model": "suno/v6-wild/text-to-audio",
"input": {
"prompt": "Calm ambient pads with a slow rising motif"
}
}),
});
// Poll with backoff. A finished task may still be copying files: wait while an asset is pending.
let task;
for (let delay = 2000; ; delay = Math.min(delay * 1.5, 15000)) {
await sleep(delay);
task = await call(`/jobs/recordInfo?taskId=${taskId}`);
const copying = (task.output?.assets ?? []).some((a) => a.pending && !a.unavailable);
if (["succeeded", "failed", "canceled", "expired"].includes(task.state) && !copying) break;
}
if (task.state !== "succeeded") throw new Error(`${task.state}: ${task.errorMessage ?? "no detail"}`);
// Each asset has a signed url (no API key needed) that expires at expiresAt: save the file.
for (const asset of task.output.assets) console.log(asset.url);import os, time, uuid, requests
BASE = "https://api.popnow.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['POPNOW_API_KEY']}"}
def call(method, path, **kwargs):
body = requests.request(method, BASE + path, headers={**HEADERS, **kwargs.pop("headers", {})}, timeout=30, **kwargs).json()
if body["code"] != 200:
raise RuntimeError(f'{body["code"]} {body["msg"]}')
return body["data"]
task_id = call(
"POST",
"/jobs/createTask",
headers={"Idempotency-Key": str(uuid.uuid4())}, # reuse it if you retry
json={
"model": "suno/v6-wild/text-to-audio",
"input": {
"prompt": "Calm ambient pads with a slow rising motif"
}
},
)["taskId"]
# Poll with backoff. A finished task may still be copying files: wait while an asset is pending.
delay = 2.0
while True:
time.sleep(delay)
task = call("GET", "/jobs/recordInfo", params={"taskId": task_id})
assets = (task.get("output") or {}).get("assets") or []
copying = any(a.get("pending") and not a.get("unavailable") for a in assets)
if task["state"] in ("succeeded", "failed", "canceled", "expired") and not copying:
break
delay = min(delay * 1.5, 15.0)
if task["state"] != "succeeded":
raise RuntimeError(f'{task["state"]}: {task.get("errorMessage", "no detail")}')
# Each asset has a signed url (no API key needed) that expires at expiresAt: save the file.
for asset in assets:
print(asset["url"])L’input è costruito dallo schema qui sotto, quindi supera la verifica così com’è. Sostituisci prompt e link con i tuoi.
Prezzo
| Opzione | Crediti per generazione | ≈ USD |
|---|---|---|
| Standard | 10,8 | 0,11 USD |
1 credito = 0,01 $ · Tutte le opzioni e i prezzi: GET /models/suno/v6-wild/text-to-audio
Ogni attività è arrotondata per eccesso ai crediti interi, quindi un'esecuzione al livello più basso costa 11 crediti per generazione (0,11 USD).
Limiti
- Immagini di riferimento
- 5
- Audio di riferimento
- 1
- Video di riferimento
- 1
- Lunghezza del prompt (caratteri)
- 3,000
Parametri
Questi campi vengono dallo stesso schema con cui verifichiamo ogni richiesta. I campi non elencati vengono rifiutati.
promptstringObbligatorioDescribe the song: genre, mood, tempo, instruments and voice. With lyrics or an instrumental this is the style (up to 1,000 characters); with no lyrics the model writes the words from it.
lyricsstringFacoltativoScrivi il tuo testo o lascia fare al modello.
generate_lyricsbooleanFacoltativoLet the model write the lyrics from the prompt. Only applies when lyrics is empty and instrumental is off.
instrumentalbooleanFacoltativoSolo musica, senza voce.
titlestringFacoltativoSong title (metadata, not sung). Applies with lyrics or an instrumental; otherwise the model names the song.
negative_promptstringFacoltativoStili o suoni che non vuoi nel brano.
vocal_genderstringFacoltativoMake a female or male lead vocal more likely. Applies with lyrics.
style_weightnumberFacoltativoHow closely to follow the style in the prompt, from 0 to 1.
weirdnessnumberFacoltativoHow experimental the song may get, from 0 (conventional) to 1 (unusual).
audio_weightnumberFacoltativoHow strongly a persona's audio shapes the result, from 0 to 1. Songs with vocals only.
varietyintegerFacoltativoHow different the two versions are from each other: 0 off, 1 normal (the model default), 2 high, 3 extra, 4 max.
persona_idstringFacoltativoID of an existing Suno persona to reuse its style or voice.
persona_modelstringFacoltativoWhether persona_id is a style persona or a voice persona.
image_urlsarray<string>FacoltativoImmagini che danno il mood: la musica ne prende l’atmosfera.
reference_video_urlsarray<string>FacoltativoUn video su cui la musica deve adattarsi.
reference_audio_urlsarray<string>FacoltativoAudio da riprendere: una voce, una musica o un ritmo.
JSON Schema grezzo
{
"additionalProperties": false,
"properties": {
"audio_weight": {
"description": "How strongly a persona's audio shapes the result, from 0 to 1. Songs with vocals only.",
"maximum": 1,
"minimum": 0,
"multipleOf": 0.01,
"type": "number"
},
"generate_lyrics": {
"default": true,
"description": "Let the model write the lyrics from the prompt. Only applies when lyrics is empty and instrumental is off.",
"type": "boolean"
},
"image_urls": {
"description": "Up to 5 mood images (JPEG, PNG or WebP, 10 MB each). Only when the model writes the lyrics.",
"items": {
"contentMediaType": [
"image/jpeg",
"image/png",
"image/webp",
"image/gif"
],
"format": "uri",
"type": "string"
},
"maxItems": 5,
"type": "array"
},
"instrumental": {
"default": false,
"description": "Generate music with no vocals.",
"type": "boolean"
},
"lyrics": {
"description": "Words to sing, sung in order. Section tags such as [Verse], [Chorus] and [Bridge] shape the song and are not sung.",
"maxLength": 5000,
"minLength": 1,
"type": "string"
},
"negative_prompt": {
"description": "Styles or elements to keep out of the song.",
"maxLength": 500,
"minLength": 1,
"type": "string"
},
"persona_id": {
"description": "ID of an existing Suno persona to reuse its style or voice.",
"maxLength": 200,
"minLength": 1,
"type": "string"
},
"persona_model": {
"description": "Whether persona_id is a style persona or a voice persona.",
"enum": [
"style_persona",
"voice_persona"
],
"type": "string"
},
"prompt": {
"description": "Describe the song: genre, mood, tempo, instruments and voice. With lyrics or an instrumental this is the style (up to 1,000 characters); with no lyrics the model writes the words from it.",
"maxLength": 3000,
"minLength": 1,
"type": "string"
},
"reference_audio_urls": {
"description": "One reference audio clip (MP3 or WAV, 6 seconds to 30 minutes). Only when the model writes the lyrics.",
"items": {
"contentMediaType": [
"audio/mpeg",
"audio/wav"
],
"format": "uri",
"type": "string"
},
"maxItems": 1,
"type": "array"
},
"reference_video_urls": {
"description": "One reference video (MP4 or WebM, up to 100 MB and 241 seconds). Only when the model writes the lyrics.",
"items": {
"contentMediaType": [
"video/mp4",
"video/webm",
"video/quicktime"
],
"format": "uri",
"type": "string"
},
"maxItems": 1,
"type": "array"
},
"style_weight": {
"description": "How closely to follow the style in the prompt, from 0 to 1.",
"maximum": 1,
"minimum": 0,
"multipleOf": 0.01,
"type": "number"
},
"title": {
"description": "Song title (metadata, not sung). Applies with lyrics or an instrumental; otherwise the model names the song.",
"maxLength": 80,
"minLength": 1,
"type": "string"
},
"variety": {
"description": "How different the two versions are from each other: 0 off, 1 normal (the model default), 2 high, 3 extra, 4 max.",
"maximum": 4,
"minimum": 0,
"type": "integer"
},
"vocal_gender": {
"description": "Make a female or male lead vocal more likely. Applies with lyrics.",
"enum": [
"female",
"male"
],
"type": "string"
},
"weirdness": {
"description": "How experimental the song may get, from 0 (conventional) to 1 (unusual).",
"maximum": 1,
"minimum": 0,
"multipleOf": 0.01,
"type": "number"
}
},
"required": [
"prompt"
],
"type": "object"
}Risposte, polling e callback
Tutti i modelli funzionano allo stesso modo: crei un task, poi lo interroghi o aspetti la callback.
Prima il prezzo
curl -X POST https://api.popnow.ai/api/v1/jobs/quote \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "suno/v6-wild/text-to-audio",
"input": {
"prompt": "Calm ambient pads with a slow rising motif"
}
}'Stesso corpo di createTask. Restituisce l’addebito previsto e quello massimo possibile, senza eseguire nulla.
Accettata
HTTP/1.1 202 Accepted
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
"state": "queued"
},
"request_id": "req_example_create"
}HTTP 202 significa che il task è stato accettato e i crediti sono riservati, non ancora addebitati. L’addebito finale non supera mai la riserva.
Controlla lo stato
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
-H "Authorization: Bearer $POPNOW_API_KEY"Controlla ogni pochi secondi allungando via via l’intervallo e fermati quando state è succeeded, failed, canceled o expired.
Task completato
{
"code": 200,
"msg": "success",
"data": {
"taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
"model": "suno/v6-wild/text-to-audio",
"state": "succeeded",
"output": {
"assets": [
{
"url": "https://cdn.popnow.ai/tasks/task_01k3m8x9q2z4v7n5p6r8s0t1w3/output.mp3?signature=FROM_RESPONSE",
"expiresAt": "2026-10-17T12:20:00Z",
"mime": "audio/mpeg",
"durationSeconds": 30
}
]
},
"settled": true
},
"request_id": "req_example_record"
}Scarica dall’url prima di expiresAt. Ti serve un link nuovo più tardi? Chiedilo con POST /common/download-url.
Verifica una callback
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
import express from "express";
const app = express();
// express.raw keeps the exact bytes that were signed; express.json would not match.
app.post("/hooks/popnow", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.header("X-Webhook-Timestamp");
const signature = req.header("X-Webhook-Signature") ?? "";
const body = JSON.parse(req.body.toString("utf8"));
const taskId = body.data?.taskId ?? body.task_id;
const digest = createHash("sha256").update(req.body).digest("hex");
const expected = createHmac("sha256", process.env.POPNOW_WEBHOOK_SECRET)
.update(`${taskId}.${timestamp}.${digest}`)
.digest("base64");
const ok = expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
// Check the signature first, then reject anything older than five minutes.
if (!ok || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(401).end();
res.status(200).end(); // answer fast, then fetch the task and store its files
});Con callBackUrl impostata ti inviamo il task completato. Verifica la firma sul corpo grezzo prima di fidarti.
Invia un file locale
curl -X POST https://api.popnow.ai/api/v1/common/upload-url \
-H "Authorization: Bearer $POPNOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"contentType": "image/png", "bytes": 482113}'
# PUT the file bytes to data.uploadUrl with every header in data.headers, then commit it:
curl -X POST https://api.popnow.ai/api/v1/files/$FILE_ID/commit \
-H "Authorization: Bearer $POPNOW_API_KEY"
# The commit returns a popnow://f/... reference. Put it in any image, video or
# audio field of the task input instead of a public https URL.I link https pubblici funzionano così come sono. I file locali passano prima da upload-url e commit.