# Voice clone
> Clone a reusable voice from an authorized audio sample.

Clone a reusable voice from an authorized audio sample.

## Primary agent path

Use the Universal Skill with the MCP tool `beatra.voices.clone`. The tool is
billable, consent-gated, and returns an asynchronous task.

1. Confirm with the user that they hold the rights to this voice. Set
   `consent_attested: true` only after that explicit confirmation.
2. Upload the local sample with `beatra.assets.upload` and use its artifact ID.
   Each model's card lists its sample limits (the `sample_*` fields); a clean
   recording of one speaker works best. For ElevenLabs the sample must be 10
   seconds to 5 minutes long and at most 20 MiB, in WAV, MP3, M4A, AAC, or
   OGG; anything outside these limits is rejected before charge.
3. Create one opaque `client_request_id` and submit the final arguments once.
4. Poll the returned task with `beatra.tasks.get`; the terminal response
   returns the new `voice_id`.

## AI guide

AI integration guide: https://docs.beatra.cn/llms/voices-clone.md

## Tool arguments

```json
{
  "sample": { "type": "artifact", "artifact_id": "artifact_01JX..." },
  "display_name": "Brand narration - female",
  "consent_attested": true,
  "client_request_id": "voice-clone-opaque-1"
}
```

`sample` accepts an artifact, HTTPS URL, or data URI. `display_name` is
required (≤255 characters). A request without `consent_attested: true` is
rejected.

## Optional quality prompt

For a higher-similarity clone, add `prompt`: a short excerpt (shorter than 8
seconds) of the same voice plus its verbatim transcript. The engine aligns the excerpt
character for character to sharpen the cloned timbre — useful when the main
sample is long or slightly noisy.

```json
{
  "sample": { "type": "artifact", "artifact_id": "artifact_01JX..." },
  "prompt": {
    "sample": { "type": "artifact", "artifact_id": "artifact_prompt..." },
    "text": "Verbatim transcript of the prompt excerpt."
  },
  "display_name": "Brand narration - female",
  "consent_attested": true,
  "client_request_id": "voice-clone-opaque-1"
}
```

`prompt.sample` accepts the same reference kinds as `sample`; `prompt.text`
(≤2,000 characters) must match the excerpt exactly and end with a punctuation
mark. An excerpt measured at 8 seconds or longer, or a transcript without
ending punctuation, is rejected before billing. Omit `prompt` to clone from
the main sample only — the prompt adds no extra charge.

## Models, controls, and cost

Omit `model` (or use `auto`) unless the user names one. `beatra.models.list`
with `capability: "voice_clone"` is the current source for selectable models,
accepted sample kinds, and the fixed price.

With `auto` (and every model whose card sets
`constraints.automatic_formal_activation: true`), voice cloning has one fixed
charge when the activated voice is created successfully. Success means Beatra
already ran a short formal synthesis to activate the clone — that activation
is included in the charge; later speech synthesis is billed separately. A
failed clone or activation does not retain the charge.

## Models that need a separate activation

Some models are explicit-only: they are not in the default list, `auto` never
picks them, and `beatra.models.list` lists them only when called with
`include_activation_required: true` (REST: `GET /v1/catalog/capabilities/voice_clone?include_activation_required=true`).
Their cards set `constraints.automatic_formal_activation: false`. That listing
rule does not tell you whether activation is needed. `doubao-voice-clone-2.0`
below clones in two steps: cloning makes a free preview, and a separate paid
activation makes the voice usable for speech. The ElevenLabs clone is listed the
same way but is one-step and ready on success (see the ElevenLabs section).
Use an explicit-only model only when the user asks for it by name.

`doubao-voice-clone-2.0`:

- `language` is required and must be the language spoken in the sample: `zh`,
  `en`, `ja`, `ko`, `es`, `es-MX`, `pt`, `pt-BR`, `id`, `ms`, `th`, `vi`,
  `fil`, `de`, `fr`, `ru` or `ar`. A missing or unlisted value is rejected
  with 422 `unsupported_option`.
