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

# Cloning a voice

> Clone a voice from an audio sample.

Voice cloning is a two-step flow: upload one sample to generate a preview, then save the preview as a reusable voice. Adjust `text` and `instructions` on the preview. Speaker consent is required; see [voice consent](https://breezeblue.ai/en/legal/voice-consent).

## Recording requirements

* Upload exactly one sample file.
* Use a single speaker with no background music or noise.
* Use MP3 or WAV.
* Maximum duration: 30 seconds.
* Maximum file size: 5 MB.

## Step 1: Create a preview

```python theme={null}
import os
from pathlib import Path

from breeze_blue import BreezeBlue

client = BreezeBlue(api_key=os.environ["BREEZE_API_KEY"])

preview = client.voices.create_clone_preview(
    name="My narrator",
    file=Path("narrator.wav"),
    text="Welcome to the preview.",
    instructions="Stay close to the reference tone.",
)

print(preview["generated_voice_id"])
```

```typescript theme={null}
import { readFile } from "node:fs/promises";
import { BreezeBlueClient } from "@breeze.blue/sdk";

const client = new BreezeBlueClient({
  apiKey: process.env.BREEZE_API_KEY!,
});

const preview = await client.voices.createClonePreview({
  name: "My narrator",
  file: {
    data: await readFile("narrator.wav"),
    filename: "narrator.wav",
    contentType: "audio/wav",
  },
  text: "Welcome to the preview.",
  instructions: "Stay close to the reference tone.",
});

console.log(preview.generatedVoiceId);
```

```bash theme={null}
curl -X POST "https://api.breeze.blue/v1/voice-previews/clone" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  -F "name=My narrator" \
  -F "files=@./narrator.wav" \
  -F "text=Welcome to the preview." \
  -F "instructions=Stay close to the reference tone."
```

The response contains a `generated_voice_id`, not a saved `voice_id`. `text` defaults to the Breeze clone script when omitted or empty. `instructions` defaults to none. SDKs also accept `files` with exactly one item.

## Step 2: Stream the preview

```python theme={null}
import os
from pathlib import Path

from breeze_blue import BreezeBlue, save

client = BreezeBlue(api_key=os.environ["BREEZE_API_KEY"])

preview_audio = client.voices.stream_preview(
    generated_voice_id="gvi_01hpreview",
)
save(preview_audio, Path("clone-preview.mp3"))
```

```typescript theme={null}
import { BreezeBlueClient } from "@breeze.blue/sdk";
import { save } from "@breeze.blue/sdk/node";

const client = new BreezeBlueClient({
  apiKey: process.env.BREEZE_API_KEY!,
});

const previewAudio = await client.voices.streamPreview("gvi_01hpreview");
await save(previewAudio, "clone-preview.mp3");
```

```bash theme={null}
curl "https://api.breeze.blue/v1/voice-previews/$GENERATED_VOICE_ID/stream" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  --output clone-preview.mp3
```

## Step 3: Save the preview as a voice

```python theme={null}
import os

from breeze_blue import BreezeBlue

client = BreezeBlue(api_key=os.environ["BREEZE_API_KEY"])

voice = client.voices.save_preview(
    generated_voice_id="gvi_01hpreview",
    voice_name="My narrator",
)

print(voice["voice_id"])
```

```typescript theme={null}
import { BreezeBlueClient } from "@breeze.blue/sdk";

const client = new BreezeBlueClient({
  apiKey: process.env.BREEZE_API_KEY!,
});

const voice = await client.voices.savePreview({
  generatedVoiceId: "gvi_01hpreview",
  voiceName: "My narrator",
});

console.log(voice.voiceId);
```

```bash theme={null}
curl -X POST "https://api.breeze.blue/v1/voice-previews/gvi_01hpreview/save" \
  -H "xi-api-key: $BREEZE_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "voice_name": "My narrator"
  }'
```

Saving consumes a voice slot. Subsequent `POST /v1/text-to-speech/{voice_id}` calls use the original uploaded sample and transcript, not the preview audio.

## Editing or deleting a saved voice

* Update labels and the description with `PATCH /v1/voices/{voice_id}`.
* Tune defaults with `PATCH /v1/voices/{voice_id}/settings`.
* Remove the voice with `DELETE /v1/voices/{voice_id}`.

## Continue building

<Columns cols={2}>
  <Card title="Voices" icon="sliders-horizontal" href="/concepts/voices">
    Learn how cloned voices, designed voices, public voices, and voice settings fit together.
  </Card>

  <Card title="Text to speech" icon="mic" href="/guides/text-to-speech">
    Use the saved cloned voice for dialogue lines, previews, or production audio.
  </Card>

  <Card title="Managing history" icon="history" href="/guides/managing-history">
    Download generated audio, replay previous requests, and clean up test runs.
  </Card>

  <Card title="Rate limits" icon="gauge" href="/reference/rate-limits">
    Plan clone and generation retries around shared Studio/API concurrency limits.
  </Card>
</Columns>
