ApiframeDocs
Music Generation

Udio

Text-to-music and lyrics-to-music generation using Udio, with extend, remix, style references and lyric writing.

POST /v2/music/generatemodel: "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

ParameterTypeDefaultDescription
udioParams.durationinteger32Song length in seconds: 32, 65, 97 or 130. Sets the price
udioParams.lyrics_typestring"generate"Who writes the words: "generate" (Udio does), "user" (you do — prompt is the lyrics), "instrumental" (nobody sings)
udioParams.lyricsstringYour own lyrics (max 5,000 characters). Implies lyrics_type: "user" and leaves prompt free to describe the music
udioParams.lyrics_promptstringWhat 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.stylestringMusic style / genre hint (max 1,000 characters). Used as the description when lyrics_type is "user"
udioParams.style_refobjectGenerate in the style of a reference instead of from a description. When set, prompt becomes optional
udioParams.voiceobjectA reference voice to sing it
udioParams.modelstring"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.titlestringTrack title (max 80 characters)
udioParams.negative_tagsstringStyles to avoid, comma-separated (max 500 characters)
udioParams.bpmnumberTarget tempo, 60–200
udioParams.manual_modebooleanfalseSend prompt verbatim, without Udio's prompt optimizer
udioParams.prompt_strengthnumber0–1. How closely to follow the description
udioParams.lyrics_strengthnumber0–1. How closely to follow the lyrics
udioParams.clarity_strengthnumber0–1. Favours clean, intelligible output
udioParams.generation_qualitynumber0–1. Trades render time for quality
udioParams.seedintegerSeed for reproducibility

References

udioParams.style_ref and udioParams.voice both point at one thing, named in exactly one of four ways:

FieldDescription
songA song ID from an earlier job's result.tracks[].id
fileAudio you uploaded
nameAn entry in Udio's library, by name
idAn 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

VariantCredits
d329
d6517
d9726
d13035
extend9
remix-d329
remix-d6517
remix-d9726
remix-d13035
write_lyrics1
upload_audio1

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.

ActionDescription
extendAdds 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
remixGenerates 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.

ParameterTypeDefaultDescription
promptstringRequired. What the song is about (max 2,000 characters)
durationintegerLength 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
lyricsstringExisting 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.

ParameterTypeDescription
audioUrlstringRequired. 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

POST/v2/music/generateTry it

On this page