Cambie su base URL y ponga una clave de OrcaRouter. Sus modelos, su SDK y el resto de su código se quedan exactamente como están; lo único que se renombra son los identificadores de router openrouter/.
OrcaRouter habla de forma nativa las API de OpenAI, Anthropic y Gemini, así que usted conserva el SDK que ya usa. En cada fragmento, las líneas que empiezan por - son las que se eliminan y las que empiezan por + son las que se añaden.
client = OpenAI(
- base_url="https://openrouter.ai/api/v1",
+ base_url="https://api.orcarouter.ai/v1",
api_key=ORCAROUTER_API_KEY,
)Ese es el único cambio de código. Ponga además una clave de OrcaRouter: sus nombres de modelo, sus mensajes y el streaming se quedan igual, salvo que llame a un identificador de router openrouter/.
client = Anthropic(
+ base_url="https://api.orcarouter.ai",
api_key=ORCAROUTER_API_KEY,
)Hablamos la API de Anthropic de forma nativa, cosa que OpenRouter no hace. Si venía llamando a Claude con el SDK de OpenAI para encajar con OpenRouter, ya no hace falta.
const ai = new GoogleGenAI({
apiKey: ORCAROUTER_API_KEY,
+ httpOptions: { baseUrl: "https://api.orcarouter.ai" },
});También hablamos la API de Gemini de forma nativa, así que el SDK de Google funciona sin cambios.
Importaciones, cliente y una llamada real. Se ejecuta tal cual en cuanto ORCAROUTER_API_KEY esté definida en tu entorno.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.orcarouter.ai/v1",
api_key=os.environ["ORCAROUTER_API_KEY"],
)
response = client.chat.completions.create(
model="anthropic/claude-sonnet-4",
messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.orcarouter.ai/v1",
apiKey: process.env.ORCAROUTER_API_KEY,
});
const response = await client.chat.completions.create({
model: "anthropic/claude-sonnet-4",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content);curl https://api.orcarouter.ai/v1/chat/completions \
-H "Authorization: Bearer $ORCAROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4",
"messages": [{"role": "user", "content": "Hello"}]
}'import os
from anthropic import Anthropic
client = Anthropic(
base_url="https://api.orcarouter.ai",
api_key=os.environ["ORCAROUTER_API_KEY"],
)
message = client.messages.create(
model="anthropic/claude-sonnet-4",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://api.orcarouter.ai",
apiKey: process.env.ORCAROUTER_API_KEY,
});
const message = await client.messages.create({
model: "anthropic/claude-sonnet-4",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
console.log(message.content[0].text);curl https://api.orcarouter.ai/v1/messages \
-H "x-api-key: $ORCAROUTER_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
}'import os
from google import genai
client = genai.Client(
api_key=os.environ["ORCAROUTER_API_KEY"],
http_options={"base_url": "https://api.orcarouter.ai"},
)
response = client.models.generate_content(
model="google/gemini-2.5-pro",
contents="Hello",
)
print(response.text)import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({
apiKey: process.env.ORCAROUTER_API_KEY,
httpOptions: { baseUrl: "https://api.orcarouter.ai" },
});
const response = await ai.models.generateContent({
model: "google/gemini-2.5-pro",
contents: "Hello",
});
console.log(response.text);curl "https://api.orcarouter.ai/v1beta/models/google/gemini-2.5-pro:generateContent" \
-H "x-goog-api-key: $ORCAROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{"parts": [{"text": "Hello"}]}]
}'Usamos los mismos nombres vendor/model, así que anthropic/claude-sonnet-4 funciona tal cual. La excepción son los identificadores de router openrouter/ propios de OpenRouter: esos se renombran.
| En OpenRouter | En OrcaRouter |
|---|---|
openrouter/auto | orcarouter/auto |
openrouter/free | orcarouter/free |
| Cualquier otro router openrouter/ | Sin equivalente: indique un modelo en su lugar |
| Cualquier identificador vendor/model, como anthropic/claude-sonnet-4 | El mismo identificador, sin cambios |
Mejor saberlo ahora que descubrirlo en producción.
En la mayoría de las integraciones, sí. Cambie la base URL y sustituya su clave por una de OrcaRouter; su SDK, los nombres de modelo, los mensajes y el streaming siguen igual. Las excepciones son los identificadores de router openrouter/ propios de OpenRouter, que se renombran, y las cuatro cosas que OrcaRouter no hace a propósito, enumeradas más arriba.
El SDK de OpenAI espera https://api.orcarouter.ai/v1. Los otros dos esperan https://api.orcarouter.ai: cada uno añade su propia ruta.
El valor cambia — una clave de OpenRouter no se autentica aquí —, pero el lugar no: leemos la misma cabecera que su SDK ya envía.
Los routers de OrcaRouter son los de orcarouter/. Dos se corresponden directamente con los suyos: use orcarouter/auto en lugar de openrouter/auto, y orcarouter/free en lugar de openrouter/free; la idea es la misma en ambos casos, elegimos un modelo por usted en el momento de la petición, y el segundo le mantiene en el nivel sin coste. Sus demás routers no tienen contrapartida aquí, así que indique un modelo concreto.
Mueva models y route dentro de extra_body. Todo lo demás es igual: enumere sus modelos por orden de preferencia y los probamos uno tras otro. Al menos 2 modelos, como máximo 5. Merece la pena hacerlo bien. En el nivel superior no los leemos, así que sus respaldos dejan de funcionar en silencio; y en despliegues que reenvían el cuerpo de la petición tal cual, el modelo recibe esos campos de más y puede rechazar la llamada.
Lee X-Orca-Request-Id de la respuesta y luego llama a /v1/generation. Un 501 significa que las consultas de coste están desactivadas en este despliegue.
Envíe X-Title y su aplicación conservará su nombre en sus analíticas sin ningún cambio; también leemos los nombres de cabecera propios de OpenRouter. HTTP-Referer por sí solo únicamente nombra su aplicación si su dominio es uno de los que ya reconocemos, así que envíe una cabecera de título si quiere asegurarse. Esta fila está aquí para que no las quite por error.
No usamos ninguno de los dos. En un canal normal se descartan antes de que la petición llegue al modelo; en un canal configurado para reenviar el cuerpo en bruto se transmiten, y un proveedor estricto puede rechazar la petición. Quitarlos es lo seguro en ambos casos.
Todo lo que espera, y algunos que OpenRouter no tiene. Disponibles aquí y no en OpenRouter: /v1/messages, /v1beta/models … generateContent, /v1/rerank y /v1/realtime. No disponibles: /v1/fine-tunes, GET /v1/files y /v1/images/variations.
Los errores vuelven con la misma forma que ya maneja. Actúe según el estado HTTP: reintente un 429 cuando enviamos Retry-After, espere y reintente un 5xx salvo 501 — que significa que no servimos esa llamada en absoluto — y trate un 4xx en una llamada de relé como algo que corregir en su petición. La excepción es un 404 de /v1/generation: puede significar simplemente que la petición aún no ha liquidado, así que reinténtelo brevemente. No lea error.type como el origen: orcarouter_api_error siempre es nuestro, pero para algunos fallos propios enviamos deliberadamente el vocabulario del proveedor para que su SDK tome su rama habitual: un límite de tasa que aplicamos nosotros y uno que aplica el modelo dicen ambos rate_limit_error. Cite X-Orca-Request-Id cuando necesite que busquemos una llamada concreta.