> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mountsea.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Model

> Create custom music models trained on your own audio

Create a personalized music model trained on your own audio. The process requires three steps: **prepare** (create session) → **upload** (upload training audio, at least 6) → **create** (submit for training).

## Workflow

```
 ① customModel/prepare
      │  Select account, create session
      │  Returns: { sessionId }
      │
      ▼
 ② customModel/upload  ×N (at least 6)
      │  Upload audio files one by one (async)
      │  Returns: { taskId }
      │  Poll: GET /suno/v2/status?taskId=xxx
      │  Result contains clip info (including id)
      │
      │  Can upload in parallel, each polled independently
      │
      ▼
 ③ customModel/create
      │  Submit clipIds + model name → Start training
      │  Returns: { taskId } (taskId = sessionId)
      │  Poll: GET /suno/v2/status?taskId=xxx
      │  Training takes ~2-3 minutes
      │  Result contains custom model details (including model ID)
      ▼
    Done → Use model ID in /generate
```

***

## Step 1: Prepare — Create Session

Create a session and bind an account. All subsequent upload and create calls use the same account automatically.

### Request

```
POST /suno/v2/customModel/prepare
```

No request body required.

### Response

```json theme={null}
{
  "sessionId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
```

<Info>
  The `sessionId` is the unique identifier for the entire workflow. Keep it for subsequent steps.
</Info>

See [Prepare API Reference →](/api-reference/suno/customModelPrepare)

***

## Step 2: Upload — Upload Training Audio

Upload audio files one at a time. Each call is async and returns a `taskId`. You need to poll until the task succeeds to get the `clipId` from the result.

**Minimum 6 audio files** are required before you can proceed to the create step. Multiple uploads can run in parallel.

### Request

```
POST /suno/v2/customModel/upload
```

| Field       | Type          | Required | Description                     |
| ----------- | ------------- | -------- | ------------------------------- |
| `sessionId` | string (UUID) | Yes      | Session ID from prepare step    |
| `audioUrl`  | string (URL)  | Yes      | Publicly downloadable audio URL |

### Task Result

On success, the `result` contains clip info including an `id` field — this is the `clipId` needed for the create step.

See [Upload API Reference →](/api-reference/suno/customModelUpload)

***

## Step 3: Create — Submit for Training

After collecting at least 6 clipIds from successful uploads, submit the training request. This costs **100 credits** and takes approximately **2-3 minutes**.

### Request

```
POST /suno/v2/customModel/create
```

| Field       | Type          | Required | Description                               |
| ----------- | ------------- | -------- | ----------------------------------------- |
| `sessionId` | string (UUID) | Yes      | Session ID from prepare step              |
| `clipIds`   | string\[]     | Yes      | Clip IDs from upload results (at least 6) |
| `name`      | string        | Yes      | Custom model name                         |

<Info>
  The returned `taskId` equals the `sessionId`. You can poll using either one.
</Info>

On success, the `result` contains the custom model details. The model ID format is `chirp-custom:<uuid>`.

See [Create API Reference →](/api-reference/suno/customModelCreate)

***

## Using Your Custom Model

Once training is complete, use the model ID directly in the [Generate](/api-reference/suno/generate) endpoint:

```json theme={null}
{
  "task": "create",
  "model": "chirp-custom:3b285ad7-b09c-48fe-99e6-ec8a109f0650",
  "prompt": "[Verse]\nA catchy pop melody...",
  "tags": "Pop, Upbeat"
}
```

The system automatically uses the same account that created the custom model for generation.

***

## Complete Example

