# Preview a voice

> Generate a preview of a cloned voice from a source audio file. Upload the audio, provide the text to speak, and stream back PCM16 audio — before committing to a permanent voice.

## Endpoint

`POST /api/v1/voices/preview`

Requires API key authentication via the `x-api-key` header. The request is `multipart/form-data`.

## Request

**Form data** — `Content-Type: multipart/form-data`

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `text` | string | **Yes** | Text to generate preview with (minimum 3 words, 10 characters) |
| `similarity` | number | **Yes** | Voice similarity to source (0.0 to 1.0). Higher values produce more similar voice |
| `model_id` | string | **Yes** | The model identifier to use for generation |
| `speed` | number | No | Speech speed (0.7 to 1.2, default 1.0). Values below 1.0 slow down speech, above 1.0 speed it up |
| `file` | File | **Yes** | Audio file containing the voice to preview |
| `sample_rate` | number | No | Output sample rate in Hz, `8000`–`48000` (default `24000`). **Use `48000` — it's the engine's native rate**, so the audio skips downsampling and needs no client-side resampling for WebRTC. |

> Notes. The API will process the provided audio file to generate the voice preview. text must be at least 3 words and 10 characters long. The default stays 24000 for backward compatibility — pass sample_rate=48000 for the best quality.

## Example request

Upload a source recording and stream the preview audio back.

```bash
curl -X POST "https://api.munsit.com/api/v1/voices/preview" \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@source_audio.wav" \
  -F "text=مرحبا بك في فصيح، هذا صوتي الجديد" \
  -F "similarity=0.8" \
  -F "model_id=faseeh-v1-preview" \
  -F "speed=1.0" \
  -F "sample_rate=48000" \
  --output voice_preview.pcm
```

```python
import requests

url = "https://api.munsit.com/api/v1/voices/preview"
headers = {
    "x-api-key": "YOUR_API_KEY"
}

with open("source_audio.wav", "rb") as audio_file:
    files = {"file": audio_file}
    data = {
        "text": "مرحبا بك في فصيح، هذا صوتي الجديد",
        "similarity": "0.8",
        "model_id": "faseeh-v1-preview",
        "speed": "1.0"
    }
    response = requests.post(url, files=files, data=data, headers=headers, stream=True)

if response.status_code == 200:
    # Save streaming audio
    with open("voice_preview.pcm", "wb") as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)
    print("Voice preview saved successfully")
else:
    print(f"Error: {response.status_code} - {response.text}")
```

```javascript
import fs from "node:fs";

const formData = new FormData();
const audioFile = new Blob([fs.readFileSync("source_audio.wav")]);
formData.append("file", audioFile, "source_audio.wav");
formData.append("text", "مرحبا بك في فصيح، هذا صوتي الجديد");
formData.append("similarity", "0.8");
formData.append("model_id", "faseeh-v1-preview");
formData.append("speed", "1.0");

const response = await fetch('https://api.munsit.com/api/v1/voices/preview', {
  method: 'POST',
  headers: {
    'x-api-key': 'YOUR_API_KEY',
    // Note: Content-Type is set automatically by FormData
  },
  body: formData,
});

if (response.ok) {
  // Handle streaming audio response
  const reader = response.body.getReader();
  const audioChunks = [];

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    audioChunks.push(value);
  }

  // Combine chunks and create audio blob
  const audioBlob = new Blob(audioChunks, { type: 'audio/raw' });
  const audioUrl = URL.createObjectURL(audioBlob);
  // Use audioUrl to play the preview
} else {
  const error = await response.json();
  console.error('Error:', error);
}
```

```go
package main

import (
    "bytes"
    "io"
    "mime/multipart"
    "net/http"
    "os"
)

func main() {
    url := "https://api.munsit.com/api/v1/voices/preview"

    var body bytes.Buffer
    writer := multipart.NewWriter(&body)

    file, _ := os.Open("source_audio.wav")
    defer file.Close()
    part, _ := writer.CreateFormFile("file", "source_audio.wav")
    io.Copy(part, file)

    writer.WriteField("text", "مرحبا بك في فصيح، هذا صوتي الجديد")
    writer.WriteField("similarity", "0.8")
    writer.WriteField("model_id", "faseeh-v1-preview")
    writer.WriteField("speed", "1.0")
    writer.Close()

    req, _ := http.NewRequest("POST", url, &body)
    req.Header.Set("x-api-key", os.Getenv("MUNSIT_API_KEY"))
    req.Header.Set("Content-Type", writer.FormDataContentType())

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    out, _ := os.Create("voice_preview.pcm")
    defer out.Close()
    io.Copy(out, resp.Body)
}
```

## Response

**Status code:** `200 OK`. The body is streaming PCM16 audio, mono, 16-bit, at the rate you requested — `24000` Hz by default, or `48000` when you pass `sample_rate=48000` (recommended). The resolved rate is always echoed in the `Content-Type` header, so a client can follow it rather than assume.

PCM1648000 Hz recommended24000 Hz defaultmono16-bit

| Header | Value |
| --- | --- |
| `Content-Type` | `audio/raw;codec=pcm16;rate=<sample_rate>;channels=1` — e.g. `rate=48000` |
| `Cache-Control` | `no-cache` |
| `Connection` | `keep-alive` |

## Error responses

Errors come back as JSON with an `errorCode` and `errorMessage`.

| Status | Error code | Example message |
| --- | --- | --- |
| **400** Bad Request | `400xx` | `text is required` |
| **400** Bad Request | `400xx` | `similarity must be a number between 0 and 1` |
| **400** Bad Request | `400xx` | `speed must be a number between 0.7 and 1.2` |
| **400** Bad Request | `400xx` | `model_id is required` |
| **400** Bad Request | `400xx` | `file is required and must be of audio type` |
| **401** Unauthorized | `40101` | `Invalid or missing API key` |
| **402** Payment Required | `40201` | `Insufficient wallet balance` |
| **500** Internal Server Error | `50001` | `Failed to generate voice preview` |

> Voice preview. This endpoint generates a preview of a cloned voice. If you're satisfied with the preview, you can proceed to create it as a permanent voice using the voice creation endpoint.

## Go further

- [Voice cloning](/text-to-speech/voice-cloning) — Happy with the preview? Create the voice permanently. — `POST /voices/clone`

- [Voices](/text-to-speech/voices) — Browse the existing voice library. — `GET /voices`

- [Models](/text-to-speech/models) — Pick a model_id for the preview generation. — `GET /models`

- [Synthesize](/text-to-speech/synthesize) — Use your new voice in a text-to-speech request. — `POST /text-to-speech/{model_id}`
