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

# Bland BTTS

## 1. Overview

This document describes how to use speech synthesis and voice cloning through the Bland BTTS native protocol. Both endpoints are synchronous: a POST request returns the result directly, with no need to create a task and poll for the result.

### 1.1 Endpoints

| Capability | Method and path |
| - | - |
| Speech synthesis | `POST /v3/bland-tts/v2/tts` |
| Voice cloning | `POST /v3/bland-tts/v1/voices/clone` |

The full address in the examples in this document is `https://api.novita.ai` plus the endpoint path in the table above, where `https://api.novita.ai` is the API domain you use.

### 1.2 Authentication

All requests must carry the platform API Key:

```text theme={"system"}
Authorization: Bearer <YOUR_API_KEY>
```

Speech synthesis requests must also specify the JSON content type (`Content-Type: application/json`); voice cloning requests use `multipart/form-data` and do not need to specify the content type separately (the HTTP client generates it automatically, including the boundary).

### 1.3 Response Structure

* On success, speech synthesis returns audio binary data directly, not JSON. See "2. Speech Synthesis" for details.
* On success, voice cloning returns JSON, where `data.voice_id` is the UUID of the newly cloned voice and can be used directly as the `voice` field of the speech synthesis endpoint.
* When the two endpoints fail, they return different JSON error structures. See the "Common Errors" section of each endpoint.

## 2. Speech Synthesis