<CodeGroup>
  ```javascript Node.js theme={null}
  const API_BASE = 'https://api.mountsea.ai';
  const headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-api-key'
  };

  async function pollTask(taskId) {
    while (true) {
      const res = await fetch(`${API_BASE}/suno/v2/status?taskId=${taskId}`, { headers });
      const task = await res.json();
      if (task.status === 'success') return task.data;
      if (task.status === 'failed') throw new Error(task.failReason);
      await new Promise(r => setTimeout(r, 3000));
    }
  }

  // Step 1: Prepare session
  const prepareRes = await fetch(`${API_BASE}/suno/v2/customModel/prepare`, {
    method: 'POST',
    headers
  });
  const { sessionId } = await prepareRes.json();
  console.log('Session ID:', sessionId);

  // Step 2: Upload audio files (at least 6, can run in parallel)
  const audioUrls = [
    'https://example.com/song1.mp3',
    'https://example.com/song2.mp3',
    'https://example.com/song3.mp3',
    'https://example.com/song4.mp3',
    'https://example.com/song5.mp3',
    'https://example.com/song6.mp3',
  ];

  const uploadPromises = audioUrls.map(async (audioUrl) => {
    const res = await fetch(`${API_BASE}/suno/v2/customModel/upload`, {
      method: 'POST',
      headers,
      body: JSON.stringify({ sessionId, audioUrl })
    });
    const { taskId } = await res.json();
    const result = await pollTask(taskId);
    return result.id; // clipId
  });

  const clipIds = await Promise.all(uploadPromises);
  console.log('Uploaded clips:', clipIds);

  // Step 3: Create custom model
  const createRes = await fetch(`${API_BASE}/suno/v2/customModel/create`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      sessionId,
      clipIds,
      name: 'My Custom Model'
    })
  });
  const { taskId: createTaskId } = await createRes.json();
  const model = await pollTask(createTaskId);
  console.log('Custom model created:', model);
  // Use model.id (e.g. "chirp-custom:xxx") in /generate
  ```

  ```python Python theme={null}
  import requests
  import time
  from concurrent.futures import ThreadPoolExecutor

  API_BASE = 'https://api.mountsea.ai'
  headers = {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer your-api-key'
  }

  def poll_task(task_id):
      while True:
          res = requests.get(f'{API_BASE}/suno/v2/status', params={'taskId': task_id}, headers=headers)
          task = res.json()
          if task['status'] == 'success':
              return task['data']
          if task['status'] == 'failed':
              raise Exception(task.get('failReason', 'Unknown error'))
          time.sleep(3)

  def upload_audio(session_id, audio_url):
      res = requests.post(f'{API_BASE}/suno/v2/customModel/upload', headers=headers, json={
          'sessionId': session_id,
          'audioUrl': audio_url
      })
      result = poll_task(res.json()['taskId'])
      return result['id']

  # Step 1: Prepare
  prepare_res = requests.post(f'{API_BASE}/suno/v2/customModel/prepare', headers=headers)
  session_id = prepare_res.json()['sessionId']

  # Step 2: Upload (parallel)
  audio_urls = [f'https://example.com/song{i}.mp3' for i in range(1, 7)]
  with ThreadPoolExecutor(max_workers=6) as executor:
      clip_ids = list(executor.map(lambda url: upload_audio(session_id, url), audio_urls))

  # Step 3: Create
  create_res = requests.post(f'{API_BASE}/suno/v2/customModel/create', headers=headers, json={
      'sessionId': session_id,
      'clipIds': clip_ids,
      'name': 'My Custom Model'
  })
  model = poll_task(create_res.json()['taskId'])
  print(f"Custom model created: {model}")
  ```
</CodeGroup>

## Failure Recovery

* **Upload fails**: Retry with the same `sessionId` — no need to re-prepare.
* **Create fails** (e.g. parameter error): Retry with the same `sessionId` and corrected parameters. The system automatically resets the session state.
* **Prepare** rarely fails since it only creates a session and binds an account.

## Important Notes

<Warning>
  The `create` step costs **100 credits**. Make sure all uploaded clips are correct before submitting.
</Warning>

* **Same account guarantee**: prepare / upload / create automatically use the same Suno account — no manual specification needed.
* **Credits**: The create step costs 100 credits. Upload steps also have minor credit costs based on task pricing configuration.
* **ClipId validation**: All `clipIds` in the create request must come from uploads within the current session, otherwise a 400 error is returned.
* **Parallel uploads**: Multiple upload requests can be sent concurrently without conflicts.
* **Model limits**: Each custom account has a maximum number of models it can create, configured by the administrator.
