openrouter-openai-compat
Switches OpenAI API integrations to OpenRouter with minimal code changes.
Install
mkdir -p .claude/skills/openrouter-openai-compat && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/5500" && unzip -o skill.zip -d .claude/skills/openrouter-openai-compat && rm skill.zipInstalls to .claude/skills/openrouter-openai-compat
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Migrate from OpenAI to OpenRouter with minimal code changes. Use whenKey capabilities
- →Configure the OpenAI SDK to use OpenRouter as a backend.
- →Access over 400 models from various providers through a single SDK interface.
- →Prefix model strings to specify providers for different models.
- →Utilize OpenRouter-specific features like model fallbacks and plugins.
- →Maintain dual compatibility between direct OpenAI and OpenRouter.
- →Attribute application usage with HTTP-Referer and X-Title headers.
How it works
The skill reconfigures the OpenAI SDK by changing the `base_url` to OpenRouter's endpoint and using an OpenRouter API key, allowing existing code to interact with OpenRouter's diverse model catalog.
Inputs & outputs
When to use openrouter-openai-compat
- →Migrating to OpenRouter
- →Implementing multi-model AI routing
- →Maintaining dual-provider compatibility
About this skill
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.
Prerequisites
- An existing OpenAI SDK integration to migrate — Python or TypeScript code calling
chat.completions.create - An OpenRouter API key exported as
OPENROUTER_API_KEY— see theopenrouter-install-authskill for setup - Python 3.8+ with the
openaipackage, or Node.js 18+ with theopenainpm package — the same SDK you already use, no new dependency - Optionally keep
OPENAI_API_KEYexported too, so the Dual-Provider Pattern can switch back to direct OpenAI
Instructions
- Apply The Two-Line Migration: point
base_urlathttps://openrouter.ai/api/v1and swapapi_keytoOPENROUTER_API_KEY; optionally add theHTTP-Referer/X-Titleheaders for app attribution. - Prefix every model string per Model ID Mapping —
gpt-4obecomesopenai/gpt-4o,o1becomesopenai/o1— and try a non-OpenAI model (anthropic/claude-3.5-sonnet) through the same client. - Confirm your feature usage against What Works Identically (streaming,
tools, JSON mode,stop,n) and adjust per What Differs — remove theorganizationparam, plan around limited embeddings, and checklogprobssupport per model via/api/v1/models. - Layer in OpenRouter-Only Features through
extra_body: ordered fallback model lists with"route": "fallback", provider preferences withsort: "price", or theplugins: [{"id": "web"}]web-search plugin. - Keep the migration reversible with the Dual-Provider Pattern —
create_client()switches between direct OpenAI and OpenRouter off theLLM_PROVIDERenvironment variable.
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"))
Output
- Standard OpenAI-SDK
ChatCompletionobjects —choices[0].message.content,usagetoken counts, andmodelreporting the provider-prefixed ID that actually served the request - The identical code path returning completions from non-OpenAI models (Claude, Gemini) with only the model string changed
- A provider-switchable client from
create_client()— flippingLLM_PROVIDERmoves traffic between direct OpenAI and OpenRouter with zero application-code changes
Examples
After the two-line change, the untouched OpenAI SDK call round-trips through OpenRouter:
client = OpenAI(base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"])
response = client.chat.completions.create(
model="openai/gpt-3.5-turbo",
messages=[{"role": "user", "content": "What is the capital of France?"}],
max_tokens=100,
)
print(response.choices[0].message.content) # The capital of France is Paris.
print(response.model) # openai/gpt-3.5-turbo
Swap the model string to anthropic/claude-3.5-sonnet and the same code returns Claude's answer — that swap is the entire multi-provider story. More worked examples: references/examples.md.
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_bodyfor OpenRouter-specific features (provider preferences, plugins, fallbacks)
References
- Examples | Errors
- OpenRouter Quickstart | API Parameters
Prerequisites
Limitations
- →The `organization` parameter is not used by OpenRouter.
- →Embeddings support is limited.
- →`logprobs` support is model-dependent.
How it compares
This approach enables access to 400+ models from all providers through the same SDK interface, unlike direct OpenAI which only provides OpenAI models.
Compared to similar skills
openrouter-openai-compat side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| openrouter-openai-compat (this skill) | 1 | 27d | Review | Intermediate |
| openai-knowledge | 5 | 4mo | No flags | Intermediate |
| openrouter-function-calling | 5 | 27d | Review | Intermediate |
| mcp-builder | 136 | 3mo | Review | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
openai-knowledge
openai
Use when working with the OpenAI API (Responses API) or OpenAI platform features (tools, streaming, Realtime API, auth, models, rate limits, MCP) and you need authoritative, up-to-date documentation (schemas, examples, limits, edge cases). Prefer the OpenAI Developer Documentation MCP server tools when available; otherwise guide the user to enable `openaiDeveloperDocs`.
openrouter-function-calling
jeremylongshore
Implement function/tool calling with OpenRouter models. Use when building agents or structured outputs. Trigger with phrases like 'openrouter functions', 'openrouter tools', 'openrouter agent', 'function calling'.
mcp-builder
anthropics
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
telegram-bot-builder
davila7
Expert in building Telegram bots that solve real problems - from simple automation to complex AI-powered bots. Covers bot architecture, the Telegram Bot API, user experience, monetization strategies, and scaling bots to thousands of users. Use when: telegram bot, bot api, telegram automation, chat bot telegram, tg bot.
stripe-integration
wshobson
Implement Stripe payment processing for robust, PCI-compliant payment flows including checkout, subscriptions, and webhooks. Use when integrating Stripe payments, building subscription systems, or implementing secure checkout flows.
langchain-architecture
wshobson
Design LLM applications using the LangChain framework with agents, memory, and tool integration patterns. Use when building LangChain applications, implementing AI agents, or creating complex LLM workflows.