Skip to main content
POST
Generate music from text prompt
This call is synchronous: it holds the connection until the track is rendered and answers with the audio. There is no job_id and no status endpoint to poll — allow for a client timeout of several minutes. The response carries a URL to the MP3 for each rendered track, plus separate stems if the model exposes them (Suno supports vocals + instrumentals):
Add ?stream=true to receive SSE progress events instead of one blocking response. If rendering outruns the 5-minute wait budget the call answers 504 with a job_id in the error body; the track is still rendered and billed, and is collected from GET /v1/images/jobs/{job_id}, which serves media jobs of every modality.

Sample output

30-second clip generated with lyria-3-clip (Google Lyria).

Parameters

  • prompt — natural-language description (required)
  • operationgenerate (default), extend, upload_cover, upload_extend, add_instrumental, add_vocals, sounds, vocal_removal, lyrics
  • response_formatmp3 (default) or wav, where the model supports it
  • custom_mode — Suno: unlocks title, style and lyrics
  • style — Suno: genre/style string, max 1000 chars
  • lyrics — Suno: explicit lyrics, custom mode only
  • instrumental — Suno: render without vocals
  • vocal_gender — Suno: exactly m or f
There is no duration parameter. Length is set by the model and the material you give it — Lyria 3 Clip always renders 30 s. duration_seconds appears on each track in the response, reporting what was actually rendered. See Music generation for the full Suno parameter set.

Supported models

Suno and Google Lyria. See Models → Music.

Authorizations

Authorization
string
header
required

API key in format: Bearer inf_***

Query Parameters

stream
enum<string>

Read the generation as Server-Sent Events instead of waiting for a JSON body. A QUERY parameter, not a body field — the handler reads @Query('stream') and accepts only the strings "true" and "1", so a stream key in the BODY is ignored and the caller silently gets buffered JSON. (chat/completions made the opposite choice and takes it in the body; the two are not interchangeable.) A streaming request also never defers: it stays on the inline path, so it cannot answer 504 with a job id the way the JSON mode can.

Available options:
true,
1

Body

application/json
model
string
required

Model ID to use for music generation

prompt
string
required

Text prompt describing the music. For Lyria 3 Clip, always produces 30s. For Lyria 3 Pro, control duration via prompt or timestamps. For Suno, max 500 chars in non-custom mode, up to 5000 in custom mode.

operation
enum<string>
default:generate

Suno operation type. Default = generate. Other operations require additional fields (audio_id, upload_url, etc).

Available options:
generate,
extend,
upload_cover,
upload_extend,
add_instrumental,
add_vocals,
sounds,
vocal_removal,
lyrics
images
object[]

Up to 10 base64-encoded images to inspire the music (Lyria 3 only)

response_format
enum<string>
default:mp3

Output format. WAV only supported by Lyria 3 Pro and Suno.

Available options:
mp3,
wav
custom_mode
boolean

Suno: Enable custom mode (full control over style/title/lyrics)

instrumental
boolean

Suno: Generate instrumental track only (no vocals)

title
string

Suno: Track title (custom mode, max 100 chars)

style
string

Suno: Music genre/style (custom mode, max 1000 chars)

lyrics
string

Suno: Lyrics text (custom mode, when not instrumental)

negative_tags
string

Suno: Styles to exclude (e.g. "Heavy Metal, Upbeat Drums")

vocal_gender
enum<string>

Suno: Preferred vocal gender

Available options:
m,
f
style_weight
number

Suno: Style adherence weight (0.0-1.0)

Required range: 0 <= x <= 1
weirdness_constraint
number

Suno: Creativity/novelty constraint (0.0-1.0)

Required range: 0 <= x <= 1
audio_weight
number

Suno: Input audio influence weight (0.0-1.0)

Required range: 0 <= x <= 1
persona_id
string

Suno: Persona ID to apply (custom mode)

persona_model
enum<string>

Suno: Persona model type

Available options:
style_persona,
voice_persona
audio_id
string

Suno: Source audio ID (for extend, vocal_removal)

task_id
string

Suno: Task ID (vocal_removal — references original generation task)

upload_url
string

Suno: Audio file URL (for upload_cover, upload_extend, add_instrumental, add_vocals)

continue_at
number

Suno: Continue from this second mark (extend operations)

default_param_flag
boolean

Suno: Use default params (extend operations)

separation_type
enum<string>

Suno: Vocal removal type (2 stems vs up to 12 stems)

Available options:
separate_vocal,
split_stem
tags
string

Suno: Tags for add_instrumental operation

sound_loop
boolean

Suno sounds: Loop the generated sound

sound_tempo
integer

Suno sounds: BPM (1-300)

Required range: 1 <= x <= 300
sound_key
string

Suno sounds: Musical key

Response

Without ?stream=true (the default) this is application/json — one result object, shown below. Audio is uploaded to private storage and returned as a signed url (7-day expiry); if the storage upload fails, the response falls back to inline b64_audio.

With ?stream=true it is text/event-stream instead: a sequence of data: <json>\n\n lines terminated by a literal data: [DONE]. OpenAPI 3.0 has no vocabulary for "repeat this, then terminate with a sentinel", so the text/event-stream schema below describes the JSON payload of a SINGLE data: line — never the whole body — which is the precedent chat/completions set.

A three-member oneOf rather than chat's single chunk schema, because music's frames are three genuinely different objects, and rather than the pipeline-run stream's bare {type: "string"}, because here the discriminant is IN the payload: progress repeats while the track renders, then exactly one terminal frame, completed or error. (The pipeline-run stream cannot be described this way — its encoder moves type out onto the SSE event: line, leaving no discriminant in the body to key a oneOf on.)

Read type before anything else. The error frame is a real failure delivered as a frame — once SSE headers are flushed the gateway cannot answer with an HTTP status, so the response is still a 200 that ends in [DONE] — and credits_used appears ONLY on the completed frame, so a client that ignores type sees a successful, empty, apparently free stream.

created
integer

Unix timestamp (seconds) when the generation completed

Example:

1713204900

data
object[]
credits_used
integer

Credits deducted from the workspace balance for this request

Example:

180