All articles

Engineering

How to Migrate from the ElevenLabs API with a Compatible Endpoint

A practical guide to moving an ElevenLabs API integration to KugelAudio's ElevenLabs-compatible endpoint: the SDK and code changes, voice ID and output format mapping, streaming differences, and the ElevenLabs features the compatible subset does not cover.

Viktor Presber12 min read
A stream of fine particles passes through a transparent ring that keeps its shape and flows on into a new coral-orange voice sphere, a picture of a compatible interface with a new destination
On this page

Most teams that search for an ElevenLabs API alternative already have working code: an ElevenLabs SDK client, a handful of voice IDs, an output format that matches their player or phone system, and perhaps a WebSocket that streams LLM tokens into speech. Rewriting that integration is the part nobody wants to schedule. An ElevenLabs-compatible API promises to skip it, and for the core text-to-speech path it largely can. This guide shows what actually changes when you point an ElevenLabs integration at KugelAudio's compatible endpoint, which parts of the ElevenLabs API the compatible subset does not cover, and when the native KugelAudio API is the better target.

It deliberately does not repeat the vendor comparison. If you are still deciding whether to leave ElevenLabs at all, read our ElevenLabs alternatives comparison first, then come back here for the implementation.

Key takeaways

  • KugelAudio exposes an ElevenLabs-compatible subset of the HTTP and WebSocket API at https://api.kugelaudio.com/11labs. The official ElevenLabs Python and JavaScript SDKs accept a custom base URL, so the client can stay.
  • Three things must change: the base URL and API key, the voice IDs, and the output format. ElevenLabs voice IDs do not carry over, and the default audio format differs, so set output_format explicitly.
  • Text-to-speech, streaming, the stream-input WebSocket, voice listing and model listing are covered. Voice creation and editing, history, user and subscription endpoints are documented as not supported.
  • Request fields the compatibility page does not list, such as language_code, pronunciation dictionary locators, seed or request stitching, are not part of the subset. If your product depends on them, plan the native KugelAudio API instead.
  • Compatibility covers the request shape, not the result. Voices, audio, latency and billing units still need the staged evaluation described in the comparison article before you cut over.

What does an ElevenLabs-compatible API change in your code?

It changes where requests go and which identifiers they carry, while keeping the request and response shapes your code already handles. Your ElevenLabs SDK still builds the same POST /v1/text-to-speech/{voice_id} call, sends the key in the xi-api-key header and receives audio bytes. Only the host, the key, the voice ID and ideally the output format are different.

The official SDKs make this possible because both expose a base URL option. The ElevenLabs Python SDK takes base_url in the client constructor, and the JavaScript SDK takes baseUrl. KugelAudio mounts its compatible routes under the /11labs prefix, so the SDK appends its usual /v1/... paths to that base.

Before, with ElevenLabs:

from elevenlabs import ElevenLabs

client = ElevenLabs(api_key="your-elevenlabs-key")

After, with KugelAudio:

from elevenlabs import ElevenLabs

client = ElevenLabs(
    api_key="your-kugelaudio-api-key",
    base_url="https://api.kugelaudio.com/11labs",
)

audio = client.text_to_speech.convert(
    voice_id="your-german-voice-id",
    text="Guten Tag, wie kann ich Ihnen helfen?",
    model_id="kugel-3",
    output_format="pcm_24000",
)

The Node.js change has the same shape:

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const client = new ElevenLabsClient({
  apiKey: "your-kugelaudio-api-key",
  baseUrl: "https://api.kugelaudio.com/11labs",
});

const stream = await client.textToSpeech.stream("your-german-voice-id", {
  text: "Guten Tag, wie kann ich Ihnen helfen?",
  modelId: "kugel-3",
  outputFormat: "pcm_24000",
});

For the model, pass kugel-3 directly. The compatibility layer also resolves the older ElevenLabs aliases eleven_turbo_v2, eleven_turbo_v2_5, eleven_multilingual_v1, eleven_multilingual_v2 and eleven_monolingual_v1 to Kugel 3. Newer ElevenLabs model IDs such as Flash v2.5 or v3 are not in the documented alias table, so do not leave them in configuration and assume they map. Kugel 3 is a single multilingual model covering 39 languages, with a maximum input of 10,000 characters per request.

If your traffic must stay in Europe, KugelAudio documents a direct EU endpoint, api.eu.kugelaudio.com, and applies EU endpoint selection to both REST and WebSocket traffic. Use the same /11labs path on that host and confirm it with a test request from your environment.

How do ElevenLabs voice IDs map to KugelAudio voices?

They do not map. An ElevenLabs voice ID is an identifier inside ElevenLabs, and a KugelAudio request needs a KugelAudio voice ID. Build an explicit mapping table in your configuration instead of rewriting IDs in code, so a rollback is one configuration change.

The compatible GET /v1/voices endpoint returns KugelAudio voices in the ElevenLabs catalogue shape, so the same SDK call lists them:

