API reference

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

Generated from the OpenAPI 3.0.3 description of Suisse Speech API 1.5.0. Download it as openapi.json to generate a client or import it into your API tool.

About this API

Speech-to-text and text-to-speech for Swiss German, its regional dialects and other languages. Both directions are available in two modes:

  • batch — send a whole file or a whole text, get the whole result
  • realtime — stream over a WebSocket and receive results as they are produced

Start with GET /capabilities: it lists every voice, language, dialect, audio format, parameter range and error code this deployment accepts, so a client never has to hard-code them.

All endpoints require an X-API-Key header with a valid sv_* API key. The environment travels with the key: sv_… is live, sv_test_… is the sandbox — not billed, no allowance consumed, its own budget and concurrency slice. A sandbox key always receives structurally identical synthetic audio and transcripts without any engine being called: free, instant and deterministic, for continuous integration. Real voices and recognition need a live key. The header X-Suisse-Sandbox-Mode: synthetic is still accepted but no longer needed. Every response reports which environment answered in X-Suisse-Environment. WebSocket endpoints additionally accept Sec-WebSocket-Protocol: suisse.v1, key.<api key> for browser clients.

Limits apply per API key: 600 requests/minute with a burst limit of 25 requests/second, a ceiling on simultaneous requests, and a daily budget of audio seconds. An evaluation key additionally carries a fixed allowance of audio hours. See limits and usage_today in GET /capabilities, and the remaining allowance in GET /usage. Synthesis and recognition are both metered in audio seconds, to the second, with no minimum per request.

Reading a 429. Four different things answer with status 429, and error.code in the response body says which one it is:

  • *.rate_limited - too many requests in the window, or the daily audio budget is spent. Retry after Retry-After.
  • *.capacity - the service is momentarily busy. Retry after Retry-After.
  • *.plan_limit_reached - too many simultaneous requests on this key. Reduce parallelism; retrying at the same parallelism does not help.
  • *.entitlement_exhausted - the evaluation allowance of audio hours is used up. Retrying does not help; contact us to extend it.

An HTTP client that reports only the status line hides this distinction, so log the response body of every 429.

Synthesised audio and transcripts are processed in memory and not stored; identical texts are synthesised again each time. Every synthesis response reports cache as miss (the field stays for compatibility).

Simultaneous work is admitted up to a published ceiling and refused beyond it with 429 and a Retry-After header, rather than queued — a queue would turn a capacity problem into a latency problem for the requests that did get in. error.detail names which ceiling was reached: key_capacity (reduce your own parallelism), service_capacity or host_load (back off and retry). The current ceilings are in capacity in GET /capabilities, and are what the deployment enforces today rather than a contractual entitlement.

A narrative integration guide, including worked examples and client behaviour for each error class, ships with the service as API_GUIDE.md.

POST/ttsSynthesise speech from text (batch)

https://api.suisse-speech.ch/v1/tts

Send the complete text, receive the complete audio.

By default the response body is the audio itself, with the media type of the requested format and the metadata in X-Suisse-* headers. Set output: "json" (or send Accept: application/json) to receive a JSON envelope with base64 audio instead.

Two speech models are available:

  • studio (default) — Our premier expressive engine. Natural prosody, nuanced delivery, and native support for regional Swiss German dialect translation and nuances. Recommended for production announcements, IVR greetings, audio content, and high-fidelity speech.
  • swift — Low-latency engine optimized for real-time conversational streaming, telephone interactions, and instant responses.

language selects the language, dialect the regional variety within it. Swiss German (de-CH) is dialect-aware:

  • standard: supra-regional Swiss German (default).
  • zurich: Zurich dialect (Züritüütsch).
  • bern: Bernese dialect (Bärndütsch).
  • basel: Basel dialect (Baaseldütsch).
  • luzern: Lucerne dialect (Lozärnerdütsch). Both models render the text into the dialect - its own words and forms, not an accent - so the text may be written in Standard German. 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. The compact form language: "de-CH-zurich" is accepted as an alternative to the two fields.

