VoiceGateway // DOCS

Adding a Provider

VoiceGateway uses a provider registry pattern that makes adding new providers straightforward. Each provider is a single Python file that extends `BaseProvider`. This guide walks through the full proc

Adding a Provider

VoiceGateway uses a provider registry pattern that makes adding new providers straightforward. Each provider is a single Python file that extends BaseProvider. This guide walks through the full process.

Prerequisites

  • Development environment set up
  • Familiarity with the provider's API (SDK, auth, pricing)
  • Account with the provider for testing

10-step checklist

1. Create the provider file

Create src/voicegateway/providers/<name>_provider.py. Use an existing provider as a template (e.g., deepgram_provider.py for STT, cartesia_provider.py for TTS).

Python
"""<Provider Name> provider implementation."""

from __future__ import annotations

from typing import Any

from voicegateway.providers.base import BaseProvider


class <Name>Provider(BaseProvider):
    """<Provider Name> provider for <STT/LLM/TTS>."""

    def __init__(self, config: dict[str, Any]) -> None:
        self._api_key = config.get("api_key", "")
        # Initialize any SDK client here

    def create_stt(self, model: str, **kwargs: Any) -> Any:
        """Create an STT instance, or call self._unsupported('stt')."""
        self._unsupported("stt")

    def create_llm(self, model: str, **kwargs: Any) -> Any:
        """Create an LLM instance, or call self._unsupported('llm')."""
        self._unsupported("llm")

    def create_tts(self, model: str, voice: str | None = None, **kwargs: Any) -> Any:
        """Create a TTS instance, or call self._unsupported('tts')."""
        self._unsupported("tts")

    async def health_check(self) -> bool:
        """Check if the provider is reachable."""
        # Make a lightweight API call to verify connectivity
        return True

2. Implement the BaseProvider ABC

The BaseProvider abstract class in src/voicegateway/providers/base.py requires four methods:

MethodPurposeReturn type
create_stt(model, **kwargs)Create an STT plugin instanceLiveKit STT plugin or None
create_llm(model, **kwargs)Create an LLM plugin instanceLiveKit LLM plugin or None
create_tts(model, voice, **kwargs)Create a TTS plugin instanceLiveKit TTS plugin or None
health_check()Verify provider connectivitybool

For modalities the provider does not support, call self._unsupported("modality_name") to raise a clear error.

Pricing is not a provider-level concern. LLM, STT, and TTS rates all resolve via voice-prices (the wrappers live at src/voicegateway/pricing/{llm,stt,tts}.py). To add pricing for a new model, see step 4.

3. Register the provider

Add your provider to the registry in src/voicegateway/core/registry.py:

Python
_PROVIDER_REGISTRY: dict[str, tuple[str, str]] = {
    # ... existing providers ...
    "<name>": ("voicegateway.providers.<name>_provider", "<Name>Provider"),
}

The registry uses lazy imports -- your provider module is only loaded when a user configures it. This means optional dependencies do not break the install.

4. Add pricing data

Pricing for every modality (LLM, STT, TTS) resolves through voice-prices, so there is no VoiceGateway-side catalog entry to add. Confirm the model id resolves with the matching wrapper:

Python
from voicegateway.inference.pricing import llm, stt, tts

llm.calculate_llm_cost("<name>/<model>", 1000, 500)   # LLM
stt.calculate_stt_cost("<name>/<model>", 60)          # STT (audio seconds)
tts.calculate_tts_cost("<name>/<model>", 1000)        # TTS (characters)

If a call returns None, the model is not yet in voice-prices. Add it upstream in voice-prices (each entry carries prices_checked and pricing_source_url), publish a new voice-prices version, and bump the pin in pyproject.toml. Self-hosted models (local/*, ollama/*) price at $0 automatically and need no entry.

5. Add optional dependency

Add a new extra in pyproject.toml:

TOML
[project.optional-dependencies]
<name> = ["<sdk-package>>=1.0.0"]

# Update the cloud or local group as appropriate
cloud = ["voicegateway[deepgram,openai,...,<name>]"]

6. Add fake API key to test fixtures

In src/voicegateway/tests/conftest.py, add the key to the _test_env fixture:

Python
@pytest.fixture(autouse=True)
def _test_env(monkeypatch):
    for key in [
        # ... existing keys ...
        "<NAME>_API_KEY",
    ]:
        monkeypatch.setenv(key, "test-key-value")

7. Write tests

Create src/voicegateway/tests/test_<name>_provider.py:

Python
"""Tests for the <Name> provider."""

import pytest

from voicegateway.providers.<name>_provider import <Name>Provider


@pytest.fixture
def provider():
    return <Name>Provider({"api_key": "test-key"})


def test_create_stt(provider):
    # Test STT creation or verify it raises NotImplementedError
    ...


def test_create_llm(provider):
    ...


def test_create_tts(provider):
    ...


async def test_health_check(provider):
    # Mock the HTTP call
    ...


def test_pricing_resolves_stt(provider):
    """Pricing for a known STT model resolves to a positive Decimal via the catalog."""
    from voicegateway.pricing import catalog
    cost = catalog.calculate_cost("stt", "<name>/model-name", audio_seconds=60)
    assert cost is not None and cost > 0


# For an LLM provider, dispatch with token kwargs:
#
#     cost = catalog.calculate_cost(
#         "llm", "<name>/model-name", input_tokens=1000, output_tokens=500
#     )
#
# For a TTS provider, use character_count:
#
#     cost = catalog.calculate_cost(
#         "tts", "<name>/model-name", character_count=100
#     )

See the testing guide for mock patterns and fixture usage.

8. Update documentation

Add the provider to relevant documentation pages:

  • docs/guide/what-is-voicegateway.md -- provider list
  • docs/guide/installation.md -- extras table
  • docs/configuration/ -- config example
  • README.md -- provider count and list

9. Test the full flow

Shell
# Lint
ruff check src/voicegateway/providers/<name>_provider.py

# Type check
mypy -p voicegateway.providers.<name>_provider

# Run your tests
pytest src/voicegateway/tests/providers/test_<name>_provider.py -v

# Run the full suite to check for regressions
pytest

10. Open a PR

Create a PR with:

  • Title: feat(providers): add <Provider Name> support
  • Description: what modalities are supported, link to provider docs, pricing source
  • Checklist: all items from the contributing guide

Example: anatomy of an existing provider

Looking at the registry, VoiceGateway ships with these 11 providers:

ProviderModuleClassModalities
openaiopenai_providerOpenAIProviderSTT, LLM, TTS
deepgramdeepgram_providerDeepgramProviderSTT, TTS
anthropicanthropic_providerAnthropicProviderLLM
groqgroq_providerGroqProviderSTT, LLM
cartesiacartesia_providerCartesiaProviderTTS
elevenlabselevenlabs_providerElevenLabsProviderTTS
assemblyaiassemblyai_providerAssemblyAIProviderSTT
ollamaollama_providerOllamaProviderLLM
whisperwhisper_providerWhisperProviderSTT
kokorokokoro_providerKokoroProviderTTS
piperpiper_providerPiperProviderTTS

On this page