Agent Skills: OpenRouter OpenAI Compatibility

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/openrouter-openai-compat

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/openrouter-pack/skills/openrouter-openai-compat

Skill Files

Browse the full folder contents for openrouter-openai-compat.

Download Skill

Loading file tree…

plugins/saas-packs/openrouter-pack/skills/openrouter-openai-compat/SKILL.md

Skill Metadata

Name
openrouter-openai-compat
Description
|

OpenRouter OpenAI Compatibility

Overview

OpenRouter implements the OpenAI Chat Completions API specification (/v1/chat/completions). Existing OpenAI SDK code works with OpenRouter by changing two values: base_url and api_key. This gives you access to 400+ models from all providers through the same SDK interface.

The Two-Line Migration

Python (Before)

from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])  # OpenAI direct
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)

Python (After)

from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",              # Changed
    api_key=os.environ["OPENROUTER_API_KEY"],              # Changed
    default_headers={
        "HTTP-Referer": "https://your-app.com",            # Added (optional)
        "X-Title": "Your App",                             # Added (optional)
    },
)
response = client.chat.completions.create(
    model="openai/gpt-4o",  # Prefix with provider namespace
    messages=[{"role": "user", "content": "Hello"}],
)

TypeScript (After)

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://openrouter.ai/api/v1",
  apiKey: process.env.OPENROUTER_API_KEY,
  defaultHeaders: { "HTTP-Referer": "https://your-app.com", "X-Title": "Your App" },
});

const res = await client.chat.completions.create({
  model: "openai/gpt-4o",
  messages: [{ role: "user", content: "Hello" }],
});

Model ID Mapping

| OpenAI Direct | OpenRouter ID | |---------------|---------------| | gpt-4o | openai/gpt-4o | | gpt-4o-mini | openai/gpt-4o-mini | | gpt-4-turbo | openai/gpt-4-turbo | | o1 | openai/o1 | | o1-mini | openai/o1-mini |

You also gain access to non-OpenAI models through the same SDK:

# Same client, any provider
response = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",  # Anthropic
    messages=[{"role": "user", "content": "Hello"}],
)

response = client.chat.completions.create(
    model="google/gemini-2.0-flash",  # Google
    messages=[{"role": "user", "content": "Hello"}],
)

What Works Identically

| Feature | Status | Notes | |---------|--------|-------| | chat.completions.create | Fully supported | Main endpoint, all parameters | | stream: true | Fully supported | SSE format identical to OpenAI | | tools / tool_choice | Supported | OpenRouter transforms for non-OpenAI providers | | response_format: { type: "json_object" } | Supported | Basic JSON mode | | response_format: { type: "json_schema" } | Supported | Strict schema mode | | temperature, top_p, max_tokens | Supported | Standard parameters | | stop sequences | Supported | Array of stop strings | | n (multiple completions) | Supported | Multiple choices |

What Differs

| Feature | Difference | Workaround | |---------|-----------|------------| | Model IDs | Prefixed with provider/ | Update model strings | | organization param | Not used | Remove from client init | | Embeddings | Limited support | Use direct provider or dedicated embedding service | | Fine-tuned models | Not directly accessible | Use provider's fine-tuned model ID if hosted | | logprobs | Model-dependent | Check model capabilities via /api/v1/models | | Responses API | Beta support | Use /api/v1/responses endpoint |

OpenRouter-Only Features

These are available through the same SDK but are unique to OpenRouter:

# Model fallbacks (try models in order)
response = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": "Hello"}],
    extra_body={
        "models": [
            "anthropic/claude-3.5-sonnet",
            "openai/gpt-4o",
            "google/gemini-2.0-flash",
        ],
        "route": "fallback",
    },
)

# Provider preferences
response = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": "Hello"}],
    extra_body={
        "provider": {
            "order": ["anthropic"],             # Prefer Anthropic direct
            "allow_fallbacks": True,
            "sort": "price",                    # Cheapest first
        },
    },
)

# Plugins (web search, response healing)
response = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "What happened today?"}],
    extra_body={
        "plugins": [{"id": "web"}],  # Enable real-time web search
    },
)

Dual-Provider Pattern

import os
from openai import OpenAI

def create_client(provider: str = "openrouter") -> OpenAI:
    if provider == "openai":
        return OpenAI(api_key=os.environ["OPENAI_API_KEY"])
    return OpenAI(
        base_url="https://openrouter.ai/api/v1",
        api_key=os.environ["OPENROUTER_API_KEY"],
        default_headers={"HTTP-Referer": "https://your-app.com"},
    )

# Switch providers without changing application code
client = create_client(os.environ.get("LLM_PROVIDER", "openrouter"))

Error Handling

| Issue | Cause | Fix | |-------|-------|-----| | 400 unsupported parameter | Model doesn't support a parameter | Conditionally set params based on model capabilities | | Different response quality | Non-OpenAI model handles prompt differently | Adjust prompts per model family; test before switching | | Missing organization | OpenRouter ignores org-level auth | Remove organization from client init |

Enterprise Considerations

  • Use environment variables to switch between direct OpenAI and OpenRouter without code changes
  • Test your full prompt suite across providers before migrating production traffic
  • Monitor response quality and latency after migration; some prompts may need tuning
  • OpenRouter normalizes the API across providers, but subtle behavioral differences exist between model families
  • Use extra_body for OpenRouter-specific features (provider preferences, plugins, fallbacks)

References