# Fast mode

<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Fast mode provides speech synthesis for complete text inputs. The audio streams back in the same HTTP response, so playback can start before synthesis finishes.

## Capabilities

-   Single-call plain text synthesis, up to 4,000 characters
-   Streamed raw PCM audio
-   Voice, speed, and volume controls
-   Optimized for prompts, IVR, notifications, UI read-out, and short narration

## Speech synthesis

Use this endpoint to convert text to speech:

**`POST /aiservices/tts/synthesize`**

Include your [Zoom AI Services credentials](/docs/ai-services/auth/) and `Content-Type: application/json`. If you send the optional `Z-Account-Id` and `Z-User-Id` headers, they must match the authenticated account and user.

### Example request (cURL)

```shell
curl --fail-with-body --no-buffer \
  https://api.zoom.us/v2/aiservices/tts/synthesize \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --dump-header hello.headers \
  --output hello.pcm \
  -d '{
    "input": "Hello everyone, welcome to Zoom AI Services.",
    "voice": "jenna",
    "speed": 1.0,
    "volume": 1.0,
    "response_format": "pcm_44100"
  }'
```

On success, `hello.pcm` contains the audio and `hello.headers` contains the `x-zm-trackingid` header. Check curl's exit status and the HTTP status before you use the file: an error writes a JSON body to the file, and an interrupted stream leaves partial audio.

### Request fields

Only `input` is required. All fields are top-level properties; there is no `config` object.

| Field             | Type   | Required | Default     | Description                                                                                          |
| ----------------- | ------ | -------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| `input`           | string | Yes      | —           | Non-empty UTF-8 plain text, up to 4,000 Unicode code points. Whitespace-only input is rejected.      |
| `voice`           | string | No       | `jenna`     | Case-insensitive [voice ID](/docs/ai-services/tts/#language-and-voices).                             |
| `speed`           | number | No       | `1.0`       | Speaking rate multiplier, from `0.5` to `2.0` inclusive. `1.0` is the voice's normal rate.           |
| `volume`          | number | No       | `1.0`       | Volume multiplier, greater than `0` and up to `10` inclusive. `1.0` is the voice's normal volume.    |
| `response_format` | string | No       | `pcm_44100` | Only `pcm_44100` is supported. Other values, including `pcm_16000`, return `400 UNSUPPORTED_FORMAT`. |

The request body must be a single UTF-8 JSON object of up to 32 KiB (32,768 bytes). Characters are Unicode code points, including spaces and punctuation, and input is never truncated.

Malformed JSON, a missing or empty `input`, wrong types, and out-of-range values return `400 INVALID_INPUT`. To use a default, omit the field. The API treats `input` as plain text, so SSML tags are read aloud rather than interpreted.

### Response (200)

```plaintext
HTTP/1.1 200 OK
Content-Type: audio/pcm;rate=44100;bits=16;channels=1;encoding=signed-int;endian=little
Transfer-Encoding: chunked
Cache-Control: no-store
x-zm-trackingid: req_123

<ordered raw PCM audio bytes>
```

The audio is signed 16-bit little-endian mono PCM at 44,100 Hz (88,200 bytes per second), with no WAV header. Set these values explicitly when you play or convert the audio.

The response has no `Content-Length`. HTTP/1.1 responses use chunked transfer encoding. Network reads don't always end on a 16-bit sample boundary, so carry incomplete samples over to the next read.

The server validates the request before it sends `200`, and sends `200` as soon as the first audio is ready. A `200` status means streaming started; synthesis succeeded only if the response body ends normally.

## Handle errors and interruptions

If the request fails before streaming starts, the server returns an HTTP error status and a JSON body:

```json
{
    "code": 400,
    "reason": "UNSUPPORTED_VOICE",
    "message": "Unsupported voice",
    "metadata": {}
}
```

| HTTP status | Reason                                    | Handling                                                                               |
| ----------- | ----------------------------------------- | -------------------------------------------------------------------------------------- |
| `400`       | `INVALID_INPUT`                           | Correct the request body, input, speed, or volume.                                     |
| `400`       | `UNSUPPORTED_VOICE`                       | Use a [supported voice](/docs/ai-services/tts/#language-and-voices).                   |
| `400`       | `UNSUPPORTED_FORMAT`                      | Use `pcm_44100`.                                                                       |
| `400`       | `TEXT_TOO_LONG`                           | Reduce the input to at most 4,000 Unicode code points.                                 |
| `401`       | Authentication error                      | Check your API key or JWT.                                                             |
| `402`       | `QUOTA_EXCEEDED`                          | Your API key reached its credit limit. Raise the limit or wait until the limit resets. |
| `403`       | `IDENTITY_MISMATCH` or `MISSING_IDENTITY` | Check that `Z-Account-Id` and `Z-User-Id` match your credentials.                      |
| `413`       | `PAYLOAD_TOO_LARGE`                       | Reduce the request body to 32,768 bytes or less.                                       |
| `415`       | `UNSUPPORTED_MEDIA`                       | Use `Content-Type: application/json`.                                                  |
| `429`       | `RATE_LIMIT_EXCEEDED`                     | Wait for the time in `Retry-After`, then retry.                                        |
| `500`       | `INTERNAL_ERROR`                          | Report the failure with its tracking ID.                                               |
| `503`       | `SERVICE_UNAVAILABLE`                     | Retry after 10 seconds, as given in `Retry-After` and `metadata.retry_after_seconds`.  |

After streaming starts, the status can't change. If synthesis fails mid-stream, the server ends the response abnormally instead of sending JSON: an HTTP/1.1 response ends without its final chunk, and an HTTP/2 stream is reset. Treat this as a failure and don't use the partial audio as a complete result.

Retry temporary failures as new requests, using exponential backoff with jitter and honoring `Retry-After`. A retry synthesizes the text from the beginning, so account for audio you've already played.

You can cancel a request by closing the connection. The service then stops synthesis. Cancellation doesn't support pause or resume.

## Request tracking

Every response includes an `x-zm-trackingid` header. For support requests, keep this value, the approximate request time, and whether the response completed, failed, or was cancelled.
