ApiframeDocs
Follow-up ActionsUdio

Extend

Add up to 32 seconds before or after a song from a completed Udio job.

POST /v2/music/udio/actionaction: "extend"

Equivalent to Udio's Extend button: adds a new section to one of the parent job's songs, either before it or after it. The result is a fresh pair of songs — same shape as a generation — and each can be extended again, which is how you build a track longer than Udio's 130-second maximum.

One extension per call, and at most 32 seconds of new audio, because Udio renders one 32-second sample at a time. Chaining is deliberate: you hear each section before deciding what comes next.

Select the song with index (1 or 2) or with the trackId from the parent's result.tracks[].id — exactly one of the two.

Request

ParameterTypeRequiredDescription
parentJobIdstring (uuid)YesID of the completed udio job to act on
actionstringYes"extend"
indexnumberOne of index/trackIdWhich of the parent's songs to extend: 1 or 2
trackIdstringOne of index/trackIdSong ID from the parent's result.tracks[].id
placementstringNoWhere the new section goes: "after-add-section", "after-add-outro", "before-add-section", "before-add-intro"
output_lengthnumberNoSeconds of new audio, 1–32. Defaults to Udio's own choice
promptstringNoDescription of the new material (max 5,000 characters). Defaults to the source song's
lyricsstringNoYour own words for the new section (max 5,000 characters)
lyrics_promptstringNoWhat the new section should be about — Udio writes the lyrics from it (max 2,000 characters)
lyrics_typestringNo"generate", "user" or "instrumental"
negative_tagsstringNoStyles to avoid (max 500 characters)
modelstringNoModel version for the extension. Defaults to the source song's
voiceobjectNoA reference voice
style_refobjectNoA reference style
bpmnumberNoTarget tempo, 60–200
seedintegerNoSeed for reproducibility
prompt_strengthnumberNo0–1
lyrics_strengthnumberNo0–1
clarity_strengthnumberNo0–1
generation_qualitynumberNo0–1
webhookUrlstringNoHTTPS URL that receives a JSON POST when the job reaches a subscribed event — see Webhooks for payload formats
webhookEventsstring[]NoEvents to be notified about: "progress", "completed", "failed". Defaults to ["completed", "failed"] when webhookUrl is set

Everything you leave out is inherited from the source song, so a bare request just continues what is already there.

Two limits are Udio's, not ours, and both are rejected before any credits are deducted:

  • Songs generated with a udio130-* model cannot be extended. Override model with a udio32-* one, or remix instead (400).
  • Songs longer than 15 minutes cannot be extended (409).

Credits

3 credits per extend — one 32-second sample, whatever the length of the source song.

Example result

Once the job is COMPLETED, the result object on GET /v2/jobs/:id contains a fresh pair of songs:

{
  "tracks": [
    {
      "id": "2c9a7e51-8f4b-4d3a-b6e0-1f5d8c2a9b74",
      "audioUrl": "https://cdn2.apiframe.ai/audio/d4e5f6a7-b8c9-0123-def4-567890123456-0.mp3",
      "imageUrl": "https://cdn2.apiframe.ai/audio/d4e5f6a7-b8c9-0123-def4-567890123456-0.jpeg",
      "title": "Midnight Frequencies",
      "tags": "lo-fi, hip hop, chill",
      "duration": 48.6
    },
    {
      "id": "7e3b1d96-2a5c-4f8e-9c07-4b6a1e8d3f25",
      "audioUrl": "https://cdn2.apiframe.ai/audio/d4e5f6a7-b8c9-0123-def4-567890123456-1.mp3",
      "imageUrl": "https://cdn2.apiframe.ai/audio/d4e5f6a7-b8c9-0123-def4-567890123456-1.jpeg",
      "title": "Midnight Frequencies",
      "tags": "lo-fi, hip hop, chill",
      "duration": 48.2
    }
  ]
}

Each of these songs can be the parent of another extend.

Code examples

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 '{
    "parentJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "action": "extend",
    "index": 1
  }'
import requests

response = requests.post(
    "https://api.apiframe.ai/v2/music/udio/action",
    headers={
        "X-API-Key": "afk_your_api_key_here",
        "Content-Type": "application/json",
    },
    json={
        "parentJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "action": "extend",
        "index": 1,
    },
)
print(response.json())
const response = await fetch("https://api.apiframe.ai/v2/music/udio/action", {
  method: "POST",
  headers: {
    "X-API-Key": "afk_your_api_key_here",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    parentJobId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    action: "extend",
    index: 1,
  }),
});
console.log(await response.json());
body := `{
  "parentJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "action": "extend",
  "index": 1
}`
req, _ := http.NewRequest("POST", "https://api.apiframe.ai/v2/music/udio/action",
    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)

Add a 16-second outro with your own lyrics

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 '{
    "parentJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "action": "extend",
    "trackId": "8b2f64d1-3c5e-4a7f-9d2b-6e1a0c4f8b3d",
    "placement": "after-add-outro",
    "output_length": 16,
    "lyrics": "[Outro]\nCity fades into the dawn"
  }'

Add an intro instead

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 '{
    "parentJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "action": "extend",
    "index": 1,
    "placement": "before-add-intro",
    "output_length": 8,
    "lyrics_type": "instrumental"
  }'

Try it

POST/v2/music/udio/actionTry it

On this page