Regional varieties and accents

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. The compact form <language>-<dialect> (de-CH-stgallen) is accepted wherever a language code is, by recognition too.

Switzerland: Swiss German in its regional dialects and as Swiss High German (de-CH + hochdeutsch, spoken word for word), Swiss French with the accents of the Romandie, and Swiss Italian (it-CH). Swiss German dialects are rendered into the dialect; every other variety keeps the words exactly as written and changes only pronunciation, melody and rhythm.

GET /capabilities is the list. Every language and dialect there carries a status: verified is measured in production, supported is rendered on a best-effort basis and no quality figure is published for it.

Following the language of a conversation

Recognition reports the language it detected in lang, in the same codes this endpoint accepts as language, the compact dialect form included. A client that lists its target locales as recognition candidates (lang = de-CH-zurich,fr-CH,en) receives exactly one of them back and can pass it here unchanged. No mapping table and no server-side session is involved: every request stands on its own. The reply text may be written in Standard German; for de-CH it is spoken in the chosen dialect. For High German use de-CH-hochdeutsch (Swiss High German) or de.

style is a free-text delivery prompt (up to 600 characters) — e.g. "freundlich und herzlich", "ruhig und geduldig, kurze Pausen nach jedem Satz", or "professionell und sachlich". It steers how the text is spoken, never what is spoken: the supplied text is always rendered verbatim.

A text value whose first element is <speak> is parsed as markup. Each construct is realised for real rather than passed on as a hint:

element effect
<break time="500ms"/> silence of exactly that length in the audio
<say-as interpret-as="digits|telephone|characters|ordinal|date|time|currency|number"> rewrites the text into its spoken form
<sub alias="Aktiengesellschaft">AG</sub> speaks the alias
<prosody rate pitch volume> real rate, pitch and gain changes on that passage
<emphasis level="strong"> delivery directive on that passage
<lang xml:lang="de-CH-bern"> switches language and dialect mid-text
<mark name="x"/> returns the offset of that point in marks
<p> <s> paragraph and sentence pauses

say-as with digits or telephone speaks Swiss numbers the way our phone agents do: dialect digit words and 3-3-2-2 grouping, so +41 31 533 22 02 in Bernese becomes "null drüü eis, füf drüü drüü, zwöi zwöi, null zwöi".

Elements that are not supported are rejected by name with an explanation in error.detail, never silently ignored. <audio> and <phoneme> are refused deliberately; use <sub alias> to respell a word. Call GET /capabilities for the authoritative list.

Billed in produced audio seconds, measured to the second, with no minimum per request.

Request body · application/json · SynthesisRequest

FieldTypeDescription
model"studio" | "swift"

Speech synthesis model:

  • studio (default): State-of-the-art expressive voice engine with authentic Swiss German dialect translation and nuanced prosody.
  • swift: Ultra-low latency engine optimized for real-time conversational streaming and telephony.
default "studio"
textrequiredstring

The text to speak. Rendered verbatim; never interpreted as an instruction.

max 8000 chars
voicestring

Voice id from GET /tts/voices.

default "anna"
languagestring

Language code. de-CH-zurich is accepted as a compact language+dialect form.

default "de-CH"
dialectstring

Variety within the language. GET /capabilities lists the dialects of every language, each with a status (verified or supported). The hand-tuned Swiss German (de-CH) dialects are:

  • standard: supra-regional Swiss German (default).
  • zurich: Zurich dialect (Züritüütsch).
  • bern: Bernese dialect (Bärndütsch).
  • basel: Basel dialect (Baaseldütsch).
  • luzern: Lucerne dialect (Lozärnerdütsch). Both models render the text INTO the dialect, so it may be written in Standard German: swift does it in real time, studio with the highest fidelity for prepared audio. Further de-CH values: hochdeutsch - Swiss High German, spoken word for word - and more regions (stgallen, aargau, graubuenden, wallis, ...). Other languages have accents of their own, for example fr-CH + geneve or en-GB + scottish.
