Suno Projects (Ace Data Cloud)
The 10-Action Node That Turns a Song Into Something You Keep Editing
- status
- task_id
- media_urls_json
- first_media_url
- result_json
- trace_id
If you've used the friendly half of this pack you know the shape: Suno Submit Music takes a prompt, hands you a task ID, and two finished tracks fall out the other end. Great - until one is almost right and you have no way to say "keep the drums, redo the second verse."
Suno Projects (Ace Data Cloud) is the other half. It's a single node that speaks Suno's Projects API - the part of the service where a song is an editable thing with versions, tracks, and candidates instead of a sealed pair of MP3s. Ten actions: create, retrieve, save, upload, add_track, generate_track, replace_section, commit_candidate, remove_track, render. That's not a node, that's a small DAW with no timeline.
Who this is actually for
Two kinds of people. The ones who get a song that's 80% right and want to fix the rest instead of rolling the dice again - replace_section and generate_track are the whole reason to care. And the ones who need the music regenerated on demand under a specific moment in a video.
Keep the tradeoff honest: our KB's read is that Suno still wins clean vocals, while local ACE-Step wins on instrumentals and cost - under 4GB of VRAM, and it takes LoRAs. For instrumental beds you don't need an API key at all.
How it works
Mechanically it's the least magical node in the pack, which is good news. The pack copies Suno's published Dify plugin API contract verbatim - endpoint, JSON schema, enums - and validates your payload against it before anything goes over the network. Your request is one POST https://api.acedata.cloud/suno/projects, and a rejected payload was very likely never sent or billed.
The node is generated at import time from that contract, which is why it looks like 26 text boxes bolted to a dropdown. It's an output node, so it runs even unwired and prints its own three status lines on the node body.
The inputs that matter
action is the only input you must understand. model (nine chirp-* IDs) is only sent for the two actions that need it - generate_track and replace_section - and those require it, so leaving it on the (from JSON/default) sentinel fails validation. That sentinel omits action too, and the endpoint's own default is retrieve, not create. Leave both alone on a fresh node and you're doing a read.
The rest are per-action, and the contract is strict about it - each action is a separate oneOf branch with additionalProperties: false. Send id alongside action: create and it's rejected. The pairings you'll actually need:
create→titleretrieve→idsave→id,state(a JSON object pasted as text;version_idandtitleoptional)- everything else wants
id+version_id, plus:upload→audio_url;add_track→audio_id,start_beats,end_beats,gain;generate_track→source_audio_id,render_audio_id,stem_control_tags,model,start_seconds,end_seconds;replace_section→source_audio_id,model,start_seconds,end_seconds;commit_candidate→operation_id,candidate_id,track_id;remove_track→track_id;render→title
Two typing traps: every box is a string widget, but numbers get coerced - start_beats: "12" is fine, "a bit" is a must be a number. And fixed must be literal true or false. parameters_json takes a raw JSON object; non-empty named fields override it.
Outputs, and the async catch
Six strings come out: status, task_id, media_urls_json, first_media_url, result_json, trace_id. None is an AUDIO - to hear anything, wire first_media_url into Suno Load Audio's audio_url input for a real ComfyUI AUDIO.
The catch: five of the ten actions (upload, generate_track, replace_section, commit_candidate, render) are asynchronous. You get status: pending and a task_id, and you poll that with Suno Retrieve Task - don't rerun the work to check on it. result_json is where you fish out the audio_id, track_id, and version_id the next action wants. This is a multi-run workflow, not a one-click toy.
Install
Manager → Custom Nodes → search Suno → publisher acedatacloud, package Suno by Ace Data Cloud (Registry ID ace-suno), install, restart. The pack's own test log notes the Registry did not list it at test time, so if Manager comes up empty, clone it:
cd ComfyUI/custom_nodes
git clone https://github.com/AceDataCloud/SunoComfyUI.git
cd SunoComfyUI && python -m pip install -r requirements.txt
requirements.txt installs requests and jsonschema - the README's "only adds requests" is out of date, and jsonschema is what validates your payloads. No GPU, no local weights. Then put the key where ComfyUI can see it and restart:
export ACEDATACLOUD_API_KEY='paste-your-key-here'
python main.py
One key from the Ace console with Suno access. If you restrict API paths on that key, add /suno/projects - the README's list of three paths only covers the guided nodes.
Where people get burned
The idempotency_key box is a red herring: it only does something on endpoints that declare an idempotency header, and this one doesn't. Don't lean on it to make retries safe - non-read-only requests are sent exactly once, never retried, so a dropped connection mid-render means reading the Ace request history by trace_id before trying again.
And be realistic about the vendor: zero threads in our Reddit corpus mention "Ace Data Cloud", against 761 for Suno - the community is still on Suno's own site. You're early here, so check the price before a batch of renders.
Inputs (29)
| Name | Type | Default | Description |
|---|---|---|---|
| parameters_json | STRING | {} | — |
| model | COMBO | (from JSON/default) | 10 options: (from JSON/default), chirp-v3-5, chirp-v4, chirp-v4-5, chirp-v4-5-plus, chirp-v5, +4 |
| action | COMBO | (from JSON/default) | 11 options: (from JSON/default), create, retrieve, save, upload, add_track, +5 |
| title | STRING | — | |
| id | STRING | — | |
| version_id | STRING | — | |
| state | STRING | — | |
| audio_url | STRING | — | |
| callback_url | STRING | — | |
| audio_id | STRING | — | |
| name | STRING | — | |
| start_beats | STRING | — | |
| end_beats | STRING | — | |
| gain | STRING | — | |
| source_audio_id | STRING | — | |
| tags | STRING | — | |
| prompt | STRING | — | |
| start_seconds | STRING | — | |
| end_seconds | STRING | — | |
| render_audio_id | STRING | — | |
| stem_control_tags | STRING | — | |
| batch_size | STRING | — | |
| replacement_lyrics | STRING | — | |
| fixed | STRING | — | |
| operation_id | STRING | — | |
| candidate_id | STRING | — | |
| track_id | STRING | — | |
| lyrics | STRING | — | |
| idempotency_key | STRING | — |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| status | STRING | — |
| task_id | STRING | — |
| media_urls_json | STRING | — |
| first_media_url | STRING | — |
| result_json | STRING | — |
| trace_id | STRING | — |