# How to Add Custom Providers to OmniRoute: OpenAI and Anthropic Compatible Integration

> Easily add custom providers like OpenAI and Anthropic to OmniRoute. Learn how to integrate new services seamlessly without modifying the core routing engine.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-08-24

---

**You can add custom providers to OmniRoute by registering an OpenAI-compatible or Anthropic-compatible service via the `/api/v1/providers` endpoint or the UI, which dynamically creates a provider node in [`src/lib/db/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/providers.ts) without requiring changes to the core routing engine.**

OmniRoute treats custom providers identically to built-in providers (Free, OAuth, API-Key) through a dynamic registration system. By leveraging the provider registry pattern in [[`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/open-sse/config/providerRegistry.ts), you can integrate private or third-party LLM endpoints that speak standard OpenAI or Anthropic HTTP APIs. This guide explains the complete process for adding custom providers to OmniRoute using the REST API, web interface, and JavaScript SDK.

## Understanding Custom Provider Architecture

### Provider ID Conventions

Custom providers follow a strict naming convention that triggers the dynamic provider branch. Valid provider IDs must match the pattern `openai-compatible-<name>` or `anthropic-compatible-<name>`, such as `openai-compatible-myservice`. This pattern is validated by the Zod schema in [[`src/shared/validation/schemas/routing.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/routing.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/validation/schemas/routing.ts), which allows any string ending with `-compatible-*` to bypass the static registry check.

### Registry and Database Flow

When you register a custom provider, OmniRoute executes a four-step persistence flow:

1. **Validation**: The `registerFallbackSchema` validates the provider ID and connection payload.
2. **Node Creation**: The `registerProvider` routine writes to the `providers` table via [[`src/lib/db/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/providers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/lib/db/providers.ts), creating a provider node that stores the display name, type (`apikey` or `oauth`), and metadata.
3. **Connection Storage**: Each connection (base URL, API key, headers, default model) is stored in the `provider_connections` table through the `registerConnection` helper found in [[`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/sse/handlers/chat.ts).
4. **Model Discovery**: When routing requests, the combo router calls `fetchModelsFromProvider` in [[`open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/combo.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/open-sse/services/combo.ts). If the provider is not in the static registry, it falls back to the connection's `defaultModel`—a behavior implemented in the Auto-Custom Provider fix.

## How to Add a Custom Provider via the REST API

The fastest method to add custom providers to OmniRoute is through the `/api/v1/providers` endpoint. This approach is ideal for automation and infrastructure-as-code workflows.

```bash
POST /api/v1/providers
Content-Type: application/json
Authorization: Bearer $OMNIROUTE_API_KEY

{
  "providerId": "openai-compatible-myservice",
  "displayName": "My OpenAI-compatible Service",
  "type": "apikey",
  "connections": [
    {
      "baseUrl": "https://api.myservice.com/v1",
      "apiKey": "sk-XXXXXXXXXXXXXXXXXXXX",
      "defaultModel": "gpt-4o-mini",
      "headers": {
        "Custom-Header": "value"
      }
    }
  ]
}

```

The request body is validated against the Zod schema in the routing validation module. Upon success, the provider immediately appears in the routing engine and is protected by the circuit breaker logic defined in [[`src/shared/utils/circuitBreaker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/circuitBreaker.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/utils/circuitBreaker.ts).

## How to Add a Custom Provider via the UI

For manual configuration, the OmniRoute dashboard provides a guided interface:

1. Navigate to **Settings → Provider Management**.
2. Click **Add Provider**, then select **Custom OpenAI-compatible** or **Custom Anthropic-compatible**.
3. Enter the **Provider ID** using the required pattern (e.g., `openai-compatible-myservice`).
4. Input the **Display Name**, **Base URL** (e.g., `https://api.myservice.com/v1`), and **API Key**.
5. Specify a **Default Model** to enable the Auto-Combo fallback mechanism.
6. Save the configuration. The UI invokes the same REST endpoint internally, writing the data to the provider database module.

The provider picker component (`ModelSelectModal`) utilizes [[`src/shared/components/modelSelectModalHelpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/components/modelSelectModalHelpers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/components/modelSelectModalHelpers.ts) to build the model list via `buildNodeAliasModels`, which safely handles null aliases introduced by custom providers.

## Using Custom Providers in Your Application

Once registered, route traffic to your custom provider using the standard OmniRoute SDK or CLI. The model string uses the format `<provider-id>/<model-name>`.

```typescript
import { OmniRouteClient } from "@omniroute/sdk";

const client = new OmniRouteClient({
  apiKey: process.env.OMNIROUTE_API_KEY,
});

const response = await client.chat.completions.create({
  model: "openai-compatible-myservice/gpt-4o-mini",
  messages: [{ role: "user", content: "Explain quantum tunneling." }],
  stream: true
});

console.log(response.choices[0].message.content);

```

The SDK automatically maps the model string to the custom provider node, selects the appropriate connection from the database, and applies the circuit breaker pattern to handle upstream failures.

## Key Source Files and Implementation Details

| File | Role in Custom Provider Flow |
|------|------------------------------|
| [[`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/open-sse/config/providerRegistry.ts) | Holds static provider metadata and fallback logic for `*-compatible-*` IDs. |
| [[`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/constants/providers.ts) | Enumerates built-in providers; exclusion of custom IDs triggers dynamic branch. |
| [[`src/lib/db/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/providers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/lib/db/providers.ts) | ORM-style helpers for creating, reading, and updating provider nodes and connections. |
| [[`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/sse/handlers/chat.ts) | Implements `registerConnection` to persist connection details to the database. |
| [[`open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/combo.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/open-sse/services/combo.ts) | Contains `fetchModelsFromProvider` for dynamic model discovery from custom endpoints. |
| [[`src/shared/utils/circuitBreaker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/circuitBreaker.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/utils/circuitBreaker.ts) | Provides provider-level failure detection and cooldown mechanisms. |
| [[`src/shared/components/modelSelectModalHelpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/components/modelSelectModalHelpers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/shared/components/modelSelectModalHelpers.ts) | UI helper that constructs model lists for the provider picker, handling null aliases. |

## Summary

- **Custom providers** in OmniRoute use the ID pattern `openai-compatible-<name>` or `anthropic-compatible-<name>` validated by the Zod schema in [`src/shared/validation/schemas/routing.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/routing.ts).
- **Registration** creates a provider node in [`src/lib/db/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/providers.ts) and stores connections via `registerConnection` in [`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts).
- **No code changes** are required; providers are added via the `/api/v1/providers` REST endpoint or the Settings UI.
- **Model discovery** falls back to the connection's `defaultModel` when the provider is not in the static registry, as implemented in [`open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/combo.ts).
- **Circuit breaker** protection applies automatically to custom providers through [`src/shared/utils/circuitBreaker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/circuitBreaker.ts).

## Frequently Asked Questions

### What API formats does OmniRoute support for custom providers?

OmniRoute supports **OpenAI-compatible** and **Anthropic-compatible** HTTP APIs. Your upstream service must expose endpoints matching the OpenAI `/v1/chat/completions` or Anthropic message formats. The system detects the format based on the provider ID prefix (`openai-compatible-*` vs `anthropic-compatible-*`).

### Where are custom provider credentials stored?

API keys and connection details are stored in the `provider_connections` table, accessed through the database module at [[`src/lib/db/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/providers.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/lib/db/providers.ts). Credentials are encrypted at rest and injected into request headers at runtime by the connection handler in [[`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/src/sse/handlers/chat.ts).

### How does OmniRoute handle model discovery for custom providers?

When a custom provider is selected, the combo router attempts to fetch available models from the provider's `/v1/models` endpoint. If the endpoint is unavailable or returns an error, the system falls back to the `defaultModel` specified during registration. This logic resides in [[`open-sse/services/combo.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/combo.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/open-sse/services/combo.ts) and is verified by the test suite in [[`tests/unit/auto-custom-provider-5873.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/auto-custom-provider-5873.test.ts)](https://github.com/diegosouzapw/OmniRoute/blob/release/v3.8.50/tests/unit/auto-custom-provider-5873.test.ts).

### Can I use custom providers in combo routes?

Yes. Custom providers function identically to built-in providers within combo routes. You can reference them in combo configurations using their full provider ID (e.g., `openai-compatible-myservice/gpt-4o-mini`). The routing engine treats them as valid targets for load balancing, failover, and circuit breaker policies defined in the combo service.