Configure OpenRouter as an OpenAI API drop-in replacement. Use when migrating from OpenAI or using OpenAI-compatible libraries. Trigger with phrases like 'openrouter openai', 'openrouter drop-in', 'openrouter compatibility', 'migrate to openrouter'.
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.
chat.completions.createOPENROUTER_API_KEY — see the openrouter-install-auth skill for setupopenai package, or Node.js 18+ with the openai npm package — the same SDK you already use, no new dependencyOPENAI_API_KEY exported too, so the Dual-Provider Pattern can switch back to direct OpenAIbase_url at https://openrouter.ai/api/v1 and swap api_key to OPENROUTER_API_KEY; optionally add the HTTP-Referer / X-Title headers for app attribution.gpt-4o becomes openai/gpt-4o, o1 becomes openai/o1 — and try a non-OpenAI model (anthropic/claude-3.5-sonnet) through the same client.tools, JSON mode, stop, n) and adjust per What Differs — remove the organization param, plan around limited embeddings, and check logprobs support per model via /api/v1/models.extra_body: ordered fallback model lists with "route": "fallback", provider preferences with sort: "price", or the plugins: [{"id": "web"}] web-search plugin.create_client() switches between direct OpenAI and OpenRouter off the LLM_PROVIDER environment variable.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"}],
)
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"}],
)
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" }],
});
| 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"}],
)
| 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 |
| 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 |
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
},
)
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"))
ChatCompletion objects — choices[0].message.content, usage token counts, and model reporting the provider-prefixed ID that actually served the requestcreate_client() — flipping LLM_PROVIDER moves traffic between direct OpenAI and OpenRouter with zero application-code changesAfter 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.
| 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 |
extra_body for OpenRouter-specific features (provider preferences, plugins, fallbacks)下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer