Edit a song
June 3, 2026 (August 12, 2026)
Table of contents
Edit an existing clip — the operation field selects one of six edit kinds, each taking a clip (an encoded clip asset ID from a previous generation or GET /music).
operation is required — one of:
operation | What it does | Required params | Optional params |
|---|---|---|---|
effect | Apply one audio effect | effect + that effect’s scalar param(s) | — |
extend | Add new music to the end, or from a point | instruction | extend_s, extend_from_s |
replace | Regenerate a time section | instruction, mask_start_s, mask_end_s | — |
cover | Restyle the whole song (a Lyria cover) | — | instruction, strength, model |
remix | Re-sing with edited lyrics | lyrics | prompt |
stems | Separate into 4 stem clips (drums/bass/vocals/other) | — | — |
https://api.useapi.net/v1/flowmusic/music/edit
Request Headers
Authorization: Bearer {API token}
Content-Type: application/json
# Alternatively you can use multipart/form-data
# Content-Type: multipart/form-data
API tokenis required, see Setup useapi.net for details.
Request Body
Every operation accepts these common fields (there is no email — the clip already identifies its account, and the edit runs there):
clipis required, the encoded clip asset ID to edit.seedis optional, an integer ≥ 0 — pins the result for reproducibility.titleis optional, a title for the result clip.modelis optional, the music model used to re-render. Supported values:lyria-3.5andlyria-3-pro(default). It is sent with the operations that re-synthesise audio —cover,extend,replace, andremix.effectandstemsaccept it but their output is unaffected, because those are signal processing and stem separation with no music model in the loop. Omitting it keeps the behaviour that existed before the parameter was added.modeis optional,sync(default — blocks until ready) orasync(returns201with ajobid; poll GET /jobs/jobid). Insyncyour connection must stay open until ready — if it drops the result is lost, so preferasyncon mobile, flaky networks, or short-timeout platforms. Ignored bystems, which is always sync.replyUrlis optional, a webhook URL — the job record is POSTed to it when the edit completes or fails. Ignored bystems.replyRefis optional, a custom reference string echoed back in the webhook.
Plus the chosen operation’s own fields, below.
operation: effect
effect is one of Trim, Fade, Gain, Reverb, Pan, Equalizer. Each effect reads only its own flat scalar params (sending a param for a different effect is ignored):
Gain—gain_db(−30 … 30).Reverb—mix,room_size(0 … 1 each).Pan—pan(−1 left … 1 right).Equalizer—bass_db,mid_db,treble_db(−12 … 12 each).Fade—fade_in_s,fade_out_s(≥ 0, at least one > 0).Trim—start_s,end_s(end_s>start_s, ≤ duration).
{
"operation": "effect",
"clip": "user:[email protected]:...",
"effect": "Reverb",
"mix": 0.4,
"room_size": 0.7
}
operation: extend
{
"operation": "extend",
"clip": "user:1234-...-clip:...",
"instruction": "add an instrumental outro",
"extend_s": 30
}
instructionis required, what to add.extend_sis optional, seconds to add, 1–300 (default 150).extend_from_sis optional, the point to extend from (default = end of clip).
operation: replace
{
"operation": "replace",
"clip": "user:1234-...-clip:...",
"instruction": "softer piano in this section",
"mask_start_s": 0,
"mask_end_s": 8
}
instructionis required, how to regenerate the section.mask_start_sis required, the section start (seconds).mask_end_sis required, the section end (seconds), >mask_start_s, ≤ duration.
operation: cover
Restyle the entire song. instruction is optional (a free-text style direction); strength is the cover-strength slider.
{
"operation": "cover",
"clip": "user:1234-...-clip:...",
"instruction": "lo-fi chillhop reinterpretation",
"strength": 0.7
}
instructionis optional, a free-text style direction.strengthis optional, 0 … 1 (default 1).
operation: remix
Re-sing the song with edited lyrics. By default it reuses the source song’s sound prompt; override with prompt. The edited lyrics round-trip into the result clip’s lyrics.
{
"operation": "remix",
"clip": "user:1234-...-clip:...",
"lyrics": "[Verse 1]\nNeon rain on the avenue\n[Chorus]\nWe rise again",
"prompt": "dreamy synthwave, 100 bpm"
}
lyricsis required, the edited lyrics,[Verse]/[Chorus]-tagged.promptis optional, a sound-prompt override (defaults to the source clip’s).
operation: stems
Separate the song into its individual tracks. Flow Music runs the split server-side and creates 4 new clips — drums, bass, vocals, other — each a normal clip with its own id and a public audio_url/wav_url. Only clip is needed.
{
"operation": "stems",
"clip": "user:1234-...-clip:..."
}
stemsis synchronous — the request blocks ~15–60 s while the split runs, then returns all four stems in one reply (it ignoresmode/replyUrl/replyRef). Re-running on an already-split clip returns its stems immediately.- Download any stem with GET /music/download (mp3) or its
audio_url/wav_url.
Its response differs from the other edits — it’s a flat manifest of the stem clips, not a job record:
{
"email": "[email protected]",
"operation": "stems",
"source_clip": "user:1234-...-clip:...",
"status": "completed",
"clips": [
{
"stem_type": "drums",
"clip": "user:1234-...-clip:...",
"title": "Song - drums",
"duration_s": 173.0,
"audio_url": "https://storage.googleapis.com/...1a2b3c4d.m4a",
"wav_url": "https://storage.googleapis.com/...1a2b3c4d.wav",
"image_url": null
}
]
}
(four entries — drums, bass, vocals, other).
Responses
Same job-record shape as POST /music — operation echoes the requested edit kind. (operation: stems is the exception — it returns the flat stem manifest shown above, not a job record.)
-
Sync mode (default) — the edit is rendered and the full record is returned inline.
{ "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic", "email": "[email protected]", "operation": "cover", "status": "completed", "created_at": "2026-06-01T18:40:42.412Z", "completed_at": "2026-06-01T18:41:37.432Z", "duration_ms": 55020, "clips": [ { "clip": "user:[email protected]:c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f", "title": "Morning Sun (Cover)", "duration_s": 171.02, "lyrics": "[Verse 1]\nCity lights blur in the rain\n[Chorus]\nAnd I will wait for the morning sun", "seed": 123456, "lyrics_timing": [ [0.0, 2.4], [2.4, 5.1] ], "created_at": "2026-06-01T18:41:30.118Z", "audio_url": "https://storage.googleapis.com/...c3d4e5f6.m4a", "wav_url": "https://storage.googleapis.com/...c3d4e5f6.wav", "image_url": "https://storage.googleapis.com/...d4e5f6a7.jpg" } ], "request": { "operation": "cover", "clip": "user:[email protected]:...", "strength": 0.7 } } -
Async mode (
"mode": "async") — the edit is queued and returned immediately aspending. Poll GET /jobs/jobiduntilstatusiscompletedorfailed.{ "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic", "email": "[email protected]", "operation": "remix", "status": "pending", "created_at": "2026-06-01T18:40:42.412Z", "request": { "operation": "remix", "clip": "user:1234-...-clip:...", "lyrics": "[Verse 1]\n...", "mode": "async" } } -
Validation error — an unknown
operation, a missing required field for the chosen operation (e.g.replacewithoutmask_start_s/mask_end_s, oreffectwithouteffect), or aclipthat isn’t a clip-type asset ID.{ "error": "instruction required for operation=extend", "code": 400 } -
Invalid API token.
{ "error": "Unauthorized", "code": 401 } -
The targeted Flow Music account has insufficient credits to complete the edit. Top up its credit balance (or target a funded account with
email), then retry.{ "error": "recipes/create failed (402): {\"detail\":\"User has insufficient credits\"}", "code": 402 } -
The
clip’s account isn’t configured under your useapi.net account, or the source clip no longer exists on Flow Music.{ "error": "source clip not found on FlowMusic", "code": 404 } -
The edit produced no audio (e.g. a content-moderation refusal — a terminal
status: "failed"record), or the source clip can’t be edited (an uploaded clip has noconversation_id).{ "jobid": "job:aaaabbbb-cccc-4ddd-8eee-ffff99990000-user:[email protected]:flowmusic", "email": "[email protected]", "operation": "cover", "status": "failed", "created_at": "2026-06-01T18:40:42.412Z", "completed_at": "2026-06-01T18:41:10.512Z", "error": { "code": "moderation_reject", "message": "the model declined to generate audio for this edit" }, "request": { "operation": "cover", "clip": "user:1234-...-clip:..." } } -
Passed through from Flow Music when the
clip’s account is already running too many concurrent jobs — retry once one finishes.{ "error": "producer/tool-call failed (429): {\"detail\":\"Too Many Requests\"}", "code": 429 } -
596 Account Error
The
clip’s account is in an error state and can’t be used — re-add it via POST /accounts.{ "error": "Account [email protected] in error state: refresh token rejected", "code": 596 }
Model
Same job-record shape as POST /music, plus a top-level operation. The request echoes the edit body you submitted. (operation: stems returns a flat manifest of the 4 stem clips instead — see operation: stems.)
-
{ jobid: string // job:<uuid>-user:<id>-<email>-bot:flowmusic email: string operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' status: 'completed' | 'pending' | 'failed' created_at: string // ISO 8601 timestamp completed_at?: string // present when terminal duration_ms?: number // wall-clock render time clips: Array<{ clip: string // encoded clip asset id — use with /music/download and /music/edit title: string | null duration_s: number | null lyrics: string | null // [Verse]/[Chorus]-tagged; "[Instrumental]" for instrumentals seed: number | null lyrics_timing: Array<[number, number]> | null // timing markers, [start, end] seconds (vocal clips) created_at: string // ISO 8601 timestamp audio_url: string // m4a download URL wav_url: string // wav download URL image_url: string | null // auto-generated artwork URL }> request: { // the edit body you submitted, echoed back verbatim operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' clip: string model?: 'lyria-3.5' | 'lyria-3-pro' // cover/extend/replace/remix — inert on effect/stems seed?: number // common — pins the result title?: string // common mode?: 'sync' | 'async' // common replyUrl?: string // common — webhook replyRef?: string // common — webhook reference effect?: 'Trim' | 'Fade' | 'Gain' | 'Reverb' | 'Pan' | 'Equalizer' // effect gain_db?: number // effect=Gain (-30..30) mix?: number // effect=Reverb (0..1) room_size?: number // effect=Reverb (0..1) pan?: number // effect=Pan (-1..1) bass_db?: number // effect=Equalizer (-12..12) mid_db?: number // effect=Equalizer (-12..12) treble_db?: number // effect=Equalizer (-12..12) fade_in_s?: number // effect=Fade fade_out_s?: number // effect=Fade start_s?: number // effect=Trim end_s?: number // effect=Trim instruction?: string // extend / replace / cover extend_s?: number // extend (1..300) extend_from_s?: number // extend mask_start_s?: number // replace mask_end_s?: number // replace strength?: number // cover (0..1) lyrics?: string // remix prompt?: string // remix } } -
{ jobid: string // job:<uuid>-user:<id>-<email>-bot:flowmusic email: string operation: 'effect' | 'extend' | 'replace' | 'cover' | 'remix' | 'stems' status: 'pending' created_at: string // ISO 8601 timestamp request: { } // the edit body you submitted — same shape as the 200 (Completed) model above }
Examples
-
# Cover (restyle) — instruction optional curl -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_TOKEN" \ -X POST "https://api.useapi.net/v1/flowmusic/music/edit" \ -d '{ "operation": "cover", "clip": "user:[email protected]:...", "strength": 0.7 }' -
const response = await fetch('https://api.useapi.net/v1/flowmusic/music/edit', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_API_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ operation: 'remix', clip: 'user:[email protected]:...', lyrics: '[Verse 1]\nNeon rain on the avenue\n[Chorus]\nWe rise again' }) }); console.log(await response.json()); -
import requests response = requests.post( 'https://api.useapi.net/v1/flowmusic/music/edit', headers={'Authorization': 'Bearer YOUR_API_TOKEN'}, json={'operation': 'effect', 'clip': 'user:[email protected]:...', 'effect': 'Gain', 'gain_db': 6} ) print(response.status_code, response.json())