Skip to main content
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.

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

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"])
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);
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

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"))
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");
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

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"])
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);
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

Voices

Learn how cloned voices, designed voices, public voices, and voice settings fit together.

Text to speech

Use the saved cloned voice for dialogue lines, previews, or production audio.

Managing history

Download generated audio, replay previous requests, and clean up test runs.

Rate limits

Plan clone and generation retries around shared Studio/API concurrency limits.