Text-to-speech

Base URL https://api.suisse-speech.ch/v1 · X-API-Key

3.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.