Self-hosted German text-to-speech with an OpenAI- and ElevenLabs-compatible API. Point any SDK that speaks either protocol at this host and it works without code changes. Multi-engine, optimised for telephony latency.
π Interactive playground β synthesize speech in the browser, no setup.
| Method | Path | Auth | What |
|---|---|---|---|
| GET | /healthz | no | Liveness check |
| GET | /v1/models | yes | List engines + aliases |
| GET | /v1/voices | yes | List available voices |
| POST | /v1/audio/speech | yes | OpenAI TTS (batch) |
| POST | /v1/text-to-speech/{voice_id} | yes | ElevenLabs TTS (batch) |
| WS | /v1/realtime | yes | OpenAI Realtime β text in, audio chunks out |
| WS | /v1/text-to-speech/{voice_id}/stream-input | yes | ElevenLabs realtime β token-by-token text in |
| ALL | /kugel/* | yes | Kugelaudio native pass-through (REST + WebSocket) β see below |
All /v1/* endpoints require an API key (the same shared key as
the STT and LLM services). Send via either header:
Authorization: Bearer <key> # OpenAI clients
xi-api-key: <key> # ElevenLabs clients
Pass the engine in the model (OpenAI) or model_id
(ElevenLabs) field. Unknown names β including provider defaults like
tts-1 or eleven_multilingual_v2 β fall back to the
default engine. Authenticated clients can list identifiers via
/v1/models.
| Engine | Notes |
|---|---|
qwen3-tts default | Cloned Sipgate brand voice (German) |
kyutai | Lowest latency β best for realtime telephony |
omnivoice | Diffusion-LM zero-shot clone (600+ languages) |
kugelaudio | External Kugelaudio provider β dynamic voice selection (model kugel-3); see the native route below |
Select a speaker with the voice / voice_id field
(see /v1/voices). Output response_format:
pcm, wav, mp3, opus. Engines
render at 24 kHz mono; pass sample_rate (e.g. 16000) for
narrowband telephony.
Two bidirectional WebSocket surfaces stream synthesized audio back as it is
produced β playback can start after the first sentence instead of waiting for
the whole text. These are not in the Swagger/OpenAPI spec below:
OpenAPI cannot describe WebSocket endpoints. Audio frames are always
raw s16le PCM, base64-encoded. Authenticate with the same key; browser clients
that cannot set headers may pass it via the bearer.<key>
subprotocol entry or a ?api_key=/?token= query param.
WS /v1/realtime β OpenAI RealtimeClient β server (JSON): text, as one message or as deltas.
Server β client (JSON): session.created, then
response.audio.delta {"delta": "<base64 PCM>"}
frames and a final response.audio.done.
WS /v1/text-to-speech/{voice_id}/stream-input β ElevenLabs RealtimeQuery: output_format β a pcm_<rate> value resamples
the stream to that rate; non-PCM values stream at the engine's native rate.
Client β server (JSON): {"text": "β¦"} token by token, then
{"text": ""} to flush and close.
Server β client (JSON): {"audio": "<base64 PCM>"} per chunk
and a closing {"isFinal": true}.
Besides the kugelaudio engine above (which fits the unified
OpenAI/ElevenLabs surface), the full native Kugelaudio API is
proxied 1:1 under /kugel/ β authenticated with the same sipgate key,
then forwarded to the provider with its own credentials. Use this to reach
Kugelaudio features the unified surface flattens: dynamic numeric voice IDs,
word timestamps, barge-in, multi-context streaming and per-request
diffusion-step control. Strip the /kugel prefix and the rest of the
path is Kugelaudio's own:
| Method | Path | What |
|---|---|---|
| POST | /kugel/v1/tts/generate | Native synthesis β streaming PCM (24 kHz s16le) |
| GET | /kugel/v1/voices, /kugel/v1/models | Native voice / model catalogue |
| POST | /kugel/11labs/v1/text-to-speech/{voice_id} | ElevenLabs-compatible surface |
| WS | /kugel/ws/tts/stream | Single-stream realtime (word timestamps, barge-in) |
| WS | /kugel/ws/tts/multi | Multi-context realtime (up to 20 concurrent streams) |
curl -X POST https://tts.sipgate.ai/kugel/v1/tts/generate \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Guten Tag, hier ist Sipgate.", "model_id": "kugel-3", "voice_id": 963}' \
--output out.pcm
OpenAI TTS (curl β WAV):
curl -X POST https://tts.sipgate.ai/v1/audio/speech \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3-tts",
"input": "Guten Tag, hier ist Sipgate. Wie kann ich Ihnen helfen?",
"response_format": "wav"
}' --output out.wav
ElevenLabs-style (curl β PCM 16 kHz):
curl -X POST "https://tts.sipgate.ai/v1/text-to-speech/sipgate-brand?output_format=pcm_16000" \
-H "xi-api-key: $KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Ein Techniker meldet sich in KΓΌrze.", "model_id": "qwen3-tts"}' \
--output out.pcm
OpenAI Python SDK:
from openai import OpenAI
client = OpenAI(base_url="https://tts.sipgate.ai/v1", api_key=KEY)
client.audio.speech.create(
model="qwen3-tts",
voice="sipgate-brand",
input="Vielen Dank fΓΌr Ihren Anruf.",
response_format="mp3",
).stream_to_file("out.mp3")
For an interactive chat front-end that reads answers aloud via this API, see chat.sipgate.ai.