> ## 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.

# Init + Complete

> Free Voice Persona path — same result as Clone Voice

Create a **Voice Persona** with two **free** calls: `init` → `complete`, one `taskId`.

This is the free Voice Persona path. [Clone Voice](/api-reference/suno/voices) (`/voices`) is the **paid** one-step wrapper of the same pipeline. Compare in [Persona overview](/api-reference/suno/persona-introduction).

On `/generate`, always pass `persona.is_voice: true` and keep the **same** Suno account.

## Workflow

```
 User's voice audio
      │
      ▼
 ① voicePersona/init
      │  Upload voice → Extract vocals → Return verification phrase
      │
      │  Returns: { taskId }
      │  Poll: GET /suno/v2/status?taskId=xxx
      │  Wait for status == "awaiting"
      │  data: { phrase_text, ... }
      │
      ▼
 User reads phrase_text aloud and records (within 30s timeout)
      │
      ▼
 ② voicePersona/complete (same taskId)
      │  Upload verification recording → Voice verification → Create Persona
      │
      │  Poll same taskId: GET /suno/v2/status?taskId=xxx
      │  Wait for status == "success"
      │  data: persona details
      ▼
    Done → Use persona in /generate
```

### Task Status Flow

```
queued → running → awaiting → running → success
                      │                    │
                      │                    └── complete failed → failed
                      └── User timeout → failed (VP_USER_TIMEOUT)
```

<Warning>
  After the task reaches `awaiting` status, you must call `complete` within **30 seconds** (default). If the timeout is exceeded, the task will fail with `VP_USER_TIMEOUT` and you'll need to restart from `init`.
</Warning>

***

## Step 1: Init — Upload Voice & Get Verification Phrase

Upload the user's voice audio. The system extracts vocals and returns a verification phrase that the user must read aloud.

<Info>
  This is an async task. Poll [Get Task Status](/api-reference/suno/task) with the returned `taskId`. Wait for status to become **`awaiting`** (not `success`).
</Info>

### Request

```
POST /suno/v2/voicePersona/init
```

| Field             | Type         | Required | Description                                                                     |
| ----------------- | ------------ | -------- | ------------------------------------------------------------------------------- |
| `voice_audio_url` | string (URL) | Yes      | Publicly downloadable URL of the voice audio (WAV/MP3)                          |
| `language`        | string       | Yes      | Verification phrase language: `zh` `en` `ja` `ko` `es` `fr` `de` `pt` `ru` `hi` |
| `vocal_start_s`   | number       | No       | Vocal extraction start time (seconds), default: 0                               |
| `vocal_end_s`     | number       | No       | Vocal extraction end time (seconds), default: auto-detected                     |

### Polling Result (status: awaiting)

When the task reaches `awaiting` status, `data` contains:

| Field                | Description                                                         |
| -------------------- | ------------------------------------------------------------------- |
| `phrase_text`        | **Verification phrase text** — user must read this aloud and record |
| `phrase_id`          | Verification phrase ID (internal)                                   |
| `vox_audio_id`       | Extracted vocal audio ID (internal)                                 |
| `voice_recording_id` | Recording ID (internal)                                             |
| `vocal_start_s`      | Vocal start time (seconds)                                          |
| `vocal_end_s`        | Vocal end time (seconds)                                            |

<Tip>
  Only `phrase_text` is needed by the user. All other fields are used internally by the system — you do **not** need to pass them to the `complete` step.
</Tip>

See [Init API Reference →](/api-reference/suno/voicePersonaInit)

***

## Step 2: Complete — Upload Verification Recording & Create Persona

After the user reads `phrase_text` aloud and records it, upload the verification recording **using the same `taskId`** to complete voice verification and create the persona.

<Info>
  Uses the **same `taskId`** from init. After calling complete, continue polling the same taskId until status becomes `success`.
</Info>

### Request

```
POST /suno/v2/voicePersona/complete
```

| Field                    | Type          | Required | Description                                          |
| ------------------------ | ------------- | -------- | ---------------------------------------------------- |
| `taskId`                 | string (UUID) | Yes      | The taskId from init (same task)                     |
| `verification_audio_url` | string (URL)  | Yes      | User's verification recording URL (WAV/MP3)          |
| `name`                   | string        | Yes      | Persona name                                         |
| `description`            | string        | No       | Persona description                                  |
| `is_public`              | boolean       | No       | Whether public (default: false)                      |
| `image_s3_id`            | string        | No       | Cover image (base64), auto-generated if not provided |

<Tip>
  No intermediate data (`vox_audio_id`, `phrase_id`, etc.) is needed — the system reads them automatically from the init phase.
</Tip>

See [Complete API Reference →](/api-reference/suno/voicePersonaComplete)

***