voices = client.voices.get_all()
for v in voices.voices:
    print(f"{v.voice_id}: {v.name}")

Choose replacements by listening to your own scripts, not by matching names or descriptions. For German, one detail matters more than it looks. KugelAudio normalizes numbers, dates and currencies in the request language, and when a request carries no language it uses the voice's primary language, the first entry of its supported_languages. The compatibility page documents no language field, so a German application on this route should use voices whose primary language is German. Otherwise "€50.99" or a date can be expanded with English rules.

A custom or cloned ElevenLabs voice cannot be exported by ID either. To recreate it you need the original reference audio, the speaker's permission and the right to use it, and a new clone in KugelAudio. The compatible POST /v1/voices/add endpoint is not supported, so create the clone in the KugelAudio dashboard or through the native SDK. The native voice API defaults a new voice to ["en"], so set supported_languages=["de"] for a German voice.

Which output format should you request?

Request one explicitly on every call. ElevenLabs documents mp3_44100_128 as the default output_format. KugelAudio's compatible endpoint returns 24 kHz PCM when neither output_format nor an Accept: audio/mpeg header is sent, and switches to mp3_44100_128 when an Accept: audio/mpeg header arrives without an output_format. Code that silently relied on the ElevenLabs default and writes the response to an .mp3 file will otherwise receive raw PCM.

KugelAudio generates audio natively at 24 kHz PCM16, so pcm_24000 has no conversion cost. Lower PCM rates are resampled on the server, MP3 is encoded on the server, and G.711 telephony formats are available directly.

Your ElevenLabs settingCompatible KugelAudio settingNote
Default (MP3, 44.1 kHz, 128 kbps)mp3_44100_128, or send Accept: audio/mpegSet it explicitly
pcm_24000pcm_24000Recommended, native rate
pcm_16000, pcm_22050, pcm_8000, pcm_44100Same tokenResampled on the server
ulaw_8000, alaw_8000Same tokenG.711 for telephony
mp3_22050_32, mp3_44100_32 to mp3_44100_192Same tokenSupported bitrates at 22.05 and 44.1 kHz
opus_48000_*, wav_*, pcm_32000, pcm_48000, mp3_24000_48Not in the documented listChoose a supported token or convert on your side

How do streaming and WebSocket integrations translate?

HTTP streaming moves over unchanged: POST /v1/text-to-speech/{voice_id}/stream is supported. The input-streaming WebSocket, /v1/text-to-speech/{voice_id}/stream-input, is supported too. You send text as it arrives from an LLM, end the stream with an empty text message, and receive frames with base64 audio and isFinal, followed by a normal close with code 1000. That close matters because the official Python SDK keeps reading until the server closes.

The behaviour behind the protocol differs in one way that affects latency. ElevenLabs clients often send flush or try_trigger_generation to push generation forward. KugelAudio's server buffer already starts synthesis at sentence boundaries, and try_trigger_generation is the default behaviour. Sending an explicit flush after every chunk is counterproductive: on KugelAudio's streaming path each flush ends a turn and the next text pays a fresh model prefill. Send tokens without flushing and end each reply once.

Two WebSocket features need attention. ElevenLabs can return character alignment data in audio frames, while the documented KugelAudio frames carry only audio and the final marker, so captions or lip-sync built on alignment need the native API's word timestamps. ElevenLabs also offers a multi-context WebSocket, multi-stream-input, which is not in the compatible endpoint list. KugelAudio's native multi-context endpoint manages up to 20 independent streams on one connection.

What does the compatible subset not cover?

The compatibility layer is deliberately a subset. It covers speech generation and the catalogue calls an integration needs to run, not the ElevenLabs platform around them. The compatibility page lists its endpoints explicitly, and anything outside that list should be treated as unavailable until you have tested it.

ElevenLabs capabilityCompatible endpointWhat to do instead
Text to speech, HTTP and streamingSupportedChange base URL, key, voice ID, format
stream-input WebSocketSupportedStop flushing per chunk
List voices, get voice, list modelsSupportedUse for voice mapping
Add or edit a voiceNot supportedClone in the KugelAudio dashboard or native SDK
History, user, subscriptionNot supportedRemove from the integration or use your own logging
stability, style, use_speaker_boostAccepted, not usedTune the voice by listening, not by these values
similarity_boostMapped to cfg_scaleNon-zero values map to 1.2 to 2.5; test your setting
language_code, seed, previous_text, next_text, pronunciation dictionary locators, apply_text_normalizationNot in the documented subsetUse native language, normalization and dictionaries
Timestamps endpoint and WebSocket alignmentNot in the documented subsetUse native word timestamps
multi-stream-input WebSocketNot in the documented subsetUse native multi-context streaming

The subset also does not cover the ElevenLabs products that sit outside text-to-speech, such as speech-to-speech, dubbing, sound effects or its conversational agents. If your integration calls those, the compatibility route only replaces part of it.

Should you use the compatible endpoint or the native KugelAudio API?

