Udio
Text-to-music and lyrics-to-music generation using Udio, with extend, remix, style references and lyric writing.
POST /v2/music/generate — model: "udio"
Generate music from a description, your own lyrics, or the style of a track you already have. Every call returns 2 songs.
See Music Generation overview for common request fields, response format, and error codes.
Length and cost
Udio builds a song by chaining 32-second samples, so udioParams.duration takes
one of exactly four values — 32, 65, 97 or 130 seconds — and each
one costs proportionally more, because each is proportionally more audio to
render. Omitting it generates 32 seconds.
To go longer than 130 seconds, generate a song and then extend it, repeatedly.
Model-specific parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
udioParams.duration | integer | 32 | Song length in seconds: 32, 65, 97 or 130. Sets the price |
udioParams.lyrics_type | string | "generate" | Who writes the words: "generate" (Udio does), "user" (you do — prompt is the lyrics), "instrumental" (nobody sings) |
udioParams.lyrics | string | — | Your own lyrics (max 5,000 characters). Implies lyrics_type: "user" and leaves prompt free to describe the music |
udioParams.lyrics_prompt | string | — | What the lyrics should be about (max 2,000 characters). Udio writes them from this. Use POST /v2/music/udio/lyrics first if you want to read them before spending credits |
udioParams.style | string | — | Music style / genre hint (max 1,000 characters). Used as the description when lyrics_type is "user" |
udioParams.style_ref | object | — | Generate in the style of a reference instead of from a description. When set, prompt becomes optional |
udioParams.voice | object | — | A reference voice to sing it |
udioParams.model | string | "udio32-v1.5" | Model version: udio32-v1.5, udio32-v1, udio32-v2, udio130-v1.5, udio130-v1. The udio130-* models cannot be extended afterwards |
udioParams.title | string | — | Track title (max 80 characters) |
udioParams.negative_tags | string | — | Styles to avoid, comma-separated (max 500 characters) |
udioParams.bpm | number | — | Target tempo, 60–200 |
udioParams.manual_mode | boolean | false | Send prompt verbatim, without Udio's prompt optimizer |
udioParams.prompt_strength | number | — | 0–1. How closely to follow the description |
udioParams.lyrics_strength | number | — | 0–1. How closely to follow the lyrics |
udioParams.clarity_strength | number | — | 0–1. Favours clean, intelligible output |
udioParams.generation_quality | number | — | 0–1. Trades render time for quality |
udioParams.seed | integer | — | Seed for reproducibility |
References
udioParams.style_ref and udioParams.voice both point at one thing, named in
exactly one of four ways:
| Field | Description |
|---|---|
song | A song ID from an earlier job's result.tracks[].id |
file | Audio you uploaded |
name | An entry in Udio's library, by name |
id | An entry in Udio's library, by ID |
Optionally with similarity (1–7, how closely to follow it) and cropStart
(seconds into the source audio to start from).
Credit cost
| Variant | Credits |
|---|---|
d32 | 9 |
d65 | 17 |
d97 | 26 |
d130 | 35 |
extend | 9 |
remix-d32 | 9 |
remix-d65 | 17 |
remix-d97 | 26 |
remix-d130 | 35 |
write_lyrics | 1 |
upload_audio | 1 |
The d* variant follows udioParams.duration. An extension always renders one
32-second sample, whatever the source length, so it costs the same as a 32-second
generation; a remix re-renders the whole song (or the cropped range), so it is
priced on that length.
Example result
Once the job is COMPLETED, the result object on GET /v2/jobs/:id looks like:
{
"tracks": [
{
"id": "2e7d9c1a-5f3b-4e6d-8a0c-1b4f7e2d9a5c",
"audioUrl": "https://cdn2.apiframe.ai/audio/c3d4e5f6-a7b8-9012-cdef-345678901234-0.mp3",
"imageUrl": "https://cdn2.apiframe.ai/audio/c3d4e5f6-a7b8-9012-cdef-345678901234-0.jpeg",
"title": "Midnight Frequencies",
"tags": "lo-fi, hip hop, chill",
"duration": 130.7
},
{
"id": "9a4b6e0d-1c8f-4a2e-b5d7-3f0a9c6e1b48",
"audioUrl": "https://cdn2.apiframe.ai/audio/c3d4e5f6-a7b8-9012-cdef-345678901234-1.mp3",
"imageUrl": "https://cdn2.apiframe.ai/audio/c3d4e5f6-a7b8-9012-cdef-345678901234-1.jpeg",
"title": "Midnight Frequencies",
"tags": "lo-fi, hip hop, chill",
"duration": 127.3
}
]
}Udio generates 2 tracks per request. See Result format for field details.
Keep the id of a track you like: it is what you pass to the follow-up
endpoints below, and what style_ref.song / voice.song accept.
Follow-up actions
POST /v2/music/udio/action
Acts on one song of a completed udio job, selected with index (1–2) or
trackId (from the parent's result.tracks[].id) — exactly one of the two.
| Action | Description |
|---|---|
extend | Adds up to 32 seconds to the song. placement chooses where (after-add-section, after-add-outro, before-add-section, before-add-intro) and output_length how much. One extension per call — extend the result again to keep going |
remix | Generates the song again. remix_strength (0.1–1.0, default 0.5) sets how far from the original it lands: low keeps almost everything, high keeps almost nothing. crop_range ([start, end] in seconds) limits it to part of the track |
Anything you leave out is inherited from the source song, so a bare request just
continues (or re-rolls) what is already there. The optional prompt, lyrics,
lyrics_prompt, lyrics_type, negative_tags, model, seed, bpm,
voice, style_ref, the four strengths and generation_quality override it.
Both return a fresh pair of songs that can themselves be acted on.
Two things Udio cannot do: extend a song generated with a udio130-* model
(override model with a udio32-* one, or remix instead), and extend a song
longer than 15 minutes. Both return an error before any credits are spent.
# Add a 16-second outro to the first song of a completed job
curl -X POST https://api.apiframe.ai/v2/music/udio/action \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"action": "extend",
"parentJobId": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"index": 1,
"placement": "after-add-outro",
"output_length": 16
}'Writing lyrics
POST /v2/music/udio/lyrics
Has Udio write lyrics without generating any audio — it settles in seconds, and
lets you read and edit the words before paying to render them. Feed them back as
udioParams.lyrics.
| Parameter | Type | Default | Description |
|---|---|---|---|
prompt | string | — | Required. What the song is about (max 2,000 characters) |
duration | integer | — | Length of the song the lyrics are for: 32, 65, 97 or 130. This matters: the same prompt yields roughly 8 lines at 32s and 30 at 130s |
lyrics | string | — | Existing lyrics for Udio to rewrite, instead of starting from nothing |
result is { "lyrics": "…", "instrumental": false }, plus "tempo" when Udio
reports one. There are no tracks.
curl -X POST https://api.apiframe.ai/v2/music/udio/lyrics \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "leaving a small town at dawn, hopeful but homesick",
"duration": 97
}'Uploading your own audio
POST /v2/music/udio/upload
Puts audio from a public URL onto Udio's storage so later generations can use
it. result is { "url": "…" }, and that URL is the handle — pass it as
style_ref.file to generate in its style, or voice.file to sing with its
voice, on as many generations as you like.
| Parameter | Type | Description |
|---|---|---|
audioUrl | string | Required. Publicly reachable audio URL. Upload your own file to POST /v2/uploads first if you need one |
Uploads are fingerprinted, and are refused when the copyright check does not clear.
# 1. Upload
curl -X POST https://api.apiframe.ai/v2/music/udio/upload \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"audioUrl": "https://example.com/my-demo.mp3"}'
# 2. Generate in its style, using the `url` from the result
curl -X POST https://api.apiframe.ai/v2/music/generate \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"model": "udio",
"udioParams": {
"duration": 65,
"style_ref": { "file": "https://storage.udio.com/uploads/…", "similarity": 5 }
}
}'Code examples
Text-to-music (description mode)
curl -X POST https://api.apiframe.ai/v2/music/generate \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "chill lo-fi hip hop beat with jazzy piano chords and vinyl crackle",
"model": "udio",
"udioParams": {
"lyrics_type": "generate",
"duration": 65
}
}'import requests
response = requests.post(
"https://api.apiframe.ai/v2/music/generate",
headers={
"X-API-Key": "afk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"prompt": "chill lo-fi hip hop beat with jazzy piano chords and vinyl crackle",
"model": "udio",
"udioParams": {
"lyrics_type": "generate",
"duration": 65,
},
},
)
print(response.json())const response = await fetch("https://api.apiframe.ai/v2/music/generate", {
method: "POST",
headers: {
"X-API-Key": "afk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "chill lo-fi hip hop beat with jazzy piano chords and vinyl crackle",
model: "udio",
udioParams: {
lyrics_type: "generate",
duration: 65,
},
}),
});
console.log(await response.json());body := `{
"prompt": "chill lo-fi hip hop beat with jazzy piano chords and vinyl crackle",
"model": "udio",
"udioParams": {"lyrics_type": "generate", "duration": 65}
}`
req, _ := http.NewRequest("POST", "https://api.apiframe.ai/v2/music/generate",
strings.NewReader(body))
req.Header.Set("X-API-Key", "afk_your_api_key_here")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)Custom lyrics mode
Put the lyrics in udioParams.lyrics and use prompt to describe the music:
curl -X POST https://api.apiframe.ai/v2/music/generate \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "warm jazz-pop with brushed drums and an upright bass",
"model": "udio",
"udioParams": {
"lyrics": "[Verse]\nIn the gentle evening air,\nWhispers dance without a care.\n[Chorus]\nHold me close, never let go",
"title": "Evening Stars",
"duration": 97
}
}'lyrics_type: "user" with the lyrics in prompt and the description in
udioParams.style also works, and is the older form of the same request.
Generating from a style
With style_ref set, prompt is optional — the reference carries the intent:
curl -X POST https://api.apiframe.ai/v2/music/generate \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"model": "udio",
"udioParams": {
"duration": 65,
"style_ref": {
"song": "2e7d9c1a-5f3b-4e6d-8a0c-1b4f7e2d9a5c",
"similarity": 5
}
}
}'Instrumental mode
curl -X POST https://api.apiframe.ai/v2/music/generate \
-H "X-API-Key: afk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "ambient electronic soundscape with evolving pads and gentle arpeggios",
"model": "udio",
"udioParams": {
"lyrics_type": "instrumental",
"negative_tags": "vocals, singing",
"duration": 130
}
}'Try it
/v2/music/generateTry it