서비스 원칙

무엇을 보장하고 무엇을 하지 않는가

MyIP OpenRouter 는 작고 의견이 뚜렷한 게이트웨이입니다. 무엇을 약속하고 무엇을 일부러 약속하지 않는지 알고 쓰면 훨씬 다루기 쉽습니다. 이 문서가 그 목록입니다.

우리가 보장하는 것

base URL 하나만 바꾸면 된다

OpenAI Chat Completions 프로토콜을 그대로 씁니다. 쓰던 OpenAI 클라이언트의 base URL 을 https://openrouter.myip.co.kr/api/v1 로, 키를 우리 키로 바꾸면 코드는 그대로 돕니다. 응답 본문은 필드 이름·중첩 구조·인코딩 규칙까지 원래 프로토콜과 같습니다 — 단가를 문자열로 직렬화하는 관행까지 포함해서요.

우리가 더한 필드(provider, usage.cost, pricing.currency)는 전부 추가일 뿐입니다. SDK 는 모르는 필드를 무시하므로, 원래 프로토콜에 맞춰 짠 클라이언트가 이 때문에 깨질 일은 없습니다.

금액은 원화뿐이다

우리가 돌려주는 모든 금액은 KRW 입니다. 1 크레딧 = 1 원입니다. 표시용으로 USD 로 환산하지 않습니다 — 표시 통화와 청구 통화가 갈리면 언젠가 누군가는 반드시 틀린 숫자로 대사를 하게 되기 때문입니다.

클라이언트가 오해할 수 없도록 세 곳에서 통화를 못박습니다.

  • 모든 /api/v1 응답의 X-MyIP-Currency: KRW 헤더
  • GET /api/v1/models 각 모델의 pricing.currency: "KRW"
  • usage.costX-MyIP-Cost-KRW — 둘 다 원 단위

과금한 모델이 곧 응답한 모델이다

폴백 체인은 업스트림 라우터에 맡기지 않고 우리가 돌립니다. 업스트림은 재시도와 폴백을 꺼 둔 상태로 씁니다. 중간 계층이 몰래 다른 곳으로 넘기면 과금한 모델과 응답한 모델이 갈라지고, 그걸 사용자가 알아챌 방법이 없기 때문입니다.

그래서 X-MyIP-ModelX-MyIP-Provider 는 추정이 아니라 사실이고, GET /api/v1/generationprovider_responses 에는 시도한 후보가 전부 남습니다.

요청 단위로 비용을 감사할 수 있다

usage.cost, X-MyIP-Cost-KRW, GET /api/v1/generationtotal_cost 는 같은 숫자입니다. 크레딧에서 실제로 차감된 금액이며, 정산 시점에 한 번 계산해 저장합니다 — 조회할 때 그동안 바뀌었을지도 모르는 단가로 다시 계산하지 않습니다.

산식은 공개되어 있습니다. 요금 계산 방식 을 보세요.

실패한 호출은 무료다

어떤 후보도 응답을 만들지 못했다면 비용 0 으로 기록하고 크레딧 원장은 건드리지 않습니다. 중간에 끊긴 스트림은 다릅니다 — 업스트림이 이미 만들어 낸 토큰은 청구합니다. 그렇지 않으면 연결을 끊는 것이 곧 무료 사용이 되기 때문입니다.

로컬이 먼저다

우리 GPU 에서 돌아가는 모델이라면 그 슬롯이 어떤 외부 provider 보다 먼저 시도됩니다. 더 싸고, 프롬프트가 우리 네트워크 밖으로 나가지 않기 때문입니다. 옵트인이 아니라 기본 동작입니다. 로컬이 지는 경우는 로컬 우선 라우팅 에 정확히 적어 두었습니다.

오류는 구체적이다

오류 형상 하나, 상태 코드와 error_type 의 짝 표 하나. 임의로 만든 코드는 없습니다.

json
{"error":{"code":404,"message":"…","metadata":{"error_type":"no_endpoints_found"}}}

