跳到正文
DEV Community· Germey·· 2 小時前AI 評分56

Suno Projects API 多軌音樂工作流程實用指南

A Practical Guide to Building Multi-Track Music Workflows with the Suno Projects API

AI 導讀

Suno Studio Projects API 可用於建立多軌音樂工作流程,流程包括建立專案、加入來源音訊、渲染混音、生成音軌候選及提交選定結果。修改專案、生成候選或匯出時須使用最新的 version_id;非同步操作則要保存 task_id,完成後再讀取結果。指南亦提醒,請求超時後應查詢原任務或重用相同 Idempotency-Key,避免盲目重新提交。

正文

If you have ever tried to turn a single generated audio clip into an editable arrangement, you have probably hit the same wall: one file is easy to play, but hard to iterate on.

The Suno Studio Projects API gives you a project-level workflow for that next step: create a project, add source material, render a reference mix, generate new track candidates, and commit the one that fits.

What you can do

The core endpoint is:

POST /suno/projects
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Idempotency-Key: <a new UUID for each write operation>

The API is action-based. Every request sends an action field, and the same endpoint handles project operations such as:

  • create — create an empty project
  • retrieve — read the latest project state
  • save — save the complete project state
  • upload — create an asset from an HTTPS audio URL
  • add_track — place completed audio into the project
  • render — export the current audible mix and get a reference audio_id
  • generate_track — generate new track candidates
  • replace_section — generate candidates for a partial replacement
  • commit_candidate — commit a selected candidate into the project
  • remove_track — remove a track

Most write operations require an Idempotency-Key header. The exception is retrieve. That matters in real integrations: if a paid generation times out or the client disconnects, you should query the original task or reuse the same idempotency key instead of blindly submitting a different request.

How the workflow fits together

A project workflow is mostly about passing the right IDs forward.

The create response gives you data.id, which becomes the project id for later calls. After the first save or any modifying operation, you also get a version_id. Use the latest version_id when modifying, generating candidates, or exporting.

When you upload audio, the completed task returns response.data.candidate.audio_id. That is the ID you use with add_track; do not pass the original audio URL into add_track.

For new generated parts, there are two more IDs to track:

  • render_audio_id comes from the final render task response as response.data.audio_id.
  • operation_id and candidate_id come from the final generation task and are used when committing a candidate.

One subtle but important detail: time can mean two different things. start_seconds and end_seconds refer to seconds inside the source audio. start_beats and end_beats refer to beats on the project timeline. The default state.timing.bps is 2, so a 41-second clip starting at beat 0 ends at beat 82 by default.

Step 1: create and save a project

Start with a small project object. A newly created project has no version_id, so the first save can omit it.

BASE_URL="https://api.acedata.cloud"

curl -X POST "$BASE_URL/suno/projects" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "action": "create",
    "title": "Demo arrangement"
  }'

The response includes a project id and an initial state, typically with empty tracks and timing.bps set to 2.

Then save the complete state:

{
  "action": "save",
  "id": "af0e104a-2a4c-40e0-9c70-7614566824a6",
  "title": "Demo arrangement",
  "state": {
    "tracks": [],
    "timing": {
      "bps": 2
    }
  }
}

After this point, keep the returned version_id. Old versions can be rejected, so do not cache a project state and edit it much later without retrieving the latest copy first.

Step 2: upload audio and add it as a track

To bring source material into a project, upload from an HTTPS URL that is publicly accessible and that you have the right to use.

{
  "action": "upload",
  "id": "af0e104a-2a4c-40e0-9c70-7614566824a6",
  "version_id": "8f0c62fb-304f-420e-9707-426e8b64b5e3",
  "audio_url": "<HTTPS_AUDIO_URL>",
  "async": true
}

Async operations return a task_id first. That only means the task was accepted. Poll the task endpoint until the task has finished_at and response.success is true:

POST /suno/tasks
Content-Type: application/json

{"action":"retrieve","id":"<task_id>"}

When upload completes, take candidate.audio_id and add it to the project:

{
  "action": "add_track",
  "id": "af0e104a-2a4c-40e0-9c70-7614566824a6",
  "version_id": "8f0c62fb-304f-420e-9707-426e8b64b5e3",
  "audio_id": "b21be571-bfe4-47c1-b59c-2abc55c6f9c3",
  "name": "Source demo",
  "start_beats": 0
}

Optional fields such as color, gain, start_beats, and end_beats let you control placement and volume. The default color is #7251F7, and gain defaults to 1.

Step 3: generate a new track candidate

For generate_track, first save an empty target track in the complete project state. At minimum, the target track needs an id, type: "audio", and clips: []. A fuller empty track can include takeLanes, mute, solo, amplitude, instrument, and color.

Next, render the current audible mix:

{
  "action": "render",
  "id": "af0e104a-2a4c-40e0-9c70-7614566824a6",
  "version_id": "cb0a82c9-aa5b-48cc-9395-0528675fc18d",
  "title": "Demo source mix",
  "lyrics": "[Instrumental]",
  "async": true
}

When the render task succeeds, use its audio_id as render_audio_id in generate_track:

{
  "action": "generate_track",
  "id": "af0e104a-2a4c-40e0-9c70-7614566824a6",
  "version_id": "cb0a82c9-aa5b-48cc-9395-0528675fc18d",
  "source_audio_id": "b21be571-bfe4-47c1-b59c-2abc55c6f9c3",
  "render_audio_id": "41038732-4dc4-40bf-b00d-2728d99bc26e",
  "model": "chirp-v5",
  "start_seconds": 12,
  "end_seconds": 20,
  "stem_control_tags": "add Piano",
  "batch_size": 2,
  "instrumental": true,
  "tags": "warm piano, cinematic"
}

Supported model names include chirp-v3-5, chirp-v4, chirp-v4-5, chirp-v4-5-plus, chirp-v5, chirp-v5-5, chirp-v6, chirp-v6-wild, and chirp-v6-mini. Availability for a specific combination is ultimately reflected in the final task state.

Step 4: commit the candidate you actually want

Generation does not modify the project immediately. It gives you candidates. After listening or inspecting results, use commit_candidate with the returned operation_id, selected candidate_id, and target track_id.

That separation is useful: your app can present several takes to a user, let them choose one, and only then update the project version.

In practice, I would wrap this workflow in a small state machine:

  1. Store project_id and latest version_id.
  2. Store every async task_id before polling.
  3. On timeout, retrieve the task instead of resubmitting.
  4. After any successful modifying operation, replace the stored version_id.
  5. Before editing state, retrieve the full project and preserve unknown fields.

That last point prevents accidental data loss. save expects the complete project state, not a partial patch.

Closing thoughts

The useful mental model is: treat /suno/projects less like a single generation endpoint and more like an arrangement workspace. You create durable project state, attach source material, ask for candidates, and commit only the result that belongs in the mix.

If you are building a tool where users iterate on stems, intros, backing tracks, or replacements, this project-based flow is much easier to reason about than repeatedly juggling standalone audio files.

Full reference: https://platform.acedata.cloud/documents/suno-projects-integration

來源:DEV Community · dev.to