- The sample must be WAV, MP3, OGG, M4A or AAC audio of at most 10 MiB, or it
  is rejected with 422 `voice_sample_rejected` before anything is charged.
  14–30 seconds of one person speaking works best; by default only the first
  25 seconds are used. `prompt` is ignored with an `option_ignored` warning.
- Cloning and the preview are free. The task succeeds with
  `output.status: "pending_activation"`, a `preview` (a fixed sentence in the
  chosen language read in the cloned voice), `activation.price_credits`,
  `activation.quote` (the activation quote, see below), and `expires_at`. Play
  the preview to the user.
- A waiting voice cannot be used for speech: synthesis returns 422
  `voice_activation_required`. It can be renamed but not made the default.
  If it is not activated by `expires_at` (normally 7 days after cloning), it
  becomes `expired` (422 `voice_preview_expired`) and the voice must be cloned
  again.
- Limits per account: 10 voices waiting for activation (409
  `voice_limit_reached`; activate or delete one), 20 clones per UTC day
  (429 `rate_limited`, `details.reason: voice_training_daily_limit`), and one
  clone in progress at a time (429 `rate_limited`,
  `details.reason: voice_training_in_progress`; retry when it finishes). While
  cloning is busy for everyone the reason is `voice_training_busy`; retry after
  about 30 seconds.

Optional `model_options.doubao` tunes the training. Values are checked before
anything is charged; an unknown key or a value out of range is rejected with
422 `unsupported_option`.

| Key | Type and range | Effect |
| --- | --- | --- |
| `sample_text` | string, at most 1,000 characters | The words spoken in the sample. A sample whose speech differs too much is rejected (`voice_sample_rejected`, `details.reason: sample_text_mismatch`). Checked for `zh`, `en`, `ja`, `ko`, `es`, `es-MX`, `pt`, `pt-BR`, `id`, `fr` and `ru` only; ignored with an `option_ignored` warning for the other languages. |
| `enable_audio_denoise` | boolean (default `false`) | Remove background noise before training. |
| `enable_audio_denoise_with_snr` | boolean | Remove noise only when the sample's signal-to-noise ratio is below `denoise_max_snr_thresh`. |
| `denoise_max_snr_thresh` | integer, 1–99 (default 50) | The signal-to-noise ratio below which noise is removed. |
| `reject_min_snr_thresh` | number, greater than 0 and less than 100 (default 5) | Reject a sample whose signal-to-noise ratio is lower. |
| `voice_clone_denoise_model_id` | `SpeechInpaintingV2` (default) or `VocalDiffusionV2VocalDiffusionV2_44k` | The noise-removal model. |
| `voice_clone_enable_mss` | boolean | Separate the voice from background music before training. |
| `enable_crop_by_asr` | boolean | Pick the training segment by speech recognition instead of taking the first 25 seconds. |
| `enable_check_prompt_text_quality` | boolean | Check the quality of `sample_text` before training. |
| `enable_check_audio_quality` | boolean | Check the sample's audio quality before training. |
| `disable_volume_normalization` | boolean | Keep the sample's recorded volume. |

```json
{
  "sample": { "type": "artifact", "artifact_id": "artifact_01JX..." },
  "display_name": "My voice",
  "model": "doubao-voice-clone-2.0",
  "language": "zh",
  "model_options": { "doubao": { "enable_audio_denoise": true } },
  "consent_attested": true,
  "client_request_id": "voice-clone-opaque-2"
}
```

## Activating a voice

`beatra.voices.activate` makes a waiting voice usable for speech. The clone
result already carries the quote, so one call activates:

1. The clone result's `activation.quote` carries `price_credits`,
   `balance_credits`, `sufficient_balance`, the `preview`, `terms` in `zh`,
   `en` and `ja`, `terms_version`, a `confirmation_token`, and
   `token_expires_at` (24 hours).
2. Tell the user the price and the terms and get their explicit consent. Never
   activate automatically.
