> ## Documentation Index
> Fetch the complete documentation index at: https://docs.voicegateway.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Adding a provider

# 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](/contributing/development-setup) 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 theme={null}
"""<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:

| Method                               | Purpose                       | Return type                  |
| ------------------------------------ | ----------------------------- | ---------------------------- |
| `create_stt(model, **kwargs)`        | Create an STT plugin instance | LiveKit STT plugin or `None` |
| `create_llm(model, **kwargs)`        | Create an LLM plugin instance | LiveKit LLM plugin or `None` |
| `create_tts(model, voice, **kwargs)` | Create a TTS plugin instance  | LiveKit TTS plugin or `None` |
| `health_check()`                     | Verify provider connectivity  | `bool`                       |

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 theme={null}
_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 theme={null}
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](https://github.com/mahimailabs/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 theme={null}
[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 theme={null}
@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 theme={null}
"""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](/contributing/testing) 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

```bash theme={null}
# 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](/contributing/#pr-checklist)

## Example: anatomy of an existing provider

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

| Provider   | Module                | Class                | Modalities    |
| ---------- | --------------------- | -------------------- | ------------- |
| openai     | `openai_provider`     | `OpenAIProvider`     | STT, LLM, TTS |
| deepgram   | `deepgram_provider`   | `DeepgramProvider`   | STT, TTS      |
| anthropic  | `anthropic_provider`  | `AnthropicProvider`  | LLM           |
| groq       | `groq_provider`       | `GroqProvider`       | STT, LLM      |
| cartesia   | `cartesia_provider`   | `CartesiaProvider`   | TTS           |
| elevenlabs | `elevenlabs_provider` | `ElevenLabsProvider` | TTS           |
| assemblyai | `assemblyai_provider` | `AssemblyAIProvider` | STT           |
| ollama     | `ollama_provider`     | `OllamaProvider`     | LLM           |
| whisper    | `whisper_provider`    | `WhisperProvider`    | STT           |
| kokoro     | `kokoro_provider`     | `KokoroProvider`     | TTS           |
| piper      | `piper_provider`      | `PiperProvider`      | TTS           |

## Related pages

* [Code Style](/contributing/code-style)
* [Testing](/contributing/testing)
* [Development Setup](/contributing/development-setup)
* [Contributing](/contributing/)