Official parameter reference: [Speak](https://docs.bland.ai/api-v1/post/speak)

### 2.1 Endpoint

```text theme={"system"}
POST https://api.novita.ai/v3/bland-tts/v2/tts
```

Common request fields:

| Field | Type | Required | Description |
| - | - | - | - |
| `text` | string | Yes | Text to synthesize, up to 5000 characters. Supports pause syntax, such as `<`. |
| `voice` | string | Yes | Voice UUID (voice names are not accepted). Use the official List Voices endpoint to look it up, or use the `voice_id` produced by the voice cloning endpoint. |
| `audio` | object | No | Output audio format configuration. All sub-fields are optional. |
| `audio.encoding` | string | No | Defaults to `pcm_s16le`. Options are `pcm_s16le` (16-bit signed little-endian PCM) or `mulaw` (8-bit mu-law, fixed at 8kHz, for telephony scenarios). |
| `audio.sample_rate` | number | No | Defaults to 48000. Options are 8000/16000/24000/44100/48000; fixed at 8000 when `encoding=mulaw`. |
| `audio.container` | string | No | Defaults to `raw`. Options are `raw` (raw frames, suitable for streaming scenarios) or `wav` (a complete RIFF/WAVE file, suitable for download and storage). |
| `controls` | object | No | Voice expressiveness controls. All sub-fields are optional, with a range of 0.0–1.0, and take effect only on BTTS\_V3 voices. |
| `controls.expressiveness` | number | No | Higher values make the intonation richer and more varied; lower values make it flatter and more uniform. |
| `controls.stability` | number | No | Higher values make repeated synthesis results more consistent; lower values increase expressiveness but also variability. |

### 2.2 Example

```bash theme={"system"}
curl -X POST 'https://api.novita.ai/v3/bland-tts/v2/tts' \
  -H 'Authorization: Bearer <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "text": "Hello world",
    "voice": "<voice_id>",
    "audio": {
      "container": "wav"
    }
  }'
```

### 2.3 Response

On success, the endpoint returns audio binary data directly (HTTP 200), not JSON. The Content-Type varies with the request's `audio.container`/`audio.encoding` (for example, `audio/wav`, `audio/pcm`). In practice, the transparent proxy returns the upstream `X-Sample-Rate` response header unchanged (the sample rate of the synthesized audio); other response headers documented by Bland, such as `x-request-id`/`x-model`/`x-voice-id`/`x-cost`/`x-latency`, were not observed in testing. Do not rely on these headers.

### 2.4 Billing

```text theme={"system"}
Request cost = unit price (per thousand characters) × number of characters in text / 1000
```

The character count is calculated from the `text` field. Chinese characters (Han characters) count as 2 characters, and other characters (including English letters, digits, spaces, and punctuation) count as 1 character. The exact unit price depends on the pricing page of the service you use.

## 3. Voice Cloning

Official parameter reference: [Clone Voice](https://docs.bland.ai/api-v1/post/clone)

### 3.1 Endpoint

```text theme={"system"}
POST https://api.novita.ai/v3/bland-tts/v1/voices/clone
```

The request body is `multipart/form-data`. Common fields:

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Display name of the cloned voice, 1–30 characters. Must be unique within your voice library. |
| `audio_samples` | file | Yes | Audio sample file. Regardless of which engine is used (V2 or V3), only a single file is accepted. About 10 seconds is recommended, with a maximum of 10MB. |
| `gender` | string | No | `male` or `female`. Optional but recommended, as it helps the underlying model. |
| `description` | string | No | Free-form text description, provided to the model as supplementary context for tone and style. |
| `isBTTS_V3` | string | No | When the value is the string `"true"`, the V3 engine is used (the default when neither engine flag is set). |
| `isBTTS_V2` | string | No | When the value is the string `"true"`, the V2 engine is used (choose one of `isBTTS_V3` and `isBTTS_V2`). |

> [!NOTE]
>
> `isBTTS_V3`/`isBTTS_V2` are boolean-semantic fields, but because the request body is `multipart/form-data` rather than JSON, they must be sent as the string `"true"`.

### 3.2 Example

```bash theme={"system"}
curl -X POST 'https://api.novita.ai/v3/bland-tts/v1/voices/clone' \
  -H 'Authorization: Bearer <YOUR_API_KEY>' \
  -F 'name=my-cloned-voice' \
  -F 'audio_samples=@sample.wav;type=audio/wav'
```

### 3.3 Response

On success, the endpoint returns (HTTP 200):

```json theme={"system"}
{
  "status": 200,
  "data": {
    "voice_id": "<voice_id>",
    "name": "my-cloned-voice"
  },
  "errors": null
}
```

| Field | Type | Description |
| - | - | - |
| `status` | integer | HTTP status code, 200 on success. |
| `data.voice_id` | string | UUID of the newly cloned voice, used directly as the `voice` field of the speech synthesis endpoint. |
| `data.name` | string | Echoes the display name provided in the request. |
| `errors` | null/array | `null` on success. |

Verified in practice: passing the `voice_id` produced by the cloning endpoint directly to the `voice` field of the speech synthesis endpoint returns real synthesized audio with HTTP 200, so the two endpoints can be used in sequence directly.

### 3.4 Billing

The voice cloning endpoint is always free of charge and generates no cost.

### 3.5 Common Errors

```json theme={"system"}
{
  "status": 400,
  "data": null,
  "errors": [
    { "error": "<error type>", "message": "<error message>" }
  ]
}
```

| Scenario | Response recorded in the official documentation | Description |
| - | - | - |
| Request is missing a required field | HTTP 400, error: "Validation Error" | For example, when the `audio_samples` file is not provided. |
| The account has reached the plan's voice limit | The official documentation records HTTP 400, error: "Limit Exceeded", message: "You have reached the maximum number of voices for your plan." | The actual response observed in testing is HTTP 500, `{"data":null,"errors":[{"error":"INTERNAL_SERVER_ERROR","message":"You have reached the maximum number of voices for your plan."}]}`. Use the observed behavior (HTTP 500) as the source of truth and do not assume this scenario returns 400. |

When the account has reached its voice limit, you need to top up the Bland account wallet to increase the quota. This is unrelated to the faas-backend configuration.

## 4. Common Errors and Notes

Error structure of the speech synthesis endpoint:

```json theme={"system"}
{ "error": { "code": "<error code>", "message": "<error message>" } }
```

| HTTP | code | Common scenario | Suggested handling |
| - | - | - | - |
| 400 | `invalid_request` | A required field is missing or incorrectly formatted. | Fix the request based on the error message. |
| 400 | `text_too_long` | `text` exceeds 5000 characters. | Shorten the text or split it into multiple requests. |
| 400 | `unsupported_encoding` | `audio.encoding` is not an allowed value. | Check whether the value is `pcm_s16le`/`mulaw`. |
| 400 | `unsupported_sample_rate` | `audio.sample_rate` is invalid for the current `encoding`. | Check the sample rate value; `mulaw` is fixed at 8000. |
| 400 | `unsupported_container` | `audio.container` is not `raw` or `wav`. | Check the value. |
| 400 | `unsupported_voice` | The voice exists but is not BTTS\_V2/BTTS\_V3. | Switch to a supported voice. |
| 402 | `insufficient_credits` | The account balance is insufficient. | Top up the account. |
| 403 | `voice_not_live` | The voice is in draft status and has not been published. | Publish the voice and retry. |
| 404 | `voice_not_found` | The voice UUID does not exist or is not accessible. | Check the value of the `voice` field. |
| 500 | `synthesis_failed` | Synthesis failed before or during streaming. | Retry later; if the failure persists, contact technical support. |

The error structure of the voice cloning endpoint is described in "3.5 Common Errors" and is not the same structure as the speech synthesis endpoint. Do not mix them up.

Other notes:

* The speech synthesis endpoint request body requires the JSON content type; the voice cloning endpoint request body is `multipart/form-data` and must not be called with JSON.
* A `voice_id` created by voice cloning is shared among all callers under the current API Key, and the system does not record "which caller cloned which voice". Manage voice ownership and visibility in your own business layer, and do not assume the platform isolates voices between callers.
* The optional fields of the voice cloning endpoint (`gender`/`description`/`isBTTS_V3`/`isBTTS_V2`) have not been fully validated with real requests. It is recommended to test them yourself before launch to confirm that the behavior meets expectations.
* When the response is audio binary data, process it directly according to the returned Content-Type and do not attempt to parse it as JSON.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.