error.code 는 언제나 HTTP 상태와 같습니다. 구현하지 않은 경로는 맨 404 대신 metadata.path 를 담은 404 not_supported 를 돌려줍니다. URL 을 잘못 쓴 건지 원래 없는 건지 헤매게 두지 않으려는 것입니다. 전체 표는 오류와 디버깅 에 있습니다.

우리가 일부러 하지 않는 것

모든 AI API 의 상위집합이 아니다

우리가 구현한 것은 chat completions, legacy completions, 모델 카탈로그, generation 조회, 키 관리, 크레딧, provider 목록, 그리고 몇 개의 데이터셋 엔드포인트입니다. 이게 전부이며 목록은 API 개요 에 있습니다.

임베딩, 이미지·영상·오디오 생성, 음성 인식/합성, Responses API, Batch API, 프리셋, 워크스페이스, 가드레일, BYOK, OAuth PKCE, SCIM, 관측 브로드캐스트, 컨테이너, 분류기는 구현하지 않습니다. 해당 경로는 404 not_supported 입니다. 지원하지 않는 엔드포인트 를 보세요.

마법 라우터는 없다

모델을 대신 골라 주는 오토 라우터도, 비용·품질 프론티어 선택도, 모델 융합도 없습니다. 라우팅은 요청한 그대로입니다 — models[] 체인을 provider 우선순위로 전개하고, provider{} 로 거른 것. 그 밖의 무엇도 순서를 바꾸지 않습니다.

모델 변종은 없다

:free, :nitro, :floor 같은 접미사가 없습니다. 모델 id 는 vendor/name 하나뿐이고 뜻도 하나입니다. 가장 싼 후보를 원하면 provider: { "sort": "price" } 로 명시하세요.

파라미터를 몰래 흉내 내지 않는다

우리가 소비하지 않는 파라미터는 업스트림으로 그대로 전달합니다. 업스트림이 모르는 파라미터는 거기서 떨어질 뿐, 게이트웨이가 대신 흉내 내고 그 값을 청구하지 않습니다. 실무적으로는 모델의 supported_parameters 를 확인하거나 provider: { "require_parameters": true } 로 지원하는 후보만 남기면 됩니다.

프롬프트를 몰래 고쳐 쓰지 않는다

메시지를 압축·절단·재배열하지 않습니다. transformsplugins 는 프로토콜 호환을 위해 받아들이지만 그대로 버립니다 — 메시지 변환 을 보세요. 라우팅 전용 필드(models, provider, route, transforms, plugins)를 뺀 나머지는 보낸 그대로 모델이 봅니다.

API 표면에 쿠키 인증을 섞지 않는다

/api/v1/*Authorization: Bearer 만 받습니다. SDK 가 쓰는 표면에 세션 쿠키를 섞으면 얻는 것 없이 CSRF 표면만 열립니다. 대시보드는 세션 인증을 쓰는 별도 API 를 씁니다.

설계할 때 감안할 것

  1. 잠들어 있던 로컬 모델 때문에 첫 요청이 느리거나 503 model_loading 이 날 수 있습니다. Retry-After 를 처리하거나 폴백 체인을 주세요. 로컬 GPU 모델 을 보세요.
  2. 프롬프트가 길면 응답하는 provider 가 바뀔 수 있습니다. 컨텍스트 창이 프롬프트보다 작은 로컬 후보는 보내기 전에 체인에서 빠집니다. 이게 중요하다면 X-MyIP-Provider 를 읽으세요.
  3. 크레딧이 떨어지면 키가 정지됩니다. 요청은 metadata.balance_krw 를 담은 402 insufficient_credits 를 받고, 충전하면 자동 복구됩니다. 관리자 정지는 403 key_suspended 이고 충전해도 풀리지 않습니다 — 두 코드를 나눈 것은 의도적입니다. 사용 한도와 402 를 보세요.

마지막 수정 2026. 9. 5.