3. Call it with `voice_id`, `confirmation_token` and `confirm_credits` (the
   quoted `price_credits`). The price is charged once and the call returns an
   asynchronous task; poll it with `beatra.tasks.get`. When it succeeds the
   voice is `ready`; its output carries the voice, with a final preview when
   one could be made.

Called without `confirmation_token` (the token is gone or older than 24
hours), it returns a new quote and charges nothing.

```json
{
  "voice_id": "voice_01JX...",
  "confirmation_token": "<from activation.quote>",
  "confirm_credits": 100000,
  "client_request_id": "voice-activate-opaque-1"
}
```

- An expired token, a price that changed, or a `confirm_credits` that differs
  from the quote returns 422 `price_confirmation_required` with a new quote in
  `details.quote`; nothing is charged. Show the new quote and ask again.
- A failed activation is refunded automatically; a successful one is not
  refunded. An activated voice cannot take a new recording: to change it,
  clone a new voice and activate that one.
- Limits per account: one activation in progress at a time (429
  `rate_limited`, `details.reason: voice_activation_in_progress`) and 3
  activations per UTC day. A fourth returns 429
  `voice_activation_daily_limit`: nothing is charged, and the user is asked to
  contact support.
- When activation cannot run, the error is `internal_error`, nothing is
  charged (or the charge is fully refunded), and the message asks the user to
  contact support with the `request_id`.
- Calling it for a voice that is already `ready`, including every voice cloned
  with `auto` and every preset voice, charges nothing and changes nothing.
- While an activation runs, the voice cannot be deleted (409 `conflict`,
  `details.reason: voice_operation_in_progress`).

The price is in the clone card (`pricing`, `billing_basis:
successful_activated_voice`) and in every quote. Deleting an activated voice
cannot be undone and the activation charge is not refunded; speech tasks
already submitted for it still finish.

An activated Doubao clone speaks with `doubao-seed-tts-2.0`, long text
included, in the language it was trained in. A `language` it does not read
(for a Chinese clone, anything other than Chinese, English or `auto`) gets an
`option_ignored` warning that names the language the voice was cloned from,
and a Chinese clone refuses it on the long-text path (send parts of up to 3,000
characters, or clone a voice from a recording in that language); the text
itself is not checked. Subtitles, pauses, and readings follow the rules of a
preset voice in that language. `emotion`, `direction`, and `previous_text` are
sent to the model as for the voices that follow them; how they come through
depends on the Doubao model.

## ElevenLabs: explicit, ready-on-success cloning

`elevenlabs-voice-clone` is open to every account but explicit-only: pass
`model: "elevenlabs-voice-clone"`. It is not in the default voice clone list and
`auto` never picks it. Find it with `beatra.models.list` and
`include_activation_required: true` (REST: `GET /v1/catalog/capabilities/voice_clone?include_activation_required=true`),
with `GET /v1/catalog/models/elevenlabs-voice-clone`, or in the full
`/v1/models` list. It matches the listing conditions of the two-step models
above, but it is one-step: the voice is ready as soon as the task succeeds.

A successful clone costs **7,270 credits once** and is immediately `ready` for
`elevenlabs-v4-turbo` and `elevenlabs-v4`. The cloned voice works only with
those two models and speaks the 10 languages they support (`en`, `zh`, `ja`,
`ko`, `es`, `pt`, `ar`, `hi`, `fr`, `it`). The clone task creates the voice
only: it does not synthesize speech, generate a preview, or require activation.
A later speech request is separately quoted and charged. Calling activate on an
already ready voice is a free no-op. `prompt` and `model_options` are ignored
with a warning.

**Sample limits.** These are limits, not recommendations; a sample outside them
is rejected before any charge:

- Format: WAV, MP3, M4A, AAC, or OGG. Another format returns 422
  `unsupported_option`.
- Length: at least 10 seconds and at most 5 minutes. Size: at most 20 MiB. A
  duration or size outside the range returns 422 `invalid_request`.
- Use an authorized recording of one speaker. 1–2 minutes is recommended; more
  than 3 minutes does not improve the clone.

