OpenRouter에서 옮기는 데는 한 줄이면 됩니다

base URL을 바꾸고 OrcaRouter 키로 교체하세요. 모델도, SDK도, 나머지 코드도 그대로 두셔도 됩니다. 이름을 바꿔야 하는 것은 openrouter/ 라우터 ID뿐입니다.

확인할 세 가지

  1. SDK에 맞는 base URL 사용하기 — OpenAI SDK에는 https://api.orcarouter.ai/v1 을, 나머지 둘에는 https://api.orcarouter.ai 을 지정하세요. 경로는 각 SDK가 알아서 붙입니다.
  2. OrcaRouter 키로 교체하세요 — 값은 바뀝니다. OpenRouter 키로는 여기서 인증되지 않습니다. 다만 위치는 그대로입니다. SDK가 이미 보내는 헤더를 그대로 읽습니다.
  3. 모델 이름 그대로 두기 — 동일한 vendor/model 이름을 사용하므로 anthropic/claude-sonnet-4를 그대로 쓸 수 있습니다. 예외는 OpenRouter 자체의 openrouter/ 라우터 ID로, 이들은 이름을 바꿔야 합니다.

변경 전과 후: 바뀌는 한 줄

OrcaRouter는 OpenAI, Anthropic, Gemini API를 기본으로 지원하므로 지금 쓰는 SDK를 그대로 쓰면 됩니다. 각 코드에서 -로 시작하는 줄은 삭제할 줄이고, +로 시작하는 줄은 추가할 줄입니다.

OpenAI — Python

  client = OpenAI(
-     base_url="https://openrouter.ai/api/v1",
+     base_url="https://api.orcarouter.ai/v1",
      api_key=ORCAROUTER_API_KEY,
  )

코드에서 바뀌는 곳은 여기뿐입니다. 키도 OrcaRouter 키로 교체하세요. 모델 이름, 메시지, 스트리밍은 그대로이며, openrouter/ 라우터 ID를 호출하는 경우만 예외입니다.

Anthropic — Python

  client = Anthropic(
+     base_url="https://api.orcarouter.ai",
      api_key=ORCAROUTER_API_KEY,
  )

저희는 Anthropic API를 직접 지원하지만 OpenRouter는 그렇지 않습니다. OpenRouter에 맞추려고 OpenAI SDK로 Claude를 호출해 왔다면 이제 그러지 않아도 됩니다.

Gemini — TypeScript

  const ai = new GoogleGenAI({
    apiKey: ORCAROUTER_API_KEY,
+   httpOptions: { baseUrl: "https://api.orcarouter.ai" },
  });

Gemini API도 직접 지원하므로 Google SDK는 수정 없이 그대로 동작합니다.

SDK별 전체 예제

임포트, 클라이언트, 실제 호출까지 한 번에. 환경 변수 ORCAROUTER_API_KEY만 설정되어 있으면 그대로 실행됩니다.

OpenAI — Python

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)

OpenAI — TypeScript

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);

OpenAI — cURL

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"}]
  }'

Anthropic — Python

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)

Anthropic — TypeScript

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);

Anthropic — cURL

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"}]
  }'

Gemini — Python

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)

Gemini — TypeScript

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);

Gemini — cURL

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"}]}]
  }'

모델 ID: 이름을 바꿔야 하는 것

동일한 vendor/model 이름을 사용하므로 anthropic/claude-sonnet-4를 그대로 쓸 수 있습니다. 예외는 OpenRouter 자체의 openrouter/ 라우터 ID로, 이들은 이름을 바꿔야 합니다.

OpenRouter에서OrcaRouter에서
openrouter/autoorcarouter/auto
openrouter/freeorcarouter/free
그 밖의 openrouter/ 라우터대응하는 라우터가 없습니다 — 모델을 직접 지정하세요
anthropic/claude-sonnet-4 같은 모든 vendor/model ID같은 ID 그대로

과금 방식의 차이

저희가 하지 않는 네 가지

운영 중에 알게 되는 것보다 지금 아는 편이 낫습니다.

자주 묻는 질문

OrcaRouter를 OpenRouter 대신 바로 쓸 수 있나요?

대부분의 연동에서는 그렇습니다. base URL을 바꾸고 OrcaRouter 키로 교체하면 SDK, 모델 이름, 메시지, 스트리밍은 그대로입니다. 예외는 이름이 바뀌는 OpenRouter 고유의 openrouter/ 라우터 ID와, 위에 정리한 OrcaRouter가 의도적으로 하지 않는 네 가지입니다.