## 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, targetStatus = 'success') {
    while (true) {
      const res = await fetch(`${API_BASE}/suno/v2/status?taskId=${taskId}`, { headers });
      const task = await res.json();
      if (task.status === targetStatus) return task.data;
      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: Init — upload voice and get verification phrase
  const initRes = await fetch(`${API_BASE}/suno/v2/voicePersona/init`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      voice_audio_url: 'https://example.com/my-voice.wav',
      language: 'zh'
    })
  });
  const { taskId } = await initRes.json();

  // Poll until status is "awaiting"
  const initData = await pollTask(taskId, 'awaiting');
  console.log('Please read aloud:', initData.phrase_text);

  // → User records themselves reading the phrase ...

  // Step 2: Complete — upload verification recording (same taskId)
  await fetch(`${API_BASE}/suno/v2/voicePersona/complete`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      taskId,
      verification_audio_url: 'https://example.com/verification.wav',
      name: 'My Voice',
      description: '我的专属声音'
    })
  });

  // Poll the SAME taskId until status is "success"
  const persona = await pollTask(taskId, 'success');
  console.log('Voice Persona created:', persona);
  ```

  ```python Python theme={null}
  import requests
  import time

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

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

  # Step 1: Init
  init_res = requests.post(f'{API_BASE}/suno/v2/voicePersona/init', headers=headers, json={
      'voice_audio_url': 'https://example.com/my-voice.wav',
      'language': 'zh'
  })
  task_id = init_res.json()['taskId']

  # Poll until "awaiting"
  init_data = poll_task(task_id, target_status='awaiting')
  print(f"Please read aloud: {init_data['phrase_text']}")

  # ... user records the phrase ...

  # Step 2: Complete (same taskId)
  requests.post(f'{API_BASE}/suno/v2/voicePersona/complete', headers=headers, json={
      'taskId': task_id,
      'verification_audio_url': 'https://example.com/verification.wav',
      'name': 'My Voice',
      'description': '我的专属声音'
  })

  # Poll the SAME taskId until "success"
  persona = poll_task(task_id, target_status='success')
  print(f"Voice Persona created: {persona}")
  ```

  ```bash cURL theme={null}
  # 1. Init
  curl -X POST "https://api.mountsea.ai/suno/v2/voicePersona/init" \
    -H "Authorization: Bearer your-api-key" \
    -H "Content-Type: application/json" \
    -d '{"voice_audio_url":"https://example.com/voice.wav","language":"zh"}'
  # → {"taskId":"abc-123"}

  # 2. Poll until status == "awaiting"
  curl "https://api.mountsea.ai/suno/v2/status?taskId=abc-123" \
    -H "Authorization: Bearer your-api-key"
  # → {"status":"awaiting","data":{"phrase_text":"风吹过山谷带来了远方的消息",...}}

  # 3. Complete (same taskId, after user records the phrase)
  curl -X POST "https://api.mountsea.ai/suno/v2/voicePersona/complete" \
    -H "Authorization: Bearer your-api-key" \
    -H "Content-Type: application/json" \
    -d '{"taskId":"abc-123","verification_audio_url":"https://example.com/verify.wav","name":"My Voice"}'
  # → {"taskId":"abc-123"}

  # 4. Poll same taskId until status == "success"
  curl "https://api.mountsea.ai/suno/v2/status?taskId=abc-123" \
    -H "Authorization: Bearer your-api-key"
  # → {"status":"success","data":{"id":"persona-xxx","name":"My Voice",...}}
  ```
</CodeGroup>

***

## Error Codes

| Code | Error                                 | Description                                           |
| ---- | ------------------------------------- | ----------------------------------------------------- |
| 400  | VP\_TASK\_NOT\_FOUND                  | taskId does not exist or is not a Voice Persona task  |
| 400  | VP\_INVALID\_STATUS                   | Task status is not `awaiting`, cannot call complete   |
| 408  | VP\_USER\_TIMEOUT                     | Timeout waiting for complete after init (default 30s) |
| 409  | VP\_SESSION\_EXPIRED                  | Verification session expired, restart from init       |
| 500  | VP\_LOCK\_EXPIRED                     | Internal lock expired (retry)                         |
| 503  | VP\_NO\_DEDICATED\_ACCOUNT\_AVAILABLE | No dedicated account available                        |
| 503  | VP\_ALL\_ACCOUNTS\_BUSY               | All account queues are full, retry later              |
| 504  | VP\_ORPHAN\_TIMEOUT                   | Task queuing timeout                                  |

## Important Notes

<Warning>
  The verification recording must clearly contain the full `phrase_text` content. Incomplete or unclear recordings will cause voice verification to fail.
</Warning>

* **Single taskId lifecycle**: Init and complete use the same `taskId` — poll one task throughout the entire flow.
* **`awaiting` status**: After init completes, the task status is `awaiting` (not `success`). The `data` field contains `phrase_text` for the user to read.
* **30s time limit**: You must call `complete` within 30 seconds after the task reaches `awaiting`. Exceeding this causes `VP_USER_TIMEOUT`.
* **Simplified parameters**: `complete` only needs `taskId` + verification recording URL + persona info. All intermediate data is auto-filled by the system.
* **Same account guarantee**: Both phases automatically use the same Suno account.
* **Language selection**: `language` determines the verification phrase language. Match the language of the original voice audio for best results.
* **Processing time**: Init takes \~20-60s (includes vocal extraction); Complete takes \~10-30s (includes voice verification).
* **Concurrency safety**: The system serializes Voice Persona operations per account — concurrent requests from different users won't interfere.
