# How to Add a New AI Provider to OmniRoute: A Step-by-Step Integration Guide

> Easily add new AI providers to OmniRoute with our step-by-step guide. Learn to register identifiers, configure registries, and integrate executors for seamless AI management.

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

---

**Adding a new AI provider to OmniRoute requires registering the provider identifier in the constants file, configuring the central registry with endpoint details, wiring an executor into the factory, and exposing the provider in the dashboard UI.**

OmniRoute is an open-source AI gateway that unifies multiple LLM providers behind a single routing layer. Extending the platform to support a new AI provider involves coordinated updates across the registry in [`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts), the executor layer in `open-sse/executors/`, and the constants definition in [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts). This guide documents the complete integration workflow based on the `release/v3.8.50` branch.

## Register the Provider Identifier

Start by adding the provider’s canonical name and metadata to the shared constants. This makes the provider ID searchable throughout the codebase and available for type checking.

In [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts), extend the `PROVIDERS` object with a new entry:

```typescript
export const PROVIDERS = {
  ...DEFAULT_PROVIDERS,
  "mynewai": {
    id: "mynewai",
    name: "MyNewAI",
    category: "API_KEY",
    // Optional: oauthConfig, defaultModel, etc.
  },
};

```

The `category` field typically uses `"API_KEY"` for token-based authentication, though OAuth-based providers use different categories.

## Configure the Provider Registry

The [`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts) file serves as the single source of truth for routing, authentication schemes, and capability checks. Populate the `REGISTRY` object with the provider’s base URL, authorization header logic, and supported models:

```typescript
REGISTRY["mynewai"] = {
  baseUrl: "https://api.mynewai.com/v1",
  authHeader: (key) => ({ Authorization: `Bearer ${key}` }),
  models: ["gpt-4o", "gpt-4-mini"],
  // Optional: specify custom transformers if the API deviates from OpenAI format
  requestTransformer: "mynewaiRequest",
  responseTransformer: "mynewaiResponse",
};

```

The `authHeader` function receives the user’s API key and must return the headers required for authentication. If the provider uses a non-standard payload format, define `requestTransformer` and `responseTransformer` keys here; the implementations are registered separately.

## Implement the Executor Layer

### Choose Between Default and Custom Executors

Most OpenAI-compatible providers operate correctly with the `DefaultExecutor`. However, if the new provider requires custom header handling, special error processing, or unique request shaping, create a subclass of `BaseExecutor`.

In [`open-sse/executors/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/base.ts), the `BaseExecutor` class defines the interface:

```typescript
export abstract class BaseExecutor {
  protected abstract buildHeaders(cfg: ProviderConfig): Record<string, string>;
  abstract execute(request: Request): Promise<Response>;
}

```

Create a custom executor in a new file such as [`open-sse/executors/customProvider.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/customProvider.ts):

```typescript
import { BaseExecutor } from "./base";

export class MyNewAIExecutor extends BaseExecutor {
  protected buildHeaders(cfg) {
    const base = super.buildHeaders(cfg);
    // MyNewAI requires an additional client identifier header
    return { ...base, "X-MyNewAI-Client": cfg.clientId };
  }
}

```

### Wire the Executor into the Factory

Update [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts) to return the new executor instance when the provider ID matches:

```typescript
import { MyNewAIExecutor } from "./customProvider";

export function getExecutor(providerId: string) {
  switch (providerId) {
    case "mynewai":
      return new MyNewAIExecutor();
    // Existing cases...
    default:
      return new DefaultExecutor();
  }
}

```

The `getExecutor` factory is invoked by the routing layer to determine which execution strategy to apply for incoming requests.

## Handle Request/Response Translation

If the provider deviates from the OpenAI chat completions format, implement translator functions that convert OmniRoute’s canonical request shape into the provider’s expected payload.