default "standard"
speednumber

Speaking rate multiplier (0.5 = half speed, 1.0 = normal pace, 2.0 = double speed).

default 1 · min 0.5 · max 2
stylestring

Free-text delivery prompt (up to 600 chars) steering tone, emotion, and pacing. Examples:

  • "freundlich, warm und einladend"
  • "ruhig und geduldig, kurze Pausen nach jedem Satz"
  • "professionell und sachlich, klare Aussprache" Steers delivery only; the spoken content always renders the text verbatim.
max 600 chars
format"wav" | "mp3" | "opus" | "pcm16" | "mulaw" | "alaw"
default "mp3"
sample_rate_hzinteger

Output sample rate. Permitted values depend on format.

output"audio" | "json"

audio returns the raw bytes, json a base64 envelope with metadata.

default "audio"

Responses

StatusDescription
200

Synthesised audio. Body is the raw audio unless output: "json".

Schema: file
400

Invalid parameters (unknown voice, language, dialect, format or speed)

Schema: Error
401

Authentication required

Schema: Error
413

Text exceeds the length limit

Schema: Error
429

Rate limit, daily audio-seconds budget, or concurrency ceiling. tts.rate_limited for the first two, tts.capacity for the third; error.detail names the ceiling. Honour Retry-After.

Schema: Error
503

Service temporarily unavailable

Schema: Error
504

Request timed out

Schema: Error
WS/tts/streamSynthesise speech from text (realtime, WebSocket)

wss://api.suisse-speech.ch/v1/tts/stream

Open a socket, push text as it becomes available, receive audio while the rest of the text is still being written. Lower time-to-first-audio than batch, and the right mode when the text comes from a live source.

Authenticate with the X-API-Key request header, or — from a browser, which cannot set handshake headers — with the subprotocol field: Sec-WebSocket-Protocol: suisse.v1, key.<api key>.

{"type":"session.start","model":"swift","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"}

Add "transport":"binary" to session.start to receive audio as raw binary WebSocket frames instead of base64 inside JSON — a third fewer bytes and no decode step. Control frames stay JSON, so a binary frame is always audio, in order, in the encoding session.ready names. The default is json, so existing clients are unaffected.

Text is synthesised segment by segment at sentence boundaries. Send text.flush to force a partial segment out without ending the session. A text.append whose content is a complete <speak> document is expanded into passages immediately, so markup works in this mode too.

