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 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)
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. |
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)
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:
{
"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. |
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.