If the engine itself rejects the sample after the task is accepted, the task
fails with `voice_sample_rejected` and is refunded in full. The message says
whether the sample was too short, too long, unreadable, or too large, or whether the voice needs additional verification (this also fails with `voice_sample_rejected` and is refunded).

**Daily limit.** At most 3 ElevenLabs clones per account per UTC day; the day
resets at 08:00 Beijing time (00:00 UTC). A clone counts when it is in
progress, succeeded, or failed after reaching the engine. A sample rejected by
the local checks above, or a clone canceled before upload, does not count. The
fourth returns 429 `rate_limited` with `details.reason:
voice_creation_daily_limit`, `retry_after_seconds`, and, over REST, a `Retry-After`
response header with the same seconds (MCP has no headers); nothing is charged. Omit `model` to use the default voice clone at the
same price. Replaying the same request does not create another clone.

**Temporary errors.** Nothing is charged for either:

- 503 `model_unavailable` with `details.reason: creation_temporarily_unavailable`:
  new clones with this model are paused. Omit `model` to use the default voice
  clone at the same price, or try again after `available_at` when it is given.
- 503 `model_unavailable` with `details.reason: voice_temporarily_busy`:
  voice cloning is busy; retry after `retry_after_seconds` (about a minute).

**Free preview.** When you explicitly select the free preview in the account or
desktop interface, Beatra synthesizes a fixed sentence in your cloned voice and
saves it for later playback. The sentence is chosen by the clone's `language`
(one of the 10 languages, otherwise English). The first preview is free, is
cached and reused, and counts toward the two-task ElevenLabs speech limit (see
[text to speech](https://docs.beatra.cn/en/docs/capabilities/speech/text-to-speech)). If the voice must
first be restored, the preview may return 503 `model_unavailable` (see `details.reason` and
`retry_after_seconds`; for a restore in progress, `voice_temporarily_busy` with
30 seconds); the restore continues in the background and the next try succeeds.
No preview is generated while two ElevenLabs speech tasks are already running;
it simply returns no preview. A failed preview
does not change the clone's result or charge. Custom text or different
synthesis settings require a separately confirmed speech quote.

**Your sample and the voice.** Clones remain owned by the account under the
same `voice_id`. The uploaded sample is kept as a private copy so the voice can
be restored internally when needed; restoring may add time and does not promise
identical waveforms after model changes. The sample is deleted, together with
the voice at the engine and any cached preview, when you delete the voice or
close the account. Deletion cannot be undone and does not refund the clone;
speech tasks already accepted still finish.

A speech request on a cloned voice can fail in these ways. A temporarily busy
voice (503 `voice_temporarily_busy`) or one that cannot be restored right now
(503 `voice_temporarily_unavailable`, with `available_at` when known) is not
charged and does not affect other voices. A voice that can no longer be
restored from its saved sample returns 422 `voice_unavailable`: this is
permanent, so do not retry; contact support. That synthesis is not charged, and
the original clone fee is not refunded. A failed accepted speech request
refunds only that speech charge.

## Task status and recovery

`queued` and `running` are not failures. Keep polling the same `task_id`; never
submit a replacement because work is still running. On a lost create response,
retry the identical arguments with the same `client_request_id`. If any input
changes, use a new ID. The returned `voice_id` works directly as the `voice`
field in [text to speech](https://docs.beatra.cn/en/docs/capabilities/speech/text-to-speech) once the
voice is `ready` (a voice that needs activation, after it is activated), stays
valid long-term, and can be inspected or deleted in
[voices](https://docs.beatra.cn/en/docs/capabilities/speech/voices).

## REST API

Direct protocol integrations may use `POST /v1/voices`,
`POST /v1/voices/{voice_id}/activate`, and the shared task endpoints. Follow
the generated API operations:
[clone](https://docs.beatra.cn/en/docs/api-reference/operations/voices/clone_voice_v1_voices_post) ·
[activate](https://docs.beatra.cn/en/docs/api-reference/operations/voices/activate_voice_v1_voices__voice_id__activate_post).
Skill + MCP is the recommended integration; use REST for custom, non-agent
applications.