Use the compatible endpoint when the goal is to switch providers quickly with minimal code movement and your integration uses only the covered calls. Use the native API when you need the features the subset leaves out, or when you are rebuilding the voice layer anyway.

Migration routeWhat changesWhat you keepBest for
Compatible endpoint with the ElevenLabs SDKBase URL, API key, voice IDs, output formatSDK, request code, response handlingFast switch of a TTS-only integration, or a tool that only offers an ElevenLabs connector
Native KugelAudio SDK or APIClient library and request codeYour application logicExplicit language, dictionaries, word timestamps, barge-in, multi-context streaming
Provider adapter in your code, both vendors behind itOne interface for both vendorsRollback to ElevenLabs by configurationStaged rollouts, shadow traffic and canaries
Stay with ElevenLabsNothingEverythingIntegrations that depend on ElevenLabs-only products or voices

The native API also exposes the controls a German production workload tends to need: an explicit language per request, text normalization you can switch off, per-project pronunciation dictionaries, and cancellation of the current turn without closing the WebSocket for barge-in. Many teams use the compatible endpoint to get traffic flowing within a day, then move the hot path to the native SDK once they know which of these they need.

Tools that only speak ElevenLabs are a special case. Open WebUI's ElevenLabs path, for example, sends Accept: audio/mpeg and saves the response as MP3, which the compatible endpoint honours. Where a tool offers an ElevenLabs connector with a configurable base URL, the compatible endpoint is the only route. Where the connector has no base URL field, as in Cognigy's built-in ElevenLabs provider, you need the platform's custom vendor mechanism instead.

How do you validate the switch before cutover?

Treat compatibility as a way to reach the evaluation faster, not a reason to skip it. Start with a smoke test that proves the key, the host and the voice work outside your application:

curl -X POST "https://api.kugelaudio.com/11labs/v1/text-to-speech/your-german-voice-id?output_format=mp3_44100_128" \
  -H "xi-api-key: your-kugelaudio-api-key" \
  -H "Content-Type: application/json" \
  -d '{"text": "Ihre Rechnung über 49,90 Euro ist am 15. Oktober fällig.", "model_id": "kugel-3"}' \
  --output test.mp3

Then run the staged plan from the comparison article: a frozen test set from real traffic, blind listening per category, latency and error rates measured on your own connections, shadow traffic, and a canary with written rollback thresholds. Keep the provider switch in configuration until the canary passes.

Budget the cost comparison on delivered audio, not on requested characters. KugelAudio lists prices per generated minute and bills per generated second, which differs from ElevenLabs' character-based API pricing. The TTS API overview for developers compares pricing units and integration surfaces across providers.

What are the limitations of this guide?

The author works for KugelAudio. The guide describes documented API behaviour on both sides as checked on 29 September 2026; it is not an independent benchmark and makes no claim about relative voice quality or latency. The ElevenLabs API changes often, so compare your SDK version and the fields you actually send against the current references before you cut over. Behaviour outside the documented compatible subset may change without notice and should not be relied on.

FAQ

Is KugelAudio a drop-in replacement for the ElevenLabs API?

For the covered text-to-speech calls, largely yes: the ElevenLabs SDK keeps working after you change the base URL, API key, voice IDs and output format. It is not a replacement for the whole ElevenLabs platform, and voice creation, history and account endpoints are not supported.

Can I keep using the official ElevenLabs SDK?

Yes. The Python SDK accepts base_url and the JavaScript SDK accepts baseUrl. Point either at https://api.kugelaudio.com/11labs and use a KugelAudio API key.

Do my ElevenLabs voice IDs work on KugelAudio?

No. List KugelAudio voices through the compatible /v1/voices endpoint and map each ElevenLabs voice to a KugelAudio voice in configuration. A cloned voice has to be recreated from its reference audio, with the necessary rights and consent.

Why do I get PCM instead of MP3?

The compatible endpoint returns 24 kHz PCM when no output_format and no Accept: audio/mpeg header is sent, while ElevenLabs defaults to MP3. Set output_format=mp3_44100_128 or send the Accept: audio/mpeg header.

Does the stream-input WebSocket work with LLM token streaming?

Yes. Send tokens as they arrive without flushing after each one, then send an empty text message to end the stream. The server starts synthesis at sentence boundaries and closes the connection normally after the final frame.

Can I keep traffic in the EU?

KugelAudio documents a direct EU endpoint at api.eu.kugelaudio.com for REST and WebSocket traffic. Use the /11labs path on that host, confirm it with a test request, and check the rest of your processing chain separately.

Which ElevenLabs parameters are ignored?

stability, style and use_speaker_boost are accepted for compatibility but not used. similarity_boost is mapped to KugelAudio's cfg_scale. Fields the compatibility page does not list, such as language_code or pronunciation dictionary locators, are outside the documented subset.

Sources

Build with KugelAudio

Put European voice infrastructure into production.

Use the EU endpoint or discuss a customer-operated Kubernetes deployment.