All endpoints are exposed through the PeachDesk API under the base path
/api/voice. For example, the synthesis endpoint POST /generate is called as POST /api/voice/generate. Every request must include your PeachDesk API key in the X-API-Key header (an interactive session token in Authorization: Bearer also works — see Authentication):Concepts
Voice profile
Every generation is spoken by a voice profile (
profile_id) — either a Built-in voice or a Clone from audio profile you created in the Voices tab.Engine
Pick one of the four served VAANI engines (
vaani, vaani-english, vaani-multilingual, vaani-indic). Models are hosted and served by PeachDesk — you just select one from the dropdown.Asynchronous by default
POST /generate returns immediately with a generating status. Watch progress over Server-Sent Events, then fetch the finished audio.Versioned takes
Re-rendering or applying effects produces additional versions on the same generation. The default version is what
/audio/{id} serves.Generate speech
POST /api/voice/generate
Queue a text-to-speech job. Returns the generation record right away with status: "generating"; the audio is rendered in the background.
string
required
ID of the voice profile to speak with (Built-in or cloned).
string
required
The text to synthesize. 1–50,000 characters. Long text is automatically split into chunks and stitched together.
string
default:"en"
BCP-style language code. Supported values include
en, zh, ja, ko, de, fr, es, it, pt, ru, hi, ar, and many more.string
default:"vaani"
Synthesis engine. One of
vaani (VAANI), vaani-english (VAANI-ENGLISH), vaani-multilingual (VAANI-MULTILINGUAL), or vaani-indic (VAANI-INDIC). Any other value is rejected with 422. If omitted, the profile’s default engine is used; every served engine can clone, so a cloned profile is only re-routed when its recorded engine is unavailable.string
Legacy field. No served engine offers multiple sizes, so this is accepted and ignored. Omit it.
integer
Optional fixed random seed for reproducible output.
string
Legacy field (up to 500 characters). Stored on the generation record, but no served engine acts on it — the engine that supported instructed generation is no longer in the catalog. Use
audio_params to steer delivery.boolean
default:"false"
When
true and the profile has a personality prompt, the input text is rewritten in-character by the LLM before being spoken.boolean
default:"true"
Normalize the output audio’s loudness.
integer
default:"800"
Maximum characters per chunk when splitting long text (100–5000).
integer
default:"50"
Crossfade duration in milliseconds between stitched chunks (0–500;
0 is a hard cut).array
Optional list of effect configs applied after synthesis as a versioned take. Overrides the profile’s default effects chain.
object
Fine-tune knobs. See Audio parameters below for the two groups, their ranges, and which engine honors which.
Audio parameters
audio_params holds two kinds of field. Native knobs are passed into the model at synthesis time, and each engine only honors the ones it advertises — sending an unsupported one is safe, it is simply dropped. Universal knobs are applied to the rendered audio afterwards, so they behave identically on every engine.
Native knobs:
stability, similarity, and style are the 0–1 abstractions; temperature, cfg_weight, and exaggeration are the same controls at their native scale and take precedence when both are sent.
Universal knobs (post-processing — every engine):
speed and pitch are post-processing, not model prosody: no VAANI engine takes a speed or pitch parameter natively, so these are applied to the rendered waveform. There is no emotion field — use style/exaggeration for expressiveness.GenerationResponse
string
Unique generation ID. Use it to poll status and fetch audio.
string
Voice profile used.
string
The final spoken text (after any personality rewrite).
string
Language code.
string
generating, loading_model, completed, or failed.string | null
Storage path of the rendered audio (populated once complete).
number | null
Audio length in seconds (once complete).
string
Engine that served the request.
string | null
Model size used, if applicable.
integer | null
Seed used.
string
Origin of the request (e.g.
manual, personality_speak).boolean
Whether the generation is favorited.
string
ISO-8601 creation timestamp.
array | null
List of versioned takes once they exist.
string | null
ID of the default version served by
/audio/{id}.POST /api/voice/generate/warmup
Preload an engine on PeachDesk’s servers so the next generation starts warm. The Voice Studio UI calls this when you pick an engine. It never triggers a download — if the model isn’t already resident it is a no-op.
string
default:"vaani"
Engine to preload.
string
Legacy field — no served engine has multiple sizes. Omit it.
status values: warming, already_loaded, or not_downloaded.
GET /api/voice/generate/{generation_id}/status
Stream live status for a generation over Server-Sent Events (text/event-stream). The stream closes once the generation reaches completed or failed.
string
required
The generation ID returned by
/generate.data: event carries:
string
Generation ID.
string
loading_model, generating, completed, failed, or not_found.number | null
Final duration when complete.
string | null
Error message if the generation failed.
string
Origin of the request.
POST /api/voice/generate/{generation_id}/retry
Retry a failed generation with its original parameters. Returns a 400 if the generation is not in failed status.
string
required
ID of the failed generation.
GenerationResponse (status back to generating).
POST /api/voice/generate/{generation_id}/regenerate
Re-run TTS with the same parameters and save the result as a new version on the same generation. The generation must be completed.
string
required
ID of a completed generation.
GenerationResponse.
POST /api/voice/generate/{generation_id}/cancel
Cancel a queued or in-flight generation. Only generations in loading_model or generating can be cancelled.
string
required
ID of an active generation.
Queued generation cancelled, Orphaned generation cleared.
Streaming synthesis
These endpoints synthesize and return audio in the same request — useful for low-latency playback.POST /api/voice/generate/stream
Generate speech and stream the rendered audio back directly without persisting it to history. Accepts the same body as POST /generate.
- Response: binary audio stream.
Content-Typeisaudio/wavby default (oraudio/ogg/audio/flacif requested viaaudio_params.output_format). Content-Disposition: attachment; filename="speech.wav".
POST /api/voice/generate/stream-live
Progressive, lowest-latency synthesis. Each chunk’s audio is streamed as soon as it’s generated, so the client can start playback on the first sentence while the rest renders. The assembled result is then persisted so it still appears in History.
Wire format: a sequence of frames, each = a 4-byte big-endian length prefix followed by a self-contained WAV blob (directly decodable by the browser’s
decodeAudioData). Content-Type: application/octet-stream. The persisted generation ID is returned in the X-Generation-Id response header.POST /generate.
POST /api/voice/generate/import
Register an external audio file as a generation row — used by the Stories timeline to drop in music or other non-TTS audio. The row attaches to a singleton “Imported Audio” profile so it flows through the normal generation plumbing.
file
required
multipart/form-data upload. Allowed extensions: .wav, .mp3, .flac, .ogg, .m4a, .aac, .webm. Maximum 200 MB.GenerationResponse with status: "completed", engine: "import", and source: "import".
Generation history
GET /api/voice/history
List your generation history with optional filters.
string
Filter to a single voice profile.
string
Free-text search over generation text.
integer
default:"50"
Page size.
integer
default:"0"
Pagination offset.
HistoryListResponse
array
List of
HistoryResponse entries (each includes the resolved profile_name).integer
Total number of matching generations.
GET /api/voice/history/stats
Aggregate statistics about your generations (counts, totals).
GET /api/voice/history/{generation_id}
Fetch a single generation by ID, including its profile_name.
string
required
The generation ID.
HistoryResponse
string
Generation ID.
string
Voice profile ID.
string
Display name of the voice profile.
string
Spoken text.
string
Language code.
string | null
Storage path of the audio.
number | null
Length in seconds.
string
Engine used.
string | null
Model size used.
string
Generation status.
boolean
Favorite flag.
string
ISO-8601 timestamp.
POST /api/voice/history/{generation_id}/favorite
Toggle the favorite flag on a generation.
string
required
The generation ID.
DELETE /api/voice/history/{generation_id}
Delete a single generation.
string
required
The generation ID.
DELETE /api/voice/history/failed
Bulk-delete every generation with status: "failed" — backs the Clear failed button in the UI.
POST /api/voice/history/import
Import a previously exported generation from a ZIP archive (multipart/form-data, max 50 MB).
file
required
The
.zip archive to import.GET /api/voice/history/{generation_id}/export
Download a generation as a ZIP archive (audio plus metadata).
string
required
The generation ID.
- Response:
application/zipattachment.
GET /api/voice/history/{generation_id}/export-audio
Download only the audio file from a generation.
string
required
The generation ID.
- Response:
audio/wavattachment. Returns404if the generation has no audio.
Serving audio
These endpoints stream stored audio bytes back to the client. TheContent-Type is derived from the file extension, so imported .mp3 / .m4a / .ogg files keep their original format.
GET /api/voice/audio/{generation_id}
Serve the default version of a generation’s audio.
string
required
The generation ID.
GET /api/voice/audio/version/{version_id}
Serve the audio for a specific version (take) of a generation — used after regenerating or applying effects.
string
required
The version ID.
GET /api/voice/samples/{sample_id}
Serve a voice profile’s sample audio clip (the reference used by Clone from audio profiles).
string
required
The profile sample ID.
- Response:
audio/wavfile. Returns404if the sample or its file is missing.

