ElevenLabs - Music Composition Plan
Get the Composition Plan First
- composition_plan
Text-to-music is a slot machine. You type "melancholy lo-fi with a sax break at 90 seconds" and you get whatever the model felt like - and when it's not what you wanted, you have no lever except rewriting the prompt and burning another credit. This node pulls one lever out of the machine: it asks the model for the plan first, as structured JSON you can read, edit, and reuse across every take you generate.
What it actually does
It's a single API call to /v1/music/plan, and the only output is composition_plan - a STRING containing the JSON the service built from your prompt. That string is meant to be wired into the composition_plan input of the pack's ElevenLabs Music Generation node, where it overrides the prompt entirely. So the shape of the workflow is: describe the song → inspect the plan → generate the audio.
Why bother with the intermediate step? Three reasons. You can read the structure before you spend a generation on it. You can hand-edit it - the JSON is a string, run it through a text node, fix the section you hate, and only then render. And a plan is the one mode where a seed actually does something, so a good plan plus a fixed seed is your route to the same song twice.
The three inputs
api_key and prompt are required. The prompt is a plain description of the song - that's your whole creative control at this stage.
model picks between music_v1 (the default), music_v2 and music_v2_5. Newer is not automatically what you want here: v2.5 only exists on accounts that have it, and if yours doesn't, you'll get an API error rather than a fallback.
duration_seconds is the one with a real gotcha. Leave it at 0 and the model picks a length on its own. Set it to anything else and it must be between 3 and 600, and the node validates that locally - feed it 700 and you get a Python ValueError from the node itself rather than a round trip. That's the author being decent; the message even tells you the range. The field is a float and gets converted to milliseconds, so the slider's whole-second steps are a UI convenience rather than a hard floor.
What to do with the plan once you have it
Feed composition_plan into the Music node. Two things to know about that handoff:
- The plan carries its own length. Whatever you asked for here is what the song will be - the Music node's
duration_secondsis ignored in plan mode. - If you edited the JSON by hand and broke it, the Music node raises
composition_plan is not valid JSON: <the parse error>. It's a strict parse, no repair, no partial acceptance.
The plan is also replayable. Same plan, same render settings, another song - you're not re-rolling the structure, only the performance. For a game jam or an episode of something with a recurring theme, keep the plan in a text file and version it; it's a far better artefact than a prompt string.
Installing
Manager → search "API Toolkit" → install → restart. Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/IxMxAMAR/ComfyUI-API-Toolkit
cd ComfyUI-API-Toolkit
pip install -r requirements.txt
For ElevenLabs-only, pip install requests soundfile scipy covers the dependencies; there are no model weights, because nothing runs locally. Environment variable ELEVENLABS_API_KEY works as a fallback for the key field.
Honest calibration
If your actual goal is "some background music, I don't much care what", skip this node and prompt the Music node directly. Planning is the move when you can describe the song precisely enough to have opinions about its structure - intro, verse, chorus, drop, outro - or when you need the same song structure more than once. Local options do exist for this job; ACE-Step in particular is the open answer to Suno and it's fine on a 4GB card, with instrumentals being its strong suit. Where the hosted route still wins is vocals and lyric intelligibility, which is the same division of labour the rest of the audio stack has.
And the standard API-node arithmetic applies: every call is metered, your prompt goes to a server you don't control, and a plan isn't free just because it contains no audio.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| api_key | STRING | — | |
| prompt | STRING | Text description of the song to plan. | |
| modelopt | COMBO | music_v1 | 3 options: music_v1, music_v2, music_v2_5 |
| duration_secondsopt | FLOAT | 00–600 | Length of the plan in seconds (3 - 600). 0 = let the model choose. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| composition_plan | STRING | — |