SDK마다 어떤 base URL이 필요한가요?

OpenAI SDK에는 https://api.orcarouter.ai/v1 을, 나머지 둘에는 https://api.orcarouter.ai 을 지정하세요. 경로는 각 SDK가 알아서 붙입니다.

OpenRouter API 키를 계속 쓸 수 있나요?

값은 바뀝니다. OpenRouter 키로는 여기서 인증되지 않습니다. 다만 위치는 그대로입니다. SDK가 이미 보내는 헤더를 그대로 읽습니다.

openrouter/auto와 openrouter/free는 무엇으로 바꾸나요?

OrcaRouter의 라우터는 orcarouter/ 쪽입니다. 두 개는 저쪽과 바로 대응됩니다. openrouter/auto 대신 orcarouter/auto를, openrouter/free 대신 orcarouter/free를 쓰세요. 개념은 둘 다 같아서 요청 시점에 저희가 모델을 골라 드리고, 뒤쪽은 무료 등급을 유지해 줍니다. 나머지 라우터는 여기에 대응하는 것이 없으니 구체적인 모델을 지정하세요.

폴백 라우팅은 똑같이 동작하나요?

models와 route를 extra_body 안으로 옮기세요. 그 밖에는 모두 같습니다. 선호 순서대로 모델을 나열하면 차례로 시도합니다. 모델은 최소 2개, 최대 5개입니다. 제대로 옮길 만한 가치가 있습니다. 최상위에 두면 저희가 읽지 않아 폴백이 조용히 작동을 멈추고, 요청 본문을 그대로 전달하는 배포에서는 모델이 불필요한 필드를 받아 요청을 아예 거부할 수도 있습니다.

요청 하나에 든 비용은 어떻게 확인하나요?

응답에서 X-Orca-Request-Id를 읽은 뒤 /v1/generation을 호출하세요. 501이 오면 이 배포에서는 비용 조회가 꺼져 있는 것입니다.

X-Title과 HTTP-Referer로 계속 앱을 식별할 수 있나요?

X-Title을 보내면 분석 화면에서 앱 이름이 그대로 유지되며 바꿀 것이 없습니다. OpenRouter의 헤더 이름도 함께 읽습니다. HTTP-Referer만 보내는 경우에는 그 도메인이 저희가 이미 인식하는 목록에 있을 때만 앱 이름이 표시되므로, 확실히 하려면 제목 헤더를 보내세요. 이 항목은 실수로 지우지 않도록 적어 둔 것입니다.

요청에 있는 provider와 transforms는 어떻게 되나요?

둘 다 저희는 사용하지 않습니다. 일반 채널에서는 요청이 모델에 닿기 전에 제거됩니다. 본문을 원본 그대로 전달하도록 설정된 채널에서는 그대로 전달되며, 엄격한 업스트림은 요청을 거부할 수 있습니다. 어느 쪽이든 빼두는 편이 안전합니다.

OrcaRouter는 어떤 엔드포인트를 제공하나요?

예상하시는 것은 모두 있고, OpenRouter에 없는 것도 몇 가지 있습니다. OpenRouter에는 없고 여기에는 있는 것: /v1/messages, /v1beta/models … generateContent, /v1/rerank, /v1/realtime. 제공하지 않는 것: /v1/fine-tunes, GET /v1/files, /v1/images/variations.

오류는 같은 형식으로 돌아오나요?

오류는 지금 처리하시는 것과 같은 형태로 돌아옵니다. HTTP 상태로 판단하세요. Retry-After를 보낸 429는 재시도하고, 5xx는 백오프 후 재시도하되 501은 예외로 그 호출은 아예 제공하지 않는다는 뜻이며, 릴레이 호출의 4xx는 요청 쪽을 고쳐야 할 것으로 보세요. 예외는 /v1/generation의 404입니다. 아직 정산이 끝나지 않았다는 뜻일 수 있으니 잠깐 재시도해 보세요. error.type을 출처로 읽지 마세요. orcarouter_api_error는 언제나 저희 쪽이지만, 저희 쪽 일부 실패에는 SDK가 원래 분기를 타도록 일부러 공급자의 어휘를 보냅니다. 저희가 건 레이트 리밋과 모델이 건 레이트 리밋 모두 rate_limit_error입니다. 특정 호출을 찾아야 할 때는 X-Orca-Request-Id를 알려 주세요.