Text-to-speech
https://api.suisse-speech.ch/v1 · X-API-Key3.0 Speech models (studio vs swift)
Two models serve different use cases:
| model | mode | description | default |
|---|---|---|---|
studio |
Batch | Highest fidelity and natural delivery. Renders Swiss German dialect with its own wording and grammar, with nuanced expressive delivery. Recommended for IVR prompts, greetings, announcements and high-quality voice content. | Yes |
swift |
Batch and realtime | Low latency. Streams audio while it is synthesised; first audio typically arrives in about half a second, and in under a second for Swiss German dialect. Made for interactive telephone agents and conversational WebSocket streams. | No |
studio renders the whole passage before returning audio, so the realtime
stream uses swift.
3.1 Batch: POST /tts
Send the whole text, get the whole audio.
{
"text": "Ihr Termin am Dienstag um zehn Uhr ist bestätigt.",
"voice": "lea",
"language": "de-CH",
"dialect": "bern",
"speed": 0.95,
"style": "ruhig und geduldig, kurze Pausen nach jedem Satz",
"format": "mp3"
}
The response body is the audio, with metadata in headers:
| header | meaning |
|---|---|
X-Suisse-Request-Id |
quote this in support requests |
X-Suisse-Audio-Duration |
seconds, the unit you are billed in |
X-Suisse-Audio-Encoding |
mp3, wav, … |
X-Suisse-Audio-Sample-Rate |
Hz |
X-Suisse-Voice |
voice actually used |
X-Suisse-Cache |
miss: no audio is stored, unless your key keeps audio of fixed prompts (Stored data); then hit, partial, miss, refresh or off |
Add "output": "json" (or send Accept: application/json) for a JSON envelope
with base64 audio, the mark offsets and the passage count instead. The audio of
a synthesis job carries the same headers, and a job reports the
mark offsets under marks.
A request takes up to 8,000 characters. A long text is rendered in passages cut
at sentence boundaries and comes back as one continuous clip. A request that is
not finished after 240 seconds fails with tts.timeout (504) and is not billed.
Measured with German text: 8,000 characters take about 35 s on swift and about
190 s on studio, so for long prepared text on studio a job is
the safer choice; a job is not held to the 240 seconds.
3.2 Realtime: GET /tts/stream (WebSocket)
Push text as you produce it and receive audio while the rest is still being written. Use this when the text comes from a live source: an LLM, an agent, an operator typing. For text you already hold in full, batch is simpler and no slower overall.
Endpoint: wss://api.suisse-speech.ch/v1/tts/stream
Client → server
{"type":"session.start","voice":"anna","language":"de-CH","dialect":"zurich",
"speed":1.0,"style":"freundlich","format":"pcm16","sample_rate_hz":24000}
{"type":"text.append","text":"Grüezi. "}
{"type":"text.flush"}
{"type":"session.end"}
Text is rendered passage by passage at sentence boundaries. A full stop after an
abbreviation, an initial or an ordinal (Dr., J. S. Bach, am 3. Oktober)
does not end a sentence; the full stops of Japanese, Chinese and Hindi (。!?।)
do, with no space after them. text.flush forces a partial passage out without
ending the session. Use it when you know no more text is coming for a while and
you would rather have the audio now.
Turns. A voice agent keeps one session for the whole call and speaks one turn
at a time: text.append as the text arrives, text.flush at the end of the turn,
session.end only when the call ends. text.flush ends the turn: as soon as its
last passage is rendered, the rest of the turn’s audio is sent at once. Without
text.flush a turn ends after 150 ms without new text. The end of a turn can be
followed by up to 0.3 s of silence. It is part of the stream you receive, so
mark offsets and the duration_seconds of session.complete count it; it is
not speech, so it is not billed (GET /usage shows the billed seconds).
Server → client
{"type":"session.ready","request_id":"req_…","voice":"anna","encoding":"pcm16",
"sample_rate_hz":24000,"frame_bytes":1024}
{"type":"audio.chunk","seq":1,"encoding":"pcm16","sample_rate_hz":24000,"data":"<base64>"}
{"type":"segment.done","characters":42,"duration_seconds":2.31,"cache":"miss"}
{"type":"mark","name":"after_ref","offset_seconds":7.15}
{"type":"session.complete","duration_seconds":7.94,"frames":48,"cache":{"hits":0,"misses":3}}
Concatenate the decoded data values in seq order to reconstruct the stream.
Every frame is exactly frame_bytes, except the last frame of each turn and of
the session, which carries the rest and is shorter.
segment.done comes after the last audio frame of its passage: when it arrives,
you have all of that passage’s audio, and once the last passage of a turn is
done, nothing more arrives until new text does. A mark likewise comes after
the audio before it, with its name exactly as you wrote it. session.complete
comes after the last frame of the session. Should the audio encoder fail, the
session ends with an error frame (tts.encode_failed) and close code 1011,
never with session.complete over unplayable bytes. A repeated session.start
is ignored.
Binary transport: a third fewer bytes
Add "transport":"binary" to session.start and audio arrives as raw binary
WebSocket frames instead of base64 inside JSON. Control frames stay JSON, so
the rule is simple: a binary frame is always audio, in order, in the
encoding session.ready named. No parsing, no decode step.
Measured on the same text: JSON transport carries 36.4 % overhead on the wire, binary carries 0.1 %.
ws.send(JSON.stringify({ type: 'session.start', voice: 'anna',
format: 'pcm16', transport: 'binary' }));
ws.on('message', (data, isBinary) => {
if (isBinary) return audio.write(data); // audio, in order
const frame = JSON.parse(data.toString()); // control
});
transport defaults to json. Use binary for anything carrying real volume.
Reconnection. A session is not resumable. If the socket drops, open a new
one and resend the text that was not yet acknowledged by a segment.done.
Sessions are capped at 15 minutes, counted from the moment the socket opens: a
socket that never sends session.start is closed at the cap as well.
3.3 Voices
Twelve voices, all usable in every supported language. GET /tts/voices returns
the catalogue with gender, timbre, pace and a suggested use for each.
| voice | voice | ||
|---|---|---|---|
anna |
warm, balanced; the default | stefan |
neutral, professional |
vera |
bright, energetic; menus and prompts | reto |
deep, calm; announcements |
lea |
soft, calm; long explanations | lukas |
brisk, direct; confirmations |
nora |
clear articulation; narrow-band lines | jonas |
full-bodied, steady; corporate audio |
mia |
gentle, empathetic; sensitive topics | andrin |
warm, patient; advice and sales |
elin |
neutral, even; long documents | felix |
expressive; follows style prompts closely |
Voices are stable identifiers: a voice will not be removed or repointed at a different sound without notice, because that would silently change the audio in a deployed IVR.
3.4 Languages and dialects
The catalogue has two levels. language is a code that may carry a region, and
a regional standard variety is its own code: it-CH, fr-CA, en-GB, en-IN,
de-AT. dialect is a variety inside one language: de-CH + stgallen,
fr-CH + geneve, en-GB + scottish. GET /capabilities is the list; the
hand-tuned Swiss German dialects are:
| dialect | region / description |
|---|---|
standard |
Supra-regional Swiss German (default) |
zurich |
Zürich (Züritüütsch) |
bern |
Bern (Bärndütsch) |
basel |
Basel (Baaseldütsch) |
luzern |
Lucerne and Central Switzerland (Lozärnerdütsch) |
Both models translate the input text into authentic regional dialect vocabulary,
grammar and pronunciation: a real dialect, not an accent. swift does it in
real time on the stream; studio does it with the highest fidelity and is the
one to use for prepared audio.
language: "de-CH-zurich" is accepted as a compact equivalent of the two
fields.
Switzerland comes first in the catalogue:
| language | dialects | what you hear |
|---|---|---|
de-CH |
standard, zurich, bern, basel, luzern |
Swiss German, hand-tuned |
de-CH |
stgallen, thurgau, schaffhausen, appenzell, glarus, graubuenden, aargau, solothurn, oberland, freiburg, wallis, zug, schwyz, uri |
further Swiss German regions |
de-CH |
hochdeutsch |
Swiss High German: Standard German with Swiss pronunciation |
fr-CH |
none, or geneve, vaud, valais, neuchatel, fribourg, jura |
Swiss French and the accents of the Romandie |
it-CH |
none | Swiss Italian (Ticino) |
Swiss German dialects are rendered INTO the dialect (wording, grammar and sound) so reply text may be written in Standard German. Every other variety, Swiss High German included, keeps the words exactly as written and changes only pronunciation, melody and rhythm.
Beyond Switzerland the larger languages carry their regional standard varieties
as language codes, some with accents of their own as dialects: de-DE, de-AT,
fr-FR, fr-BE, fr-CA, it-IT, en-GB, en-US, en-IE, en-AU, en-IN,
es-ES, es-MX, pt-PT, pt-BR, nl-BE and more. Read them from
GET /capabilities rather than from this page.
The catalogue has 60 languages in all, more than 150 with the regional varieties and dialects. Recognition and synthesis accept the same codes. Beside German, French, Italian and English they are:
| region | codes |
|---|---|
| Europe | es, pt, nl, pl, tr, sq, sr, hr, bs, mk, sl, bg, ro, el, hu, cs, sk, da, sv, no, fi, et, lv, lt, uk, be, ru, ca, gl, eu, cy |
| Middle East and Central Asia | ar, he, fa, az, kk |
| South Asia | hi, ur, bn, pa, gu, mr, ta, te, kn, ml |
| East and Southeast Asia | zh, ja, ko, vi, th, id, ms, tl |
| Africa | sw, af |
These are plain codes without regional varieties or dialects: the text is spoken as written, in the language it is written in.
Every language and every dialect carries a status. The five hand-tuned Swiss
German dialects and Swiss French are verified: we run and measure them in
production. Everything else on this page is supported: rendered on a
best-effort basis, with no published quality figure. Listen before you commit a
supported variety to production. A delivery the catalogue does not list at
all (another accent, a register) can be asked for in free text with style
(3.6), equally on a best-effort basis.
3.5 Audio formats
| format | container | rates (Hz) | use |
|---|---|---|---|
mp3 |
MPEG | 32000, 44100, 48000 | general purpose, small |
wav |
RIFF | 8000 … 48000 (24000) | lossless, easy to post-process |
opus |
Ogg | 48000 | lowest bandwidth for streaming |
pcm16 |
none | 8000 … 48000 (24000) | lowest latency, feed straight to a mixer |
mulaw |
none | 8000 | G.711 µ-law, drop-in for a telephony trunk |
alaw |
none | 8000 | G.711 A-law, drop-in for a telephony trunk |
Defaults in bold. sample_rate_hz selects the rate (the older spelling
sample_rate is still read). pcm16, mulaw and alaw are headerless: you
get raw samples, which is what a telephony stack usually wants. mp3 is encoded
at 96 kbit/s, at 32000 Hz at 80 kbit/s.
3.6 Style
style is a free-text delivery prompt. It steers how the text is spoken,
never what is spoken: the supplied text is always rendered verbatim.
"freundlich und zügig, wie am Empfang"
"ruhig und geduldig, kurze Pausen nach jedem Satz"
"sachlich und neutral, ohne Emotion"
3.7 Long text
Batch and realtime both hold a connection for the length of the work. For a chapter rather than a sentence, submit a job instead.