In [`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts), register transformers matching the keys defined in the registry:

```typescript
export const requestTransformers = {
  ...DEFAULT_TRANSFORMERS,
  mynewaiRequest: (body) => ({
    prompt: body.messages.map((m) => m.content).join("\n"),
    temperature: body.temperature,
    max_tokens: body.max_tokens,
  }),
};

export const responseTransformers = {
  ...DEFAULT_TRANSFORMERS,
  mynewaiResponse: (raw) => ({
    choices: raw.outputs.map((text, index) => ({
      index,
      message: { role: "assistant", content: text },
    })),
  }),
};

```

These transformers ensure that requests leaving OmniRoute conform to the provider’s API contract and that responses are normalized back to the OpenAI-compatible format expected by downstream clients.

## Expose the Provider in the API

The REST route wrappers under `src/app/api/v1/providers/[provider]/` automatically pick up registry entries. Typically, no code changes are required here unless you need special endpoint behavior such as OAuth login flows.

The completions endpoint at `src/app/api/v1/providers/[provider]/chat/completions/route.ts` dynamically handles the `[provider]` parameter by looking up the registry and invoking the appropriate executor:

```typescript
// The route extracts providerId from params and delegates to the executor layer
const executor = getExecutor(providerId);
return executor.execute(request);

```

## Update the Dashboard UI

### Featured Providers List

To make the provider selectable in the "Add Provider" interface, update `src/app/(dashboard)/dashboard/providers/featuredProviders.ts`:

```typescript
export const featuredProviders = [
  ...DEFAULT_FEATURED,
  {
    id: "mynewai",
    name: "MyNewAI",
    description: "Custom AI models with specialized reasoning capabilities",
    logo: "/logos/mynewai.svg",
  },
];

```

### Provider Detail Page

Create a helper file for the provider’s configuration page. Copy an existing implementation from `src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts` and adjust the ID constant:

```typescript
// src/app/(dashboard)/dashboard/providers/mynewai/helpers.ts
export const PROVIDER_ID = "mynewai";
export const requiredFields = ["apiKey", "baseUrl"];

```

## Manage Model Catalogs

If the provider ships with unique model identifiers, ensure they appear in the global catalog. The catalog generator at [`src/app/api/v1/models/catalog.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/models/catalog.ts) pulls data directly from the `REGISTRY` object defined in [`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts).

No additional code is required beyond the registry entry, though you should verify that the `models` array in the registry accurately reflects the provider’s available endpoints.

## Database Considerations

Most providers store connection credentials in the existing `provider_connections` table, so migrations are rarely necessary. If your provider requires additional per-provider configuration tables, create a new migration in `db/migrations/`:

```bash

# Example migration file: db/migrations/0003_add_mynewai_config.sql

ALTER TABLE provider_connections ADD COLUMN client_id TEXT;

```

Run the migration script to bump the schema version before deploying.

## Testing the Integration

### Unit Tests

Add tests under [`tests/unit/providers/mynewai.test.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/tests/unit/providers/mynewai.test.ts) that mock the provider’s HTTP endpoint and verify request shaping:

```typescript
import { vi, describe, it, expect } from "vitest";

vi.stubGlobal("fetch", vi.fn().mockResolvedValue({
  ok: true,
  json: async () => ({ choices: [{ message: { content: "hello" } }] }),
}));

describe("MyNewAI Provider", () => {
  it("should transform requests to flat prompt format", async () => {
    // Assert that the executor calls fetch with the expected body structure
  });
});

```

### Integration Tests

Execute end-to-end tests by running the full route with the new provider selected:

```bash
npm run test:all

```

Verify that the CLI command `omniroute providers list` displays the new entry and that `POST /api/v1/chat/completions` routes correctly to the new provider.

## Summary

- **Register the provider** in [`src/shared/constants/providers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/providers.ts) to establish the canonical ID and category.
- **Configure the registry** in [`open-sse/config/providerRegistry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/config/providerRegistry.ts) with base URLs, auth headers, and model lists.
- **Implement executors** by extending `BaseExecutor` in `open-sse/executors/` and wiring them into the factory at [`open-sse/executors/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/executors/index.ts).
- **Add translators** in [`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts) for non-OpenAI request/response formats.
- **Update the UI** by modifying [`featuredProviders.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/featuredProviders.ts) and creating provider-specific helpers.
- **Test thoroughly** using unit mocks in `tests/unit/` and integration tests against the live API routes.

## Frequently Asked Questions

### Do I need to create a custom executor for every new provider?

No. Use the `DefaultExecutor` for any provider that follows the standard OpenAI chat completions format. Create a custom executor extending `BaseExecutor` only when the provider requires unique header injection, error handling logic, or request preprocessing that cannot be handled by the default implementation.

### How do I handle providers that don't use the OpenAI request/response format?

Implement request and response transformers in [`open-sse/translator/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/translator/index.ts). Register these functions under `requestTransformers` and `responseTransformers` using keys that match the `requestTransformer` and `responseTransformer` values defined in your registry entry. These functions normalize the payload between OmniRoute’s internal format and the provider’s native API contract.

### What database changes are required when adding a provider?

Typically none. OmniRoute uses a generic `provider_connections` table that stores encrypted credentials for all providers. Only create a new migration in `db/migrations/` if your provider requires additional relational data beyond the standard `apiKey`, `baseUrl`, and metadata fields.

### Where should I add unit tests for the new provider?

Place provider-specific unit tests in `tests/unit/providers/[providerName].test.ts`, following the pattern used for existing providers. Mock `globalThis.fetch` to simulate the provider’s API responses, and assert that the executor generates the correct request headers and body structure according to your registry configuration.