{"type":"session.ready","request_id":"...","voice":"anna","language":"de-CH",
 "dialect":"zurich","encoding":"pcm16","sample_rate_hz":24000,"frame_bytes":4096}
{"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}}
{"type":"error","error":{"code":"tts.unavailable","message":"...","request_id":"..."}}

Audio frames are a fixed frame_bytes in size apart from the final one. Concatenate the decoded data values in seq order to reconstruct the stream.

Responses

StatusDescription
101

Switching Protocols

401

Authentication required

GET/tts/voicesList voices, languages and audio formats

https://api.suisse-speech.ch/v1/tts/voices

The voice catalogue on its own, for clients that only need to populate a picker. A subset of GET /capabilities.

Responses

StatusDescription
200

Voice catalogue

Schema: object
401

Authentication required

Schema: Error
POST/tts/prewarmPrewarm phrases - stores nothing on this service

https://api.suisse-speech.ch/v1/tts/prewarm

On this service synthesised audio is processed in memory and not stored, so prewarming stores nothing: every phrase comes back skipped, and nothing is synthesised or billed. The endpoint stays for compatibility.

Needs a live key: a sandbox key never reaches the engine, so there would be nothing to warm.

Request body · application/json

FieldTypeDescription
model"studio" | "swift"

Speech model to prewarm (studio or swift).

default "studio"
phrasesrequiredstring[]

The passages to synthesise ahead of time.

voicestring
default "anna"
languagestring
default "de-CH"
dialectstring
default "standard"
speednumber
default 1
stylestring

Responses

StatusDescription
200

What was warmed

Schema: object
400

No phrases, too many phrases, or a sandbox key

429

Rate limited or allowance exhausted

POST/sttTranscribe an audio file

https://api.suisse-speech.ch/v1/stt

Sync transcription for short audio (≤ 25 MB, ≤ 5 min). Pass audio as multipart/form-data with field audio. Optional fields: lang (default de-CH), vocabulary (JSON array of up to 200 strings to bias recognition).

Multilingual recognition

lang takes one language code, several candidates separated by commas (de-CH,fr-CH,en), or auto (short for de-CH,fr-CH,it,en). With more than one candidate the spoken language is detected automatically, the transcript is written in that language, and the result reports it in lang. The reported value is always one of the candidates given, and is accepted unchanged as language by POST /tts and /tts/stream. Name only the languages you expect: fewer candidates means a steadier result on short utterances.

A candidate may carry a region or a dialect (fr-CH, de-CH-zurich) and is reported back exactly so, which lets the choice of dialect travel with the code. Recognition reports the language, not the dialect that was spoken.

Swiss German dialects and Standard German are both recognised under de-CH and are written in Standard German.

Request body · multipart/form-data

FieldTypeDescription
audiorequiredfile

PCM16 16kHz mono WAV is recommended. WAV / Opus / FLAC accepted.

langstring

One code, comma-separated candidates (de-CH,fr-CH,en) or auto. See "Multilingual recognition" above.

default "de-CH"
vocabularystring

Terms to bias recognition towards - names, places, product words. Either a JSON array of strings or a comma-separated list; at most 200 terms of 100 characters each. A value that is neither is refused with 400 rather than ignored.

Responses

StatusDescription
200

Transcript

Schema: Transcript
400

Invalid request

Schema: Error
401

Authentication required

Schema: Error
413

Audio too large

Schema: Error
415

Unsupported audio format

Schema: Error
429

Rate limited

Schema: Error
503

Service temporarily unavailable

Schema: Error
WS/stt/streamStreaming transcription (WebSocket)

wss://api.suisse-speech.ch/v1/stt/stream

WebSocket endpoint at wss://api.suisse-speech.ch/api/v1/stt/stream. Upgrade with the X-API-Key header (or ?api_key=sv_... query param).

{"type":"config","lang":"de-CH","vocabulary":["..."]}     // first message
{"type":"audio.append","data":"<base64 PCM16 16kHz mono>"} // chunks
{"type":"audio.end"}                                       // signal end

Binary frames are also accepted as raw PCM16 audio after config.

{"type":"session.ready","request_id":"..."}
{"type":"transcript.partial","text":"...","words":[...],"lang":"de-CH","duration_s":1.2}
{"type":"transcript.final","text":"...","words":[...],"lang":"de-CH","duration_s":3.4}
{"type":"session.complete","request_id":"..."}
{"type":"error","code":"stt.upstream_unavailable","message":"...","request_id":"..."}

Partial events are emitted on a fixed 250 ms cadence.

Multilingual recognition

lang in config takes one code, comma-separated candidates ("de-CH,fr-CH,en") or "auto", exactly as on POST /stt. Every transcript.partial and transcript.final then carries the language detected for that stretch of speech in lang, so a change of language during a session is visible as it happens.

Responses

StatusDescription
101

Switching Protocols

401

Authentication required

GET/jobsList recent jobs for this key

https://api.suisse-speech.ch/v1/jobs

Parameters

NameTypeDescription
limitinteger · query

Responses

StatusDescription
200

Jobs, newest first

Schema: object
POST/jobsSubmit an asynchronous synthesis job

https://api.suisse-speech.ch/v1/jobs

For text long enough that holding a connection open for the whole synthesis is the wrong shape. Acknowledged in milliseconds; the audio is collected later from /jobs/{id}/audio.

Everything is validated at submission, so a bad voice or malformed markup is a 400 here rather than a failure discovered later.

Results are kept for 48 hours. Up to 200 jobs may be queued per key. Jobs queue behind interactive traffic and are metered identically.

Request body · application/json

Responses

StatusDescription
202

Accepted

Schema: Job
400

Invalid parameters

Schema: Error
401

Authentication required

Schema: Error
429

Rate limit, or too many jobs already queued

Schema: Error
GET/jobs/{id}Job status, and the result when it has finished

https://api.suisse-speech.ch/v1/jobs/{id}

Parameters

NameTypeDescription
idrequiredstring · path

Responses

StatusDescription
200

Job

Schema: Job
400

No such job

Schema: Error
GET/jobs/{id}/audioCollect the audio of a finished synthesis job

https://api.suisse-speech.ch/v1/jobs/{id}/audio

Parameters

NameTypeDescription
idrequiredstring · path

Responses

StatusDescription
200

The audio

Schema: file
400

Not finished, not found, or the result has expired

Schema: Error
GET/capabilitiesDiscover everything the speech API accepts

https://api.suisse-speech.ch/v1/capabilities

Runtime discovery. Returns every voice, language, dialect, audio format, parameter range and error code the service accepts, plus the calling key's own quota for the current day.

Read this instead of hard-coding values: a new voice or language appears here without any client change.

Responses

StatusDescription
200

Capability document

Schema: Capabilities
401

Authentication required

Schema: Error
GET/usageWhat this key has consumed

https://api.suisse-speech.ch/v1/usage

Read from the billing ledger, not from the rate limiter's expiring counters, so these are the same numbers an invoice is built from, in the same unit. A customer billed by the second is entitled to reconcile continuously rather than at month end.

Sandbox traffic is reported separately and is never billed.

Parameters

NameTypeDescription
fromstring · query

Start of the window. Defaults to the start of the current month.

tostring · query

End of the window. Defaults to now.

granularity"total" | "day" · query

Add day to break the window down by day.

Responses

StatusDescription
200

Consumption for the window

Schema: object
400

Invalid window

401

Missing or invalid key

Schemas

Word
FieldTypeDescription
wrequiredstring

The word.

startrequirednumber

Start time in seconds from the audio start.

endrequirednumber

End time in seconds.

confrequirednumber

Confidence in [0,1].

min 0 · max 1
Transcript
FieldTypeDescription
textrequiredstring
langrequiredstring

Language of the transcript. When the request named several candidate languages (or auto), this is the language that was detected - always one of the candidates, and always a code that synthesis accepts as language, so it can be passed on unchanged.

e.g. "de-CH"
wordsrequiredWord[]
duration_srequirednumber

Audio duration in seconds.

Error
FieldTypeDescription
errorrequiredobject
Voice
FieldTypeDescription
idrequiredstring

Value to pass as voice.

e.g. "anna"
namerequiredstring
e.g. "Anna"
genderrequired"female" | "male" | "neutral"
timbrerequiredstring
e.g. "warm"
pacerequiredstring
e.g. "medium"
descriptionrequiredstring
best_forrequiredstring[]
languagesrequiredstring[]
Dialect
FieldTypeDescription
idrequiredstring

Value to pass as dialect.

e.g. "zurich"
namerequiredstring
e.g. "Züridütsch"
regionstring
e.g. "Zürich"
Language
FieldTypeDescription
coderequiredstring
e.g. "de-CH"
namerequiredstring
e.g. "Swiss German"
statusrequired"verified" | "supported"

verified — run and measured in production. supported — accepted by the service, no published quality figure.

dialectsrequiredDialect[]
default_dialectstring
e.g. "standard"
AudioFormat
FieldTypeDescription
idrequired"wav" | "mp3" | "opus" | "pcm16" | "mulaw" | "alaw"
mimerequiredstring
e.g. "audio/mpeg"
extensionrequiredstring
e.g. "mp3"
descriptionstring
sample_rates_hzrequiredinteger[]
default_sample_rate_hzrequiredinteger
e.g. 24000
streamablerequiredboolean
SynthesisRequest
FieldTypeDescription
model"studio" | "swift"

Speech synthesis model:

  • studio (default): State-of-the-art expressive voice engine with authentic Swiss German dialect translation and nuanced prosody.
  • swift: Ultra-low latency engine optimized for real-time conversational streaming and telephony.
default "studio"
textrequiredstring

The text to speak. Rendered verbatim; never interpreted as an instruction.

max 8000 chars
voicestring

Voice id from GET /tts/voices.

default "anna"
languagestring

Language code. de-CH-zurich is accepted as a compact language+dialect form.

default "de-CH"
dialectstring

Variety within the language. GET /capabilities lists the dialects of every language, each with a status (verified or supported). The hand-tuned Swiss German (de-CH) dialects are:

  • standard: supra-regional Swiss German (default).
  • zurich: Zurich dialect (Züritüütsch).
  • bern: Bernese dialect (Bärndütsch).
  • basel: Basel dialect (Baaseldütsch).
  • luzern: Lucerne dialect (Lozärnerdütsch). Both models render the text INTO the dialect, so it may be written in Standard German: swift does it in real time, studio with the highest fidelity for prepared audio. Further de-CH values: hochdeutsch - Swiss High German, spoken word for word - and more regions (stgallen, aargau, graubuenden, wallis, ...). Other languages have accents of their own, for example fr-CH + geneve or en-GB + scottish.
default "standard"
speednumber

Speaking rate multiplier (0.5 = half speed, 1.0 = normal pace, 2.0 = double speed).

default 1 · min 0.5 · max 2
stylestring

Free-text delivery prompt (up to 600 chars) steering tone, emotion, and pacing. Examples:

  • "freundlich, warm und einladend"
  • "ruhig und geduldig, kurze Pausen nach jedem Satz"
  • "professionell und sachlich, klare Aussprache" Steers delivery only; the spoken content always renders the text verbatim.
max 600 chars
format"wav" | "mp3" | "opus" | "pcm16" | "mulaw" | "alaw"
default "mp3"
sample_rate_hzinteger

Output sample rate. Permitted values depend on format.

output"audio" | "json"

audio returns the raw bytes, json a base64 envelope with metadata.

default "audio"
SynthesisResult
FieldTypeDescription
request_idrequiredstring
voicerequiredstring
e.g. "anna"
languagerequiredstring
e.g. "de-CH"
dialectstring
e.g. "zurich"
speednumber
e.g. 1
charactersrequiredinteger

Characters of spoken text, after markup has been expanded.

passagesinteger

Number of separately rendered passages. 1 for plain text.

cache"hit" | "partial" | "miss"

Always miss: no audio is stored on this service. Kept for compatibility.

marksobject[]

Present when the document contained elements.

audiorequiredobject
Job
FieldTypeDescription
idrequiredstring
e.g. "job_50f665b6efff3fbfb6b58fdf"
kindrequired"tts"
statusrequired"queued" | "running" | "succeeded" | "failed"
environment"live" | "sandbox"
created_atrequiredstring
started_atstring
finished_atstring
audio_secondsnumber
result_expires_atstring
audioobject

Present once the job has succeeded.

callbackobject

Delivery state, when the job carried a callback_url.

transcriptobject

Present on a finished recognition job.

errorobject
Capabilities

Runtime description of the whole service. Generated from the same catalogues the request handlers validate against, so it cannot drift from the implementation.

FieldTypeDescription
apiobject
authenticationobject
text_to_speechobject
speech_to_textobject
limitsobject
capacityobject

Concurrency ceilings this deployment enforces, and how much is in flight.

cacheobject

Synthesis cache counters. The cache is switched off on this service: no audio is stored.

usage_todayobject
errorsobject[]