Sync HTTP
Generate speech synchronously with Open API v1.
Sync HTTP
Use the sync TTS endpoint when the text is short enough for a request-response flow and your product can wait for the audio before continuing. For long text, batch work, or user-visible queues, use Async Jobs.
There is no additional sync-only hard limit. As operational guidance, use Async Jobs for text longer than about 2,500 characters, and set the HTTP client timeout high enough for the selected model and text length.
If your client expects the OpenAI /v1/audio/speech request shape, use the OpenAI-Compatible TTS endpoint instead.
POST /api/open/v1/speech/tts
Authorization: Bearer KITTA_API_KEY
Content-Type: application/json
X-Request-Id: YOUR_STABLE_REQUEST_IDRequest
{
"text": "Hello from Kitta Audio.",
"voiceId": "00a1b221-6137-4b73-ad62-b0cbce134167",
"modelId": "fishaudio-s21pro-flash",
"format": "mp3"
}Common fields:
| Field | Type | Notes |
|---|---|---|
text | string | Text to synthesize. Normalize whitespace before sending large generated text. |
voiceId | string | Preferred voice id for new integrations. |
modelId | string | TTS engine model id, such as fishaudio-s21pro-flash. |
format | string | Output container such as mp3, depending on enabled models. |
cache | boolean | When true, the response can return JSON metadata and an audio URL. |
New integrations should use voiceId from GET /api/open/v1/voices. For a quick connection test, use the public system voice 00a1b221-6137-4b73-ad62-b0cbce134167.
Do not mix fields from older SDKs or other site variants into the current Open API contract.
curl https://kittaai.com/api/open/v1/speech/tts \
-H "Authorization: Bearer KITTA_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Request-Id: tts-order-123-segment-1" \
-d '{"text":"Hello from Kitta Audio.","voiceId":"00a1b221-6137-4b73-ad62-b0cbce134167","modelId":"fishaudio-s21pro-flash","format":"mp3"}' \
--output speech.mp3Response
When cache is false or omitted, successful responses return binary audio. When cache is true, successful responses return JSON metadata:
{
"audio_url": "https://example.com/generated.mp3",
"credits_used": 12,
"quota_remaining": 987988
}Your client should branch on the Content-Type header instead of assuming one response shape. Store generated audio in your own durable storage if the URL is short-lived.
Billing And Credits
Sync TTS consumes credits based on generated content and model configuration. Because the endpoint performs generation inside the HTTP request, a client timeout does not always mean the server cancelled work.
X-Request-Id is optional, but strongly recommended. Generate one stable value for each logical generation and reuse it only when retrying that exact request. Do not send concurrent blind retries. The same account and request id behave as follows:
- a matching request still in progress returns
409 ERR_REQUEST_IN_PROGRESSwithout another charge; - a different payload returns
409 ERR_REQUEST_ID_CONFLICT; - a completed
cache=truerequest replays the existing JSON URL response without another charge; - a completed binary response returns
409 ERR_REQUEST_ALREADY_COMPLETED, because the server does not retain every binary response; - a previously refunded request returns
409 ERR_REQUEST_PREVIOUSLY_REFUNDED; use a new request id after correcting the failure.
For retry-sensitive synchronous work, use cache=true. For text longer than about 2,500 characters, use Async Jobs for durable status and result retrieval.
If you need exact post-generation balance, call Profile after the request completes. For large batches, prefer async jobs so each task has a durable id and status.
Errors
| Status | Meaning | Action |
|---|---|---|
400 | Text, voice id, format, or payload shape is invalid | Fix the request before retrying |
401 | API key is missing or invalid | Refresh server-side credentials |
402 | Credits or quota are insufficient | Stop the batch and show a billing state |
409 | Request id is active, completed, refunded, or reused | Follow the error code; do not retry with a new id blindly |
429 | Rate limited | Retry with backoff |
500 | Generation failed after validation | Retry only if your product can tolerate duplicate audio |