# `PhoenixKitAI.OpenRouterClient`
[🔗](https://github.com/BeamLabEU/phoenix_kit_ai/blob/0.19.2/lib/phoenix_kit_ai/openrouter_client.ex#L1)

OpenRouter API client for PhoenixKit AI system.

Provides functions for interacting with the OpenRouter API, including:
- API key validation
- Model discovery (fetching available models)
- Building request headers

## OpenRouter API Reference

- Base URL: https://openrouter.ai/api/v1
- Authentication: Bearer token in Authorization header
- Optional headers: HTTP-Referer, X-Title (for rankings)

## Usage Examples

    # Validate an API key
    {:ok, %{credits: _}} = PhoenixKitAI.OpenRouterClient.validate_api_key("sk-or-v1-...")

    # Fetch available models
    {:ok, models} = PhoenixKitAI.OpenRouterClient.fetch_models("sk-or-v1-...")

# `base_url`

Returns the base URL for OpenRouter API.

# `build_headers`

Builds HTTP headers for OpenRouter API requests.

## Options
- `:http_referer` - Site URL for rankings
- `:x_title` - Site title for rankings
- `:include_usage` - Include detailed usage/cost info (default: true for completions)

# `build_headers_from_account`

Builds headers from an Account struct's settings.

# `build_headers_from_endpoint`

Builds headers from an Endpoint struct's provider_settings.

Resolves the API key by uuid lookup against `PhoenixKit.Integrations`,
falling back to the legacy `endpoint.api_key` column when the
integration row is missing or has no key.

HTTP-Referer and X-Title fall back to PhoenixKit.Settings (`site_url`
and `project_title`) when the endpoint's `provider_settings` don't
carry a non-blank override — the endpoint form treats those settings
as the source of defaults, and the per-endpoint fields as overrides.

# `embedding_models_last_updated`

Returns the date the built-in embedding model list was last refreshed.

# `extract_model_name`

Extracts the model name without provider prefix.

# `extract_provider`

Extracts the provider name from a model ID.

## Examples

    iex> extract_provider("anthropic/claude-3-opus")
    "Anthropic"

    iex> extract_provider("openai/gpt-4")
    "OpenAI"

# `fetch_embedding_models`

Fetches embedding models from OpenRouter.

Note: Embedding models are not returned by `/models`, so this function
returns a curated list maintained in source (last refreshed
`2026-03-24`) merged with any user-contributed
entries from `config :phoenix_kit_ai, :embedding_models`.

Returns `{:ok, models}` with a list of known embedding models.

# `fetch_embedding_models_grouped`

Fetches embedding models grouped by provider.

# `fetch_model`

Fetches details for a specific model by ID.

Returns `{:ok, model}` or `{:error, reason}`.

# `fetch_models`

Fetches available models from OpenRouter.

Returns `{:ok, models}` where models is a list of model objects,
or `{:error, reason}` on failure.

## Options
- `:model_type` - Filter by model type: `:text`, `:vision`, `:image_gen`, `:all` (default: `:all`)
- `:http_referer` - Site URL for rankings
- `:x_title` - Site title for rankings

## Model Object Structure

Each model has:
- `id` - Model identifier (e.g., "anthropic/claude-3-opus")
- `name` - Display name
- `description` - Model description
- `pricing` - Pricing information (prompt/completion costs)
- `context_length` - Maximum context window
- `architecture` - Model architecture details

# `fetch_models_by_type`

Fetches models by type and groups them by provider.

## Model Types
- `:text` - Text/chat completion models (text->text), excluding TTS
- `:vision` - Vision/multimodal models (text+image->text)
- `:image_gen` - Image generation models (text+image->text+image)
- `:tts` - Text-to-speech models (matched by `tts` in the id/name)
- `:all` - All models without filtering

## Examples

    {:ok, grouped} = fetch_models_by_type(api_key, :vision)

# `fetch_models_grouped`

Fetches models and groups them by provider.

## Options
- `:model_type` - Filter by model type: `:text`, `:vision`, `:image_gen`, `:tts`, `:all` (default: `:text`)

Returns a map where keys are provider names and values are lists of models.

# `fetch_voices`

Fetches available TTS voices from a Mistral-compatible `/audio/voices`
endpoint.

This is **Mistral-specific** — other providers (OpenRouter, DeepSeek)
don't expose `/audio/voices` and will return a non-200, in which case
the caller should fall back to a free-text voice field. Mistral returns
the full catalogue (~30 presets) well within a single `limit=100` page,
so no pagination loop is needed.

Returns `{:ok, [%{slug, name, language, gender, tags}]}` (the `slug` is
what `/audio/speech` accepts as its `voice`) or `{:error, reason}`.

## Options
- `:base_url` - Provider base URL (defaults to OpenRouter's, which has
  no voices endpoint — pass the endpoint's Mistral base_url).

# `fetch_xai_voices`

Fetches available voices from xAI's `GET /v1/tts/voices` — used by the
streaming voice panel (`PhoenixKitAI.Web.Playground`), not the
request/response `/audio/speech` path `fetch_voices/2` serves.

A different shape from `fetch_voices/2` entirely — a different path
(`/tts/voices`, not `/audio/voices`), a `"voices"` envelope key (not
`"items"`), and per-voice fields (`voice_id`/`name`/`language`) with no
Mistral-style gender/tags/mood grouping — so it isn't a variant of that
function, it's xAI's own endpoint with its own shape. Includes any
custom/cloned voices on the account alongside the 5 built-ins
(ara/eve/leo/rex/sal), which is exactly why this fetches live instead of
hardcoding the built-in list.

Returns `{:ok, [%{voice_id, name, language}]}` or `{:error, reason}`.

## Options
- `:base_url` - Defaults to xAI's base_url (`https://api.x.ai/v1`).

# `get_model_max_tokens`

Gets the effective max tokens for a model.

Returns the model's max_completion_tokens if available,
otherwise falls back to a percentage of context_length.

# `humanize_provider`

Converts a provider slug to a human-friendly name.

OpenRouter model IDs use slugs like "arcee-ai/model-name". This function
converts the slug portion to a human-readable provider name.

## Examples

    iex> humanize_provider("openai")
    "OpenAI"

    iex> humanize_provider("meta-llama")
    "Meta Llama"

    iex> humanize_provider("arcee-ai")
    "Arcee AI"

# `model_option`

Formats a model for display in a select dropdown.

Returns `{label, value}` tuple.

# `model_supports_parameter?`

Checks if a model supports a specific parameter.

## Examples

    iex> model_supports_parameter?(model, "temperature")
    true

    iex> model_supports_parameter?(model, "tools")
    false

# `validate_api_key`

Validates an OpenRouter API key by making a request to the /models endpoint.

Returns `{:ok, %{valid: true}}` on success, `{:error, reason}` on failure.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
