개발 문서

Cafe24 LLM Router는 OpenAI SDK 호환 API를 제공합니다. 하나의 API Key로 OpenAI, Anthropic, Google, DeepSeek 등 여러 프로바이더의 모델을 사용할 수 있습니다.

Authentication

API를 호출하려면 먼저 API Key가 필요합니다.

1. API Key 발급

API 키 관리 페이지에서 키를 생성합니다. 키는 생성 시 한 번만 표시되므로 안전하게 저장하세요.

항목설명
Key 형식sk-cafe24- + 64자 hex (총 74자)
Base URLhttps://llm-router.cafe24.com
API 경로/api/v1/*
인증 방식Authorization: Bearer sk-cafe24-YOUR_KEY
적용 범위/api/v1/* 모든 엔드포인트에 필요합니다 — 모델 목록 조회(GET /api/v1/models) 포함

2. 연결 테스트

curl https://llm-router.cafe24.com/api/v1/models \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY"

Quick Start

API Key가 준비되었으면 Chat Completion을 호출합니다.

curl https://llm-router.cafe24.com/api/v1/chat/completions \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-ai/DeepSeek-V3.1", "messages": [{"role": "user", "content": "Hello!"}], "stream": true }'
from openai import OpenAI client = OpenAI( base_url="https://llm-router.cafe24.com/api/v1", api_key="sk-cafe24-YOUR_KEY", ) response = client.chat.completions.create( model="deepseek-ai/DeepSeek-V3.1", messages=[{"role": "user", "content": "Hello!"}], stream=True, ) for chunk in response: print(chunk.choices[0].delta.content or "", end="")

Auto Routing

cafe24/auto 모델을 사용하면 프롬프트를 분석하여 코딩, 추론, 번역, 창작 등 task 유형을 자동 판별하고 최적 모델을 선택합니다.

curl https://llm-router.cafe24.com/api/v1/chat/completions \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "cafe24/auto", "messages": [{"role": "user", "content": "퀵소트를 파이썬으로 구현해줘"}] }'
response = client.chat.completions.create( model="cafe24/auto", messages=[{"role": "user", "content": "퀵소트를 파이썬으로 구현해줘"}], ) print(response.model) # 실제 선택된 모델
ParameterTypeDefaultDescription
cost_quality_balancestring"balanced""quality" 품질 우선 | "balanced" 균형 | "cost" 비용 우선
model_poolstring[]null후보 모델 제한. 예: ["deepseek-ai/*", "Qwen/Qwen3*"]. 빈 배열([])은 생략과 같아 제한하지 않습니다 (Allowed Models → 전체 후보 순)

Allowed Models (Account 영구 설정)

매 요청에 model_pool을 보내는 대신, 라우팅 설정 의 Allowed Models 필드에 와일드카드 패턴을 저장하면 모든 cafe24/auto 호출에 자동 적용됩니다 (per-request model_pool이 없을 때).

적용 범위

Auto Router 관련 설정 (cost_quality_balance, model_pool, Account의 allowed_models)은 cafe24/auto 모델로 호출했을 때만 적용됩니다. 다른 모델 (Qwen/Qwen3-32B, deepseek-ai/DeepSeek-V3.1 등) 호출 시에는 무시됩니다. 계정의 Access Control 과 데이터 정책은 언제나 적용되며, 막힌 모델은 후보에서 제외됩니다.

응답

HTTP케이스응답
200정상 자동 선택응답 model에 실제 선택된 모델 ID + extra_fields.resolved_model_used 포함
400model_pool/Allowed Models 패턴이 모든 모델을 제외 (0건 매칭){"error":{"message":"No model in the requested model_pool is available for this group","type":"model_pool_no_match","code":"model_pool_no_match"}}
403계정 Access Control 이 모든 후보를 차단{"error":{"message":"No auto-router candidate is allowed by account access policy","type":"model_not_allowed","code":"model_not_allowed"}}
403데이터 정책에 맞는 후보 모델이 없음data_policy_not_allowed — 아래 데이터 정책 참조

Provider Routing

요청의 provider 객체로 프로바이더 선택을 제어합니다. 설정은 3-layer로 머지됩니다: Account < Preset < Request (request 최우선).

"provider": { "order": ["deepinfra", "siliconflow"], "allow_fallbacks": false }
FieldTypeDescription
orderstring[]프로바이더 시도 순서. 예: ["deepinfra", "siliconflow"]
onlystring[]이 프로바이더만 허용 (화이트리스트)
ignorestring[]이 프로바이더 제외 (블랙리스트)
allow_fallbacksbooleanfallback 허용. 기본 true
sortstring"price" | "throughput" | "latency"
zdrbooleantrue 면 프롬프트를 보관하지 않는(ZDR) 프로바이더로만 보냅니다 (require_zdr 도 같은 뜻). 아래 데이터 정책 참조
data_collectionstring"deny" 면 프롬프트를 학습에 쓸 수 있는 프로바이더를 제외합니다. "allow"(기본)는 아무것도 바꾸지 않습니다

API(/api/v1) 요청에서 해석되는 provider 필드는 위 표의 필드뿐입니다. max_price, require_parameters, quantizations, preferred_min_throughput, preferred_max_latency 는 지원하지 않습니다 — 함께 보내도 요청은 정상 처리되지만 해당 조건은 적용되지 않으므로, 비용 상한이 걸린 것으로 기대하고 호출하지 마세요.


정책 우선순위 (3-layer)

Provider Routing 설정은 3개 layer로 머지됩니다. Account < Preset < Request (request가 최우선).

Layer설정 위치적용 범위
AccountWeb 라우팅 설정이 사용자의 모든 요청에 우선 적용
PresetWeb 프리셋 설정 · API preset field해당 preset 사용 요청에만 적용
RequestAPI 요청 body provider 객체해당 요청 1회에만 적용

쉽게 말하면

  • Account 는 큰 울타리입니다. 사용자 본인이 Web 설정에서 정한 정책이며, 모든 요청에 항상 먼저 적용됩니다.
  • Preset 과 Request 는 그 울타리 안에서 동작합니다. Account 가 차단한 provider 는 Preset 이나 Request 에서 다시 허용할 수 없습니다.
  • "무엇만 허용한다"(only) 는 가장 좁은 범위로 좁혀지고, "무엇을 차단한다"(ignore) 는 모두 합쳐서 차단합니다. 즉 안전한 방향으로 머지됩니다.
  • "어느 순서로 시도할지"(order), "무엇 기준으로 정렬할지"(sort) 같은 단일 값은 Request 가 명시한 값이 가장 우선합니다 (없으면 Preset, 없으면 Account 순).

필드별 Merge 규칙

Account / Preset / Request 가 모두 지정되어 있을 때 각 필드별 머지 동작입니다. 한 layer 만 지정되어 있으면 그 값이 그대로 사용됩니다.

FieldMerge 방식의미
ignore합집합 (Account ∪ Preset ∪ Request)어느 layer 에서든 차단하면 차단 — 가장 엄격한 차단 정책
only교집합 (Account ∩ Preset ∩ Request)모든 layer 에서 허용한 것만 사용 — 가장 좁은 허용 범위. 교집합이 빈 set 이면 호출 차단
order상위 layer 우선 (Request > Preset > Account, 비-null 값이 있는 가장 상위 layer 채택)Request 가 명시하면 Request 값. Request 가 명시 안 했고 Preset 명시했으면 Preset 값. 둘 다 없으면 Account
sort상위 layer 우선 (동일)price / throughput / latency
data_collectionOR (어느 layer 든 deny 면 deny)프롬프트를 학습에 쓰는 프로바이더 제외 — Account 는 라우팅 설정 Access Control 1단계(데이터 정책 필터)의 데이터 학습 "학습에 사용하지 않는 프로바이더만". 요청으로 끌 수 없습니다
zdr (preset 은 require_zdr)OR (어느 layer 든 true 면 true)ZDR 강제 — Account 는 라우팅 설정 Access Control 1단계(데이터 정책 필터)의 데이터 보관 "보관하지 않는 프로바이더만". 요청으로 끌 수 없습니다
allow_fallbacksRequest layer 값 (preset/account 무시)Request 에 미명시 시 fallback 기본값 적용
max_price · require_parameters · quantizations · preferred_min_throughput · preferred_max_latency지원하지 않음보내면 오류 없이 무시됩니다

위 표는 머지 규칙이고, layer 별로 지정 가능한 필드는 다릅니다. Request layer (/api/v1 요청의 provider 객체)에서 해석되는 필드는 order·only·ignore·sort·allow_fallbacks·zdr·data_collection 7개이고(위 Provider Routing 참고), 계정 단위 설정으로 저장되는 값은 only·ignore·sort 와 Access Control 1단계의 데이터 정책(보관·학습·처리 지역)입니다.

시나리오 예시

실제 사용 상황에서 각 layer 의 설정이 어떻게 합쳐지는지 보여드립니다.

상황AccountPresetRequest최종 결과
ignore 합집합ignore=[deepinfra]ignore=[siliconflow]—ignore=[deepinfra, siliconflow]
only 교집합 — 결과 있음only=[deepinfra, siliconflow]—only=[deepinfra]only=[deepinfra]
only 교집합 — 결과 빈 setonly=[siliconflow]—only=[deepinfra]교집합 빈 set → 호출 차단 (403)
order 덮어쓰기order=[siliconflow, deepinfra]order=[deepinfra]—order=[deepinfra] (Preset 이 Account 덮어씀)
order + sort 동시 (Preset/Request 다른 필드)—order=[deepinfra]sort="price"order=[deepinfra] + sort="price" (필드별 독립 머지)
zdr ORZDR 사용 안 함require_zdr=true—ZDR 강제 (어느 한 쪽이라도 켜면 켜짐)
핵심 정리
  • Account 가 정한 정책은 절대 우회되지 않습니다.
  • Preset 과 Request 는 그 안에서 추가로 좁히거나 다른 필드를 더할 수 있을 뿐입니다.
  • 의도치 않게 차단된다면 먼저 Account 의 ignore / only 설정을 확인해보세요.

Access Control — 모델별 프로바이더 범위

라우팅 설정 의 Access Control 에서 모델을 추가하면, 칩 안에 그 모델을 제공하는 프로바이더가 버튼으로 보입니다. 버튼마다 그 프로바이더에서의 실제 결과(차단 / 허용)가 적혀 있고, 누르면 그 프로바이더에서만 바뀝니다. 모델을 추가하면 처음에는 모든 프로바이더에 적용됩니다(차단 모드는 모두 차단, 허용 모드는 모두 허용). 와일드카드 항목(anthropic/claude-*)은 패턴에 맞는 모델을 제공하는 프로바이더가 나옵니다. 프로바이더 목록에서 이미 막힌 프로바이더는 점선 버튼으로 보이고, 모델 칩에서는 풀 수 없습니다. 같은 모델에 맞는 다른 항목(예: *claude-opus-4-7)이 결과를 정하면 버튼에 * 가 붙고, 버튼에 마우스를 올리면 그 항목 이름이 보입니다 — 버튼 글자는 언제나 저장했을 때의 실제 결과입니다.

규칙은 하나입니다 — 요청이 쓸 수 있는 프로바이더 중 허용된 곳이 있으면 그곳으로 라우팅하고, 없으면 403 입니다. 이 규칙은 모든 엔드포인트에 적용됩니다 — 채팅(/v1/chat/completions·/v1/messages·/v1/responses)뿐 아니라/v1/embeddings, /v1/images/*, /v1/audio/*, /v1/rerank, /v1/videos/generations, /v1/systemone 도 같습니다. 차단한 짝은 폴백·재시도를 포함해 어떤 경우에도 호출하지 않습니다. 단, BYOK(본인 키) 호출에는 프로바이더 범위가 적용되지 않습니다 — 범위를 고르지 않은 모델 항목은 BYOK 호출에도 그대로 적용됩니다.

요청예: anthropic/claude-opus-4-7 을 deepinfra 에서만 차단
프로바이더를 지정하지 않음deepinfra 를 빼고 남은 프로바이더(예: tencent)로 호출
provider.only: ["deepinfra", "tencent"]tencent 로 호출 (고른 곳 중 허용된 곳)
provider.order: ["deepinfra", "tencent"]tencent 로 호출 (순서의 앞이 막혀 있으면 다음 허용된 곳)
provider.only: ["deepinfra"]403 model_not_allowed (고른 곳이 모두 차단)
cafe24/autoAuto Router 가 막힌 짝을 고르지 않음. 위 규칙이 그대로 적용됨

데이터 정책 — 보관(ZDR)·프롬프트 학습·처리 지역

라우팅 설정의 Access Control 1단계 "데이터 정책 필터" 에서, 프로바이더가 프롬프트를 보관하는지(ZDR)·학습에 쓰는지·어느 지역에서 처리하는지에 따라 호출할 곳을 한 번에 정합니다. 판정 기준은 관리자가 관리하는 프로바이더·모델별 데이터 정책이며, 모델 화면의 프로바이더 표에 배지(보관 안 함 / 보관함 / 학습에 씀 / 보관 미확인 / 학습 미확인 / 미확인)로 보입니다. Access Control 2단계(프로바이더·모델 제한)와 함께 적용되어, 둘 다 통과한 프로바이더로만 보냅니다.

설정동작
데이터 보관 — 보관하지 않는 프로바이더만프롬프트를 보관하지 않는 것(ZDR)이 확인된 프로바이더로만 보냅니다. 모든 모델에 적용됩니다 — 보관하는 곳과 보관 여부가 확인되지 않은 곳은 제외됩니다
데이터 학습 — 학습에 사용하지 않는 프로바이더만프롬프트를 학습에 쓰지 않는 것이 확인된 프로바이더로만 보냅니다
데이터 처리 제한 지역추가한 국가에서 데이터를 처리하는 프로바이더로는 보내지 않습니다. 여러 지역에서 처리하는 프로바이더는 그 중 하나라도 제한 국가면 쓰지 않습니다(어느 지역에서 처리될지 정할 수 없기 때문). 계정 설정으로만 정합니다
정책을 모르는 프로바이더지키지 않는 것으로 보고 제외합니다 — 보관 여부를 모르면 보관하는 것으로, 학습 여부를 모르면 학습하는 것으로, 처리 지역을 모르면 제한 국가에서 처리하는 것으로 봅니다
요청 단위provider.zdr: true · provider.data_collection: "deny" 로 이 요청에만 켤 수 있습니다. 계정 설정과 OR 로 합쳐지며, 요청으로 계정 설정을 끌 수는 없습니다. preset 에는 require_zdr: true · data_collection: "deny" 로 저장합니다
BYOKBYOK 키로 호출하는 요청에도 같은 조건으로 적용됩니다 — 등록한 프로바이더의 정책 정보가 확인되지 않았으면 그 키로는 호출되지 않습니다
적용 범위모든 엔드포인트(chat·messages·responses·embeddings·images·audio·rerank·System One)와 폴백·재시도·cafe24/auto
프로바이더 밖으로 나가는 기능같은 조건으로 판정합니다. 시맨틱 캐시는 메시지를 OpenAI 임베딩 API 로 보내므로, 조건에 맞지 않으면 캐시를 찾지도 저장하지도 않습니다(응답은 그대로). 외부 웹 검색(Exa)은 검색 엔진의 보관·학습 정책이 확인되지 않아, 조건이 걸리는 요청이 웹 검색을 쓰면 403 입니다 — 모델 자체 웹 검색(native)은 그 프로바이더의 정책으로 판정합니다. 체험하기의 웹 검색·Deep Research 도 같습니다
맞는 프로바이더가 없을 때403 data_policy_not_allowed (/v1/messages 는 Anthropic 오류 형식이라 error.type 이 permission_error). cafe24/auto 도 같습니다. 메시지에 적용된 설정과, 정책이 확인되지 않은 프로바이더는 제외한다는 안내가 적힙니다
{
  "model": "anthropic/claude-opus-4-7",
  "messages": [{ "role": "user", "content": "..." }],
  "provider": { "zdr": true, "data_collection": "deny" }
}

모든 라우팅 설정의 우선순위 — 한눈에

Provider 객체 머지 외에도 모델 선택, 화이트리스트, BYOK, 키 선택, 캐시 등 다양한 설정이 서로 다른 위치에서 결정됩니다.
각 설정이 어디서 정해지고, 충돌 시 무엇이 이기는지를 한눈에 정리했습니다.

설정결정 위치우선순위 / 머지빈 set / 충돌 시
Model
(단일 모델)
Preset.model
· Request model
Preset 이 model 을 지정하면
Request 의 model 무시 (override)
둘 다 미지정 시 400
Models
(fallback 후보 배열)
Request models[]
· Preset.fallback_models
Request 배열 먼저 시도
→ Preset fallback_models append (dedupe)
빈 배열이면 단일 모델만 시도
Provider 객체
(12 필드)
Account
· Preset
· Request
위 "필드별 Merge 규칙" 표 참조
(필드별 합집합 / 교집합 / 덮어쓰기)
only 교집합 빈 set → 403
Suffix
(:thinking, :floor)
Request 모델명 뒤 suffix암묵 provider prefs 제공 (sort=price 등)
explicit Account/Preset/Request prefs 가 있으면 무시
(빈 필드만 채움)
해당 모델이 suffix 미지원 시 무시
모델 ID 형식
(provider/model 표기)
Request model 문자열 전체/ 포함 전체가 모델 ID
(prefix 를 provider 로 해석 안 함)
미등록 모델 ID → 404 model_not_found
Allowed Models
(모델 화이트리스트)
API Key.allowed_models
· Group.allowed_models
교집합
(둘 다 허용해야 사용 가능)
NULL = 제약 없음
교집합 빈 set → 호출 거부
Auto Router
(cafe24/auto)
Account routing_config
(autoroute pool patterns)
Account 의 pool patterns 만 적용
Preset / Request override 없음
pool 빈 set → 400 model_pool_no_match
(No model in the requested model_pool is available for this group)
BYOK 키 선택User.byok_config
(사용자가 등록한 외부 provider 키)
등록된 provider 호출 시 자동 선택
Account/Preset 라우팅 설정과 무관
BYOK 복호화 실패 시 system 키로 fallback
(fail-open)
System 키 선택
(Two-Tier)
Group.provider_keys
(관리자 등록)
remaining > 0 필터
→ remaining 최다 키
→ 모두 0이면 Least-Used
Account/Preset 무관
활성 키 0개 → ProviderError
Fallback 동작Account · Preset · Request 의 allow_fallbacksRequest layer 값 사용
(Preset/Account 무시)
기본 true
401 / 403 / 인증 오류는 non-retryable
(fallback skip)
Rate Limit
(RPM/RPD)
API Key.rate_limitAPI Key 단위만
Group/Account override 없음
한도 초과 → 429
Budget
(월간 KRW/토큰)
API Key.budgetAPI Key 단위만한도 초과 → 429
(budget_exceeded_error)
Semantic CacheAdmin 강제
∧ API Key 토글
∧ 본문 저장 ON
∧ Privacy Filter(request_response_masking) OFF
∧ PII 마스킹(log_masking, 기본 ON) OFF
네 조건 모두 만족할 때만 활성
하나라도 부정이면 자동 비활성
비활성 시 cache miss 처리
(LLM 호출 진행)
Cache Sharing
(그룹 캐시 공유)
Group.cache_sharing_enabledGroup 단위 정책
API Key 토글 불가
OFF 시 API Key 별 격리 캐시만 사용
Privacy Filter
(request_response_masking)
관리자 강제 (admin endpoint)User-level 토글 불가
ON 시 본문 마스킹 + cache 자동 OFF
OFF (default) 시 원문 그대로
Body 저장
(store_request_response)
User.store_request_response
(본인 토글)
User-level
OFF 시 본문 미적재 + cache 자동 OFF
OFF 시 로그 상세에서 "(저장 안 함)"
BYOK 정책
(free_quota / fee_rate)
Admin (전역 admin_settings)모든 user 동일 적용
user 별 override 없음
월 호출수 한도 초과 시
호출 단위 fee 적용
정책 영역 구분 요약
  • 3-layer 머지 영역 (Account / Preset / Request 모두 영향)
    → Provider 객체 12 필드만 해당
  • Preset override 영역
    → Model (Preset.model 이 Request.model 우선) · Models (Request 배열 + Preset.fallback_models append)
  • API Key / Group 단위 영역 (Preset / Request 영향 없음)
    → Allowed Models, BYOK 키 선택, System 키 선택, Rate Limit, Budget, Cache Sharing
  • Account / User 단위 영역
    → Auto Router pool, Body 저장, BYOK 등록 키
  • Admin 강제 영역
    → Privacy Filter, BYOK 정책 (free_quota / fee_rate), Semantic Cache 글로벌 ON/OFF

모델 ID 형식

cafe24 LLM Router 는 모델 문자열 전체를 그대로 모델 ID 로 사용합니다. 모델 ID 에 / 가 포함돼 있어도(예: deepseek-ai/DeepSeek-V3.1) 그 전체가 하나의 모델 ID 이며,/ 앞부분을 provider 로 해석하지 않습니다. GET /api/v1/models 가 반환한 id 를 그대로model 필드에 넣으면 됩니다.

{ "model": "deepseek-ai/DeepSeek-V3.1" }

대표 모델 ID

같은 모델을 여러 프로바이더가 서로 다른 표기로 등재하기도 합니다 (예: MiniMaxAI/MiniMax-M3 와 minimax/minimax-m3). 이런 모델은 GET /api/v1/models 목록에 대표 모델 ID(author/slug, 소문자) 하나로만 실립니다. 프로바이더가 등재한 표기로 호출해도 같은 모델로 해석되므로 기존 호출은 그대로 동작합니다 (/ 가 있는 표기는 대소문자를 구분하지 않고, / 가 없는 표기는 등재된 그대로 일치해야 합니다). 어느 프로바이더가 어떤 표기로 등재했는지는 단건 조회 GET /api/v1/models/{model_id} 응답의 providers[].model_id 에 실립니다 (목록 응답에는 없습니다). Models 페이지의 모델 상세 프로바이더 목록에서도 같은 내용을 볼 수 있습니다.

Provider 선택은 provider 객체로

특정 provider 로 강제하거나 우선순위를 두려면 모델 prefix 가 아니라 위 Provider Routing 의provider 객체(order / only / ignore)를 사용합니다. 동일 모델을 여러 provider 가 제공할 때(예: deepseek-ai/DeepSeek-V3.1 은 deepinfra·siliconflow모두 제공) 그중 하나를 선택할 수 있습니다.

프로바이더가 등재한 표기로 부르는 것은 그 프로바이더를 지정하는 것이 아닙니다. / 가 들어간 표기는 대표 모델 그룹의 진입점이므로, 그 그룹을 제공하는 다른 프로바이더로 라우팅될 수 있습니다. 예를 들어 zai-org/GLM-5 로 불러도 glm-5 로 등재한 다른 프로바이더가 응답할 수 있습니다. 프로바이더를 고정하는 방법은 provider.only 뿐입니다.

{ "model": "deepseek-ai/DeepSeek-V3.1", "provider": { "only": ["siliconflow"] } // siliconflow 로 강제 }

존재하지 않는 모델

어느 프로바이더에도 등재되지 않은 모델 ID 를 호출하면 404 model_not_found 를 반환합니다. 이는 시맨틱 캐시 hit 으로도 우회되지 않습니다. 반대로 /api/v1/models 목록에 보이지 않더라도 대표 모델 ID 로 묶인 프로바이더별 등재 표기는 그대로 호출됩니다 (위 대표 모델 ID 참고).

Reserved Model ID

cafe24/auto 는 / 가 있지만 모델 ID 가 아니라 Auto Router 트리거입니다. 모델 매칭 대신 자동 선택 라우팅으로 동작합니다.

BYOK 모델 ID

BYOK(본인 키)로 호출할 때는 claude-sonnet-4-6 와 같은 형식의 prefix 없는 모델 ID 로만 호출 가능합니다. (anthropic/claude-sonnet-4-6 처럼 provider/ prefix 가 붙은 형식은 BYOK 경로에서 지원되지 않습니다.)

Fallback Chain

models 배열의 각 항목도 동일하게 모델 ID 전체로 지정합니다. 앞 모델이 실패하면 다음으로 전환됩니다.

{ "model": "deepseek-ai/DeepSeek-V3.1", "models": [ "deepseek-ai/DeepSeek-V3.1", "Qwen/Qwen3-32B", "Qwen/Qwen3-8B" ] }

Model Features

Model Suffix

모델 ID 뒤에 :suffix를 붙여 동작을 변경합니다.

SuffixExampleEffect
:floordeepseek-ai/DeepSeek-V3.1:floor가장 저렴한 프로바이더 우선
:nitrodeepseek-ai/DeepSeek-V3.1:nitro가장 빠른 프로바이더 우선
:thinkingQwen/Qwen3-32B:thinking추론 모드 활성화
:freeQwen/Qwen3-8B:free무료 프로바이더 우선 (없으면 기본 라우팅)

Model Fallback

model 필드와 함께 models 배열로 순차 시도할 모델 체인을 지정합니다. 첫 모델이 실패하면 다음 모델로 자동 전환됩니다. model 필드는 필수이며, models만 단독 사용은 불가합니다.

{ "models": ["deepseek-ai/DeepSeek-V3.1", "Qwen/Qwen3-8B", "deepseek-ai/DeepSeek-V3.2"], "messages": [{"role": "user", "content": "Hello"}] }

Sticky Routing

동일 대화를 같은 프로바이더로 라우팅하여 KV 캐시를 활용합니다. Multi-turn 대화 시 자동 적용됩니다.


Presets

프리셋은 모델 + 프로바이더 라우팅 + 샘플링 파라미터를 하나의 설정으로 묶어 재사용하는 기능입니다. 수정 시 자동으로 버전 스냅샷이 저장됩니다.

프리셋 사용 (3가지 방법)

MethodExampleDescription
@preset/"model": "@preset/fast-coding"프리셋의 모델과 설정 모두 적용
Model override"model": "Qwen/Qwen3-32B@preset/fast-coding"모델만 변경, 나머지 프리셋 적용
preset field"preset": "fast-coding"별도 필드로 프리셋 지정

요청 파라미터가 프리셋 값을 오버라이드합니다. 프리셋 설정 페이지에서 UI로 생성하거나 API로 직접 관리합니다.


Semantic Cache

동일하거나 유사한 요청에 대해 캐시된 응답을 반환하여 비용을 절감하고 응답 속도를 높입니다.

설정위치설명
API Key별 ON/OFFAPI 키 관리 페이지키별 캐시 활성화/비활성화 + 유사도 임계값 (0.70~0.99)
요청별 제어요청 body"cache": {"semantic": false}로 개별 요청 캐시 비활성화

우선순위

API Key OFF > 요청 OFF > API Key 설정 > 글로벌 기본값. API Key에서 OFF한 경우 요청에서 ON할 수 없습니다.

캐시 스코프

시맨틱 캐시는 대표 모델 ID 단위로 동작합니다. 같은 모델을 가리키는 표기는 모두 한 캐시를 공유합니다 — 대표 모델 ID 로 부르든(zai-org/glm-5), 프로바이더가 등재한 표기로 부르든 (glm-5) 같습니다. 어느 프로바이더가 응답했는지도 구분하지 않습니다.

단, provider 객체로 프로바이더를 지정한 요청은 그 프로바이더 전용 캐시를 씁니다. only · ignore · order 중 하나라도 있으면 지정으로 봅니다. 지정한 요청에는 다른 프로바이더가 만든 응답이 나가지 않으며, 지정 없는 요청의 캐시와도 섞이지 않습니다. 계정 설정(라우팅 설정)에 걸어 둔 only · ignore 도 같습니다 — 계정이 막아 둔 프로바이더의 응답이 캐시로 나가는 일은 없습니다.

요청캐시 범위
{"model": "zai-org/glm-5"}그룹 공유 (어느 프로바이더 응답이든)
{"model": "glm-5"}그룹 공유 (위와 같은 캐시)
{"model": "glm-5", "provider": {"only": ["tencent"]}}tencent 전용

대표 모델 ID 가 없는 모델(한 프로바이더만 등재한 모델 등)은 등재된 표기 단위로 동작합니다. 캐시를 아예 쓰지 않으려면 요청에 "cache": {"semantic": false} 를 넣으십시오.

모델 ID 와 캐시

  • 유효한 모델 ID → 캐시 정상 hit
  • 미등록 모델 ID (예: Qwen/Qwen3-NotExist) → 캐시 lookup 전 차단되어 404 model_not_found

즉 잘못된 모델 ID 호출이 캐시 hit 으로 silently 성공하는 일은 없습니다.

캐시 엔트리는 캐시 관리 페이지에서 조회/삭제할 수 있습니다.


Metadata

요청에 metadata를 포함하면 사용량을 팀, 프로젝트, 환경 등으로 분류하여 추적할 수 있습니다. 프로바이더에 전달되지 않으며 로그에만 저장됩니다.

curl https://llm-router.cafe24.com/api/v1/chat/completions \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "Qwen/Qwen3-8B", "messages": [{"role": "user", "content": "Hello"}], "metadata": {"team": "backend", "project": "api-server", "env": "prod"} }'
response = client.chat.completions.create( model="Qwen/Qwen3-8B", messages=[{"role": "user", "content": "Hello"}], extra_body={"metadata": {"team": "backend", "project": "api-server"}}, )

사용 현황에서 metadata key-value 조합별 사용량을 집계할 수 있습니다.


Request/Response Body 저장

계정 단위 요청/응답 본문 저장 정책을 본인이 직접 토글합니다. default OFF — 디버깅이 필요할 때만 ON 으로 변경하세요. 본문 저장 OFF 상태에서는 시맨틱 캐시도 자동 비활성화됩니다.

항목설명
적용 범위계정 단위 — 본인이 발급한 모든 API Key 에 일괄 적용
기본값OFF — 본문이 저장되지 않음. 메타데이터/토큰/비용/모델명은 정상 적재
설정 방법프라이버시 설정 페이지 상단의 “Prompt / Response 데이터 관리” 카드에서 ON/OFF 토글
관리자 강제 OFF민감 데이터/컴플라이언스 사유로 관리자가 계정 단위 비상 OFF 가능 (audit 기록)
시맨틱 캐시본문 저장 OFF 면 시맨틱 캐시도 자동 OFF (semantic_cache_entries 가 raw 본문 저장)
보관 기간 (retention)저장된 본문의 보관 일수 — 7 / 14 / 30(기본)일 중 선택. 경과 시 자동 삭제
전환 시점OFF 토글 후 최대 300초 안에 모든 키에 반영 (Redis auth cache 만료)

Privacy Filter

LLM 호출 직전 요청 내용 중 민감정보(PII)만 식별해 마스킹 후 프로바이더로 전송하는 기능입니다. 본문 저장 정책과는 독립적으로 동작하지만, 마스터 스위치가 ON 이면 시맨틱 캐시는 자동 비활성화됩니다. 프라이버시 설정 페이지에서 룰을 관리합니다.

항목설명
적용 시점LLM 호출 직전 사용자 요청 내용
처리 방식REDACT 룰: 매칭 부분만 마스킹/치환 후 전송. BLOCK 룰: 매칭 시 요청 전체를 403 guardrail_blocked 로 차단
마스터 ON/OFF관리자 강제 (request_response_masking, user 토글 불가). 단 PII 카테고리/커스텀 룰은 사용자가 직접 관리
설정 위치Privacy Filter 페이지 — 사용자가 직접 룰 추가/수정/삭제
본문 저장과 관계본문 저장 정책과는 독립 (저장 ON/OFF 무관하게 동작)
시맨틱 캐시와 관계마스터 ON 시 시맨틱 캐시 자동 OFF (마스킹된 본문은 캐시 대상 제외)

Base URL: https://llm-router.cafe24.com/api/v1

Models

GET/api/v1/models
사용 가능한 모델 목록. cafe24/auto 포함. 모델당 1개 항목(id 유일)이며, id 는 대표 모델 ID 입니다. 같은 모델을 여러 프로바이더가 서빙하면 한도(max_context_tokens/max_output_tokens)는 가장 낮은 값으로 표기하고 프로바이더별 원값은 providers 배열에 담깁니다.
GET/api/v1/models/{model_id}
단건 조회. 대표 모델 ID 로도, 프로바이더가 등재한 표기로도 조회됩니다. 슬래시가 들어간 모델 ID 는 그대로 붙입니다 (예: /api/v1/models/minimax/minimax-m3). 프로바이더별 등재 표기와 가격은 이 응답에만 실립니다.

Response — data[] 항목

FieldTypeDescription
idstring대표 모델 ID (author/slug). 목록 안에서 유일하며 호출에 그대로 씁니다. 프로바이더별 등재 표기로 불러도 같은 모델로 해석됩니다. 대표 ID 가 없는 모델은 등재된 표기 그대로입니다.
owned_bystring대표 모델 ID 의 앞부분(author). 대표 ID 가 없는 모델은 providers 사전순 첫째입니다 — 요청마다 흔들리지 않도록 한 가지로 정해 둡니다.
model_typestring모델 종류 — chat / embedding / image / tts / stt / rerank / video / music / decision. 어느 엔드포인트에 쓰는 모델인지 여기서 구분합니다. cafe24/auto 는 종류가 없어 이 필드가 빠집니다.
max_context_tokens / max_output_tokensinteger여러 프로바이더가 서빙하면 가장 낮은 값. 어느 프로바이더로 가도 통과하는 한도입니다. 미신고면 null.
supported_parametersarray그 모델이 받아들이는 파라미터. 텍스트(chat) 모델에만 실리며, 값은 서빙 프로바이더 전체의 교집합입니다 — 한 곳이라도 지원하지 않으면 빠지므로, 없다고 해서 모든 프로바이더가 미지원이라는 뜻은 아닙니다. 프로바이더별 원값은 단건 조회의 providers[].supported_parameters 에 있습니다.
providersarray프로바이더별 원값 (name, max_context_tokens, max_output_tokens) — 목록 응답에서는 이 3개뿐입니다. name 은 provider.only 에 넣는 값입니다. 등재 표기·가격 등 나머지는 아래 단건 조회에 실립니다.
{ "object": "list", "data": [ { "id": "cafe24/auto", "object": "model", "owned_by": "cafe24", "max_context_tokens": null, "max_output_tokens": null }, { "id": "minimax/minimax-m3", "object": "model", "owned_by": "minimax", "model_type": "chat", "max_context_tokens": 524288, "max_output_tokens": 131072, "supported_parameters": ["max_tokens", "temperature", "tools", ...], "providers": [ { "name": "deepinfra", "max_context_tokens": 524288, "max_output_tokens": 512000 }, { "name": "novita", "max_context_tokens": 1000000, "max_output_tokens": 131072 }, { "name": "siliconflow", "max_context_tokens": 1049000, "max_output_tokens": 262144 } ] } ] }

목록 응답에는 단가와 프로바이더별 등재 표기가 실리지 않습니다. 둘 다 아래 단건 조회 또는 Models 페이지에서 확인하세요. cafe24/auto 는 프로바이더가 정해져 있지 않아 providers 와 model_type 이 없습니다.

단건 조회 — GET /api/v1/models/{model_id}

대표 모델 ID 로 물어도, 프로바이더가 등재한 표기로 물어도 같은 모델의 상세가 옵니다. 찾는 순서는 다음과 같습니다.

순서찾는 방법
1목록의 id 와 글자까지 똑같은 항목이 있으면 그 항목
2/ 가 들어간 요청이면 앞뒤 공백을 지우고 소문자로 바꾼 뒤, 대표 모델 ID 와 그 대표 ID 로 묶인 등재 표기에서 찾습니다 (대소문자 구분 없음)
3/ 가 없는 요청이면 등재된 표기와 글자까지 똑같은 행을 찾아, 그 행이 속한 모델을 돌려줍니다
4못 찾았거나 후보가 둘 이상이어서 하나로 좁혀지지 않으면 404

응답 id 는 대표 모델 ID 입니다 (대표 ID 가 없는 모델은 등재된 표기 그대로). 나머지 필드는 목록 항목과 같고 providers 배열만 프로바이더별 상세로 넓어집니다. 같은 프로바이더가 두 표기로 등재했다면 providers 에 두 번 나오며 model_id 로 구분합니다.

{ "id": "minimax/minimax-m3", "object": "model", "owned_by": "minimax", "model_type": "chat", "max_context_tokens": 524288, "max_output_tokens": 131072, "supported_parameters": ["max_tokens", "temperature", "tools", ...], "providers": [ { "name": "deepinfra", "model_id": "MiniMaxAI/MiniMax-M3", "model_type": "chat", "max_context_tokens": 524288, "max_output_tokens": 512000, "provider_available": true, "provider_status": "healthy", "supported_parameters": ["max_tokens", "temperature", "tools", ...], "pricing": { "currency": "KRW", "unit": "per_1m_tokens", "input": 386.4, "output": 1518, "cache_read": 77.28, "is_discounted": false } }, { "name": "novita", "model_id": "minimax/minimax-m3", "model_type": "chat", "max_context_tokens": 1000000, "max_output_tokens": 131072, "provider_available": true, "provider_status": "healthy", "supported_parameters": ["max_tokens", "temperature", "tools", ...], "pricing": { "currency": "KRW", "unit": "per_1m_tokens", "input": 414, "output": 1656, "cache_read": 82.8, "is_discounted": false } }, ... ] }
Field (providers[])TypeDescription
namestring프로바이더 이름. provider.only 에 넣는 값입니다.
model_idstring그 프로바이더가 등재한 표기 (대소문자 그대로). 이 표기로 호출해도 같은 모델입니다.
model_typestring그 행의 모델 종류. 드물게 같은 모델이라도 프로바이더마다 종류가 다를 수 있습니다.
max_context_tokens / max_output_tokensinteger그 프로바이더의 한도 원값. 미신고면 null.
provider_available / provider_statusboolean / string프로바이더 표시값. 현재는 항상 true / healthy 이며 실시간 장애 상태를 반영하지 않습니다.
supported_parametersarray그 프로바이더 행이 받아들이는 파라미터 (교집합을 내기 전 원값). 텍스트(chat) 모델에만 실리고, 빈 값이면 필드 자체가 빠집니다.
pricingobject원화(KRW) 단가. 아래 표 참고. 단가가 하나도 없으면 필드 자체가 빠집니다.
Field (pricing)TypeDescription
currencystring항상 KRW 입니다.
unitstring과금 단위. per_1m_tokens 면 토큰 100만 개당 과금이고, 그 밖의 값(image / megapixel / second / character / request / byte)이면 그 단위당 과금입니다.
input / output / cache_readnumber토큰 100만 개당 적용 단가 (할인 기간이면 할인가, 아니면 정가).
unit_pricenumber단위 과금 모델의 단위당 적용 단가. unit 이 per_1m_tokens 가 아닐 때만 나옵니다.
is_discountedboolean적용 단가가 정가보다 낮은 항목이 하나라도 있으면 true.
list_input / list_output / list_cache_read / list_unit_pricenumber할인 전 정가. is_discounted 가 true 일 때만 실립니다.
discount_ends_atstring할인 종료 시각 (UTC 기준 RFC 3339, 예 2026-09-30T14:59:59Z). 할인 중이고 종료 시각이 정해진 경우에만 실립니다.

값이 없는 키는 아예 나오지 않습니다 — 예를 들어 캐시 단가가 없는 모델에는 cache_read 가 없습니다. 컨텍스트 길이 구간에 따라 단가가 달라지는 모델은 기본 구간 값만 실리므로, 구간별 요금은 Models 페이지에서 확인하세요. 하나로 좁혀지지 않는 모델 ID 로 조회하면 404 가 옵니다.


Chat Completions

POST/api/v1/chat/completions
OpenAI 호환 Chat Completion. 스트리밍, Auto Routing, Preset, Provider Routing, Fallback, Function Calling, Vision 지원.
curl https://llm-router.cafe24.com/api/v1/chat/completions \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "deepseek-ai/DeepSeek-V3.1", "messages": [{"role": "user", "content": "Hello!"}], "max_tokens": 100, "stream": true }'
response = client.chat.completions.create( model="deepseek-ai/DeepSeek-V3.1", messages=[{"role": "user", "content": "Hello!"}], max_tokens=100, stream=True, )

응답의 extra_fields.routing_info 에 실제로 요청을 처리한 프로바이더와 모델이 실려 옵니다 (provider, resolved_model_used, latency). cafe24/auto 나 Preset 처럼 모델이 런타임에 정해지는 경우 어디로 나갔는지 확인할 수 있습니다. 이 필드는 Embeddings · Rerank · Speech to Text 응답에도 함께 옵니다.


Responses

POST/api/v1/responses
OpenAI Responses API 호환. input/output 구조로 요청하고 받습니다.

지원 범위가 좁습니다. Responses 규격을 구현한 프로바이더의 OpenAI 계열 모델에서만 동작합니다. 그 밖의 모델은 아래처럼 거절되므로, 범용으로 쓸 경로가 필요하면 Chat Completions 를 쓰세요.

모델결과
gpt-4o, gpt-5, gpt-5-mini 등 OpenAI 계열정상
Anthropic 계열 (claude-*)400 — 이 경로에서 지원하지 않는다는 안내
그 밖 (예: gemini-*, solar-*)404 — 프로바이더가 이 규격을 제공하지 않음

Request Body

ParameterTypeDescription
modelstring필수. 위 지원 범위의 모델
inputstring | array필수. 입력 텍스트 또는 메시지 배열
instructionsstring시스템 프롬프트에 해당
max_output_tokensinteger최대 출력 토큰. 추론 모델은 이 예산을 추론에 먼저 씁니다 — 너무 작으면 본문 없이 status: "incomplete" 로 끝납니다
temperature · top_pnumber샘플링 파라미터
toolsarray도구 정의
streambooleanSSE 스트리밍
metadataobject요청 추적용 key-value. 프로바이더로 전달되지 않고 Activity 에서 확인합니다
curl https://llm-router.cafe24.com/api/v1/responses \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o", "input": "Say OK", "max_output_tokens": 32}'
response = client.responses.create( model="gpt-4o", input="Say OK", max_output_tokens=32, ) print(response.output_text)

Response

{ "id": "resp_009ee3bd52ff381b...", "object": "response", "status": "completed", "model": "gpt-4o", "output": [ { "type": "message", "role": "assistant", "status": "completed", "content": [ { "type": "output_text", "text": "OK!" } ] } ], "incomplete_details": null, "usage": { "input_tokens": 9, "output_tokens": 4, "total_tokens": 13 } }

Chat Completions 와 구조가 다릅니다 — 본문은 choices[].message.content 가 아니라 output[].content[].text 에 있고, 토큰 이름도 input_tokens · output_tokens 입니다. SDK 를 쓰면 response.output_text 로 바로 꺼냅니다. 끝까지 못 간 응답은 status 가 incomplete 이고 incomplete_details.reason 에 사유(예: max_output_tokens)가 실립니다. 이때도 소비한 토큰은 과금됩니다.


Embeddings

POST/api/v1/embeddings
텍스트를 벡터로 변환. 시맨틱 검색, 문서 유사도, RAG 인덱싱에 씁니다.
ParameterTypeDescription
modelstring필수. 임베딩 모델 (Models 에서 타입 Embedding 으로 필터)
inputstring | string[]필수. 임베딩할 텍스트. 배열로 여러 건을 한 번에 보낼 수 있습니다
dimensionsinteger출력 벡터 차원. 이를 지원하는 모델에서만 반영됩니다 (실측: google/embeddinggemma-300m 에 256 을 주면 256차원이 옵니다)
encoding_formatstringfloat(기본) 또는 base64. base64 를 주면 embedding 이 숫자 배열이 아니라 base64 문자열로 옵니다
metadataobject요청 추적용 key-value
curl https://llm-router.cafe24.com/api/v1/embeddings \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "google/embeddinggemma-300m", "input": ["안녕하세요", "hello world"] }'
response = client.embeddings.create( model="google/embeddinggemma-300m", input=["안녕하세요", "hello world"], ) print(len(response.data[0].embedding)) # 768

Response

{ "object": "list", "model": "google/embeddinggemma-300m", "data": [ { "object": "embedding", "index": 0, "embedding": [0.012, -0.034, ...] } ], "usage": { "prompt_tokens": 7, "total_tokens": 7 } }

data 는 입력 순서대로 오고 index 로도 확인할 수 있습니다.벡터 차원은 모델마다 다릅니다 (실측: google/embeddinggemma-300m 은 768). 저장소 스키마를 잡기 전에 실제 응답 길이를 확인하세요. 과금은 입력 토큰 기준이며 출력 벡터 크기와 무관합니다.


Images

POST/api/v1/images/generations
텍스트 프롬프트로 이미지 생성.
POST/api/v1/images/edits
기존 이미지를 프롬프트로 편집. multipart/form-data 와 JSON(base64) 둘 다 받습니다.

Request Body

ParameterTypeDescription
modelstring필수
promptstring필수. 생성·편집 지시
imagefile | string/images/edits 전용, 필수. multipart 파일 또는 JSON 의 base64 data URL
maskfile | string/images/edits 전용. 편집 영역 마스크 (지원 모델 한정)
ninteger생성 장수 (기본 1). 장당 과금이라 이 값에 비례해 과금됩니다. 다만 모델이 무시할 수 있습니다 — 실측에서 stabilityai/sdxl-turbo 는 2장을 주지만 google/nano-banana-2-lite 는 n: 2 에도 1장만 돌려줍니다
sizestring"1024x1024" 형태. 해상도를 정하는 파라미터입니다
metadataobject요청 추적용 key-value. 프로바이더로 전달되지 않고 Activity 에서 확인합니다
curl https://llm-router.cafe24.com/api/v1/images/generations \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "stabilityai/sdxl-turbo", "prompt": "a small red apple on a white table", "n": 1, "size": "512x512" }'
curl https://llm-router.cafe24.com/api/v1/images/edits \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -F image=@original.jpg \ -F prompt="make the apple green" \ -F model=google/nano-banana-2-lite
curl https://llm-router.cafe24.com/api/v1/images/edits \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "google/nano-banana-2-lite", "prompt": "make the apple green", "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." }'

Response

{ "created": 1787711991, "data": [ { "b64_json": "/9j/4AAQSkZJRgABAQ..." } ] }

b64_json 과 url 중 무엇이 올지는 모델이 정합니다 — 실측에서 stabilityai/sdxl-turbo · google/nano-banana-2-lite 는 b64_json, 일부 편집 모델은 만료되는 임시 url 을 줍니다. 두 키를 모두 확인하고, url 은 받은 즉시 내려받아 보관하세요. base64 는 선두 바이트로 실제 포맷을 판별하는 편이 안전합니다 (/9j/ = JPEG, iVBORw0 = PNG).

response_format 은 보내지 마세요. 반환 형태는 위처럼 모델이 정하며, 값을 지정하면 프로바이더가 거절할 수 있습니다 — 실측에서 stabilityai/sdxl-turbo 에 response_format: "url" 을 주면 422 가 납니다.

이미지 응답에는 usage 가 없습니다 — 현재 제공하는 이미지 모델은 전부 장당 과금이라 토큰 집계가 없습니다. 비용은 Activity 의 usage_krw_micro 로 확인하세요 (그 행의 토큰 값은 0 입니다).

모든 이미지 모델이 편집을 지원하지는 않습니다. 지원하지 않는 모델로 /images/edits 를 호출하면 프로바이더가 404 를 돌려줍니다. 편집 입력이 2장 이상이면 multipart 파일 필드명이 image[] 가 됩니다 (1장이면 image).


Rerank

POST/api/v1/rerank
질의와 문서 목록을 받아 관련도 순으로 재정렬. RAG 검색 결과 정제에 씁니다.

벡터 검색으로 넓게 뽑은 뒤 이 API 로 좁히면 LLM 에 넣는 문서 수를 줄일 수 있습니다.

ParameterTypeDescription
modelstring필수. rerank 모델
querystring필수. 기준이 되는 질의
documentsstring[] | object[]필수. 재정렬할 문서. 문자열 배열과 [{"text": "..."}] 형식 둘 다 받습니다
top_ninteger상위 N건만 반환. 미지정 시 전체
return_documentsbooleantrue 면 응답에 원문을 함께 실어 줍니다 (기본 false)
max_tokens_per_docinteger문서당 처리 토큰 상한. 프로바이더로 전달합니다
metadataobject요청 추적용 key-value
curl https://llm-router.cafe24.com/api/v1/rerank \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "Qwen/Qwen3-Reranker-0.6B", "query": "강아지 사료 추천", "documents": ["고양이 장난감 후기", "반려견 사료 비교 가이드", "노트북 리뷰"], "top_n": 2 }'
import requests r = requests.post( "https://llm-router.cafe24.com/api/v1/rerank", headers={"Authorization": "Bearer sk-cafe24-YOUR_KEY"}, json={ "model": "Qwen/Qwen3-Reranker-0.6B", "query": "강아지 사료 추천", "documents": ["고양이 장난감 후기", "반려견 사료 비교 가이드"], "top_n": 2, }, ).json() # index 는 보낸 documents 의 원본 위치다 for hit in r["results"]: print(hit["index"], hit["relevance_score"])

Response

{ "id": "01a03beeee177da6...", "model": "Qwen/Qwen3-Reranker-0.6B", "results": [ { "index": 1, "relevance_score": 0.9938, "document": { "text": "" } }, { "index": 0, "relevance_score": 0.0033, "document": { "text": "" } } ], "usage": { "prompt_tokens": 259, "total_tokens": 259 } }

results 는 관련도 내림차순이고 index 는 보낸 documents 의 원본 위치입니다. return_documents 를 주지 않으면 document.text 가 빈 문자열로 옵니다 — 키 자체는 오므로, 원문이 필요하면 index 로 되찾거나 return_documents: true 를 주세요. 과금은 질의와 문서를 합한 입력 토큰 기준입니다.


Text to Speech

POST/api/v1/audio/speech
텍스트를 음성으로 합성. 응답이 JSON 이 아니라 오디오 바이트입니다.

응답 본문이 원시 오디오 바이트라 파일로 그대로 저장하거나 플레이어에 바로 넘기면 됩니다 — .json() 으로 파싱하면 깨집니다.

ParameterTypeDescription
modelstring필수. TTS 모델
inputstring필수. 합성할 텍스트. 이 길이가 과금 기준입니다
voicestring음성 이름. 생략하면 프로바이더 기본 음성을 씁니다
response_formatstringmp3(기본) · opus · aac · flac · wav · pcm
speednumber재생 속도 배율. 프로바이더로 전달됩니다
instructionsstring톤·스타일 지시. 지원 모델에서만 반영됩니다
metadataobject요청 추적용 key-value
curl https://llm-router.cafe24.com/api/v1/audio/speech \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "hexgrad/Kokoro-82M", "input": "안녕하세요. 카페24 LLM Router 입니다.", "voice": "af_bella", "response_format": "mp3" }' \ --output speech.mp3
# 응답은 오디오 바이트다 — 스트리밍으로 파일에 바로 쓴다. with client.audio.speech.with_streaming_response.create( model="hexgrad/Kokoro-82M", input="안녕하세요. 카페24 LLM Router 입니다.", voice="af_bella", response_format="mp3", ) as response: response.stream_to_file("speech.mp3")
import { writeFile } from "node:fs/promises"; const res = await client.audio.speech.create({ model: "hexgrad/Kokoro-82M", input: "안녕하세요. 카페24 LLM Router 입니다.", voice: "af_bella", response_format: "mp3", }); await writeFile("speech.mp3", Buffer.from(await res.arrayBuffer()));

응답

본문은 오디오 바이트이고 포맷은 Content-Type 으로 알려 줍니다. 추적용 X-Request-ID 헤더도 함께 옵니다.

response_formatContent-Type
mp3 (기본)audio/mpeg
opus · aac · flac · wav · pcmaudio/opus · audio/aac · audio/flac · audio/wav · audio/pcm
그 밖의 값application/octet-stream

과금

  • 토큰이 아니라 input 의 문자 수로 과금됩니다. 한글 1자와 영문 1자는 같은 1자입니다.
  • 생성된 오디오 길이·파일 크기는 과금과 무관합니다 — speed 를 올려 짧게 만들어도 비용은 그대로입니다.
  • Activity 에서 이 호출의 토큰은 0 으로 기록됩니다. 비용은 usage_krw_micro 로 보세요.

Speech to Text

POST/api/v1/audio/transcriptions
오디오 파일을 텍스트로 변환. multipart/form-data 로 전송합니다.

JSON 이 아니라 multipart/form-data 로 보내야 하며, 파일은 26 MiB 까지 받습니다. 초과하면 요청이 거절됩니다.

FieldTypeDescription
filefile필수. 변환할 오디오 파일. 이 오디오의 길이가 과금 기준입니다
modelstring필수. STT 모델
languagestringISO-639-1 언어 코드 (ko, en 등). 지정하면 인식 정확도가 올라갑니다
promptstring고유명사·용어 힌트. 프로바이더로 전달됩니다
response_formatstring프로바이더로 전달됩니다. 지원 값은 모델마다 다릅니다
curl https://llm-router.cafe24.com/api/v1/audio/transcriptions \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" \ -F file=@sample.mp3 \ -F model=openai/whisper-large-v3-turbo \ -F language=ko
with open("sample.mp3", "rb") as f: result = client.audio.transcriptions.create( model="openai/whisper-large-v3-turbo", file=f, language="ko", ) print(result.text)

Response

{ "text": "안녕하세요. 카페24 LLM Router 입니다." }

과금은 오디오 길이(초) 기준이며 인식된 글자 수와 무관합니다. TTS 와 마찬가지로 Activity 의 토큰 값은 0 이고 비용은 usage_krw_micro 에 실립니다.


System One NEW

POST/api/v1/systemone
상태(state)와 질문(questions)을 보내면 질문마다 형식이 정해진 답(answers)을 돌려주는 판단 API. 문장을 생성하지 않습니다.

분류·배정·필터처럼 답의 형식이 정해진 판단에 씁니다. 질문 여러 개를 한 요청에 보내면 답도 한 응답에 모두 옵니다.

TypeSafe 의 System One API 규격을 따릅니다. 게이트웨이는 인증·라우팅·과금만 하고, state·questions 와 응답 본문은 바꾸지 않고 전달합니다. OpenAI 규격이 아니므로 OpenAI SDK 로는 호출할 수 없습니다. HTTP 로 직접 호출하거나 TypeSafe 공식 SDK 를 쓰세요.

ParameterTypeDescription
modelstring필수. 모델 타입이 decision 인 모델. Models 페이지에서 모델 타입 Decision 으로 필터해 확인합니다. 다른 타입의 모델을 주면 400 과 함께 그 모델이 쓸 수 있는 엔드포인트가 안내됩니다
statestring · object · array필수. 판단할 대상. 형식 제한이 없습니다
questionsobject필수. { 질문 이름: 질문 정의 }. 비어 있으면 400. 질문 정의는 아래 표를 보세요
providerobject프로바이더 지정. 형식은 Provider Routing 과 같습니다
metadataobject요청 추적용 key-value. 프로바이더에 전달되지 않고 사용량 조회에서 확인할 수 있습니다

질문 정의

모든 질문에 type 과 instructions(질문 문장)를 씁니다. criteria 는 유형마다 형식이 다릅니다.

type묻는 것criteria답에 오는 필드
noul예 / 아니오선택
{"true": "…", "false": "…"}
참·거짓의 판단 기준
noul 참일 확률 (0~1)
choice선택지 중 하나필수
{ 선택지 키: 설명 }
choice 고른 선택지 키
probabilities 선택지별 확률
confidence 확신도
score척도 위의 위치필수
["0단계 설명", "1단계 설명", …]
앞에서부터 0, 1, 2 … 단계
score 점수 (소수)
legend 단계 설명
probabilities 단계별 확률
confidence 확신도

질문 정의의 세부 형식은 게이트웨이가 아니라 프로바이더가 검사합니다. 형식이 틀리면 400(provider_error)이 오고, message 에 프로바이더의 오류 문구가 그대로 담깁니다.

예시

curl https://llm-router.cafe24.com/api/v1/systemone \ -H "Authorization: Bearer $LLM_ROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "typesafe/jev-1.13.0", "state": { "subject": "호스팅 요금 문의", "body": "쇼핑몰 트래픽이 늘어서 다음 달부터 상위 호스팅 상품으로 바꾸고 싶습니다. 요금 차이를 알려 주세요." }, "questions": { "is_billing": { "type": "noul", "instructions": "요금이나 결제에 관한 문의인가?" }, "team": { "type": "choice", "instructions": "어느 팀이 처리해야 하는가?", "criteria": { "sales": "상품 변경, 업그레이드, 요금 문의", "support": "기술 문제, 장애", "other": "그 밖의 문의" } }, "urgency": { "type": "score", "instructions": "얼마나 급한 문의인가?", "criteria": ["급하지 않음", "이번 주 안에 답이 필요함", "지금 서비스에 문제가 있음"] } } }'
# System One 은 OpenAI 규격이 아니라 HTTP 로 직접 호출합니다. import requests res = requests.post( "https://llm-router.cafe24.com/api/v1/systemone", headers={"Authorization": "Bearer $LLM_ROUTER_API_KEY"}, json={ "model": "typesafe/jev-1.13.0", "state": {"subject": "호스팅 요금 문의", "body": "..."}, "questions": { "is_billing": {"type": "noul", "instructions": "요금이나 결제에 관한 문의인가?"}, "team": { "type": "choice", "instructions": "어느 팀이 처리해야 하는가?", "criteria": {"sales": "상품 변경, 요금 문의", "support": "기술 문제, 장애", "other": "그 밖의 문의"}, }, }, }, timeout=30, ).json() answers = res["answers"] if answers["is_billing"]["noul"] > 0.9: print("요금 문의", answers["team"]["choice"])
# pip install typesafe-sdk from typesafe_sdk import TypeSafeClient client = TypeSafeClient( api_key="$LLM_ROUTER_API_KEY", base_url="https://llm-router.cafe24.com/api", # /api 까지만 — SDK 가 /v1/systemone 을 붙입니다 ) res = client.system_one( model="typesafe/jev-1.13.0", # 꼭 지정 — SDK 기본값 jev-latest 는 이 서비스에 없습니다 state="다음 달부터 상위 호스팅 상품으로 바꾸고 싶습니다", questions={ "is_billing": {"type": "noul", "instructions": "요금 문의인가?"}, "team": { "type": "choice", "instructions": "어느 팀이 처리해야 하는가?", "criteria": {"sales": "요금·상품 변경", "support": "기술 문제, 장애"}, }, }, ) print(res.answers["team"].choice, res.answers["is_billing"].noul)

TypeSafe SDK 로 호출할 때

항목설정틀리면
base_urlhttps://llm-router.cafe24.com/api
(/api 까지만)
404. SDK 가 뒤에 /v1/systemone 을 붙이므로, 위 Base URL(/api/v1)을 넣으면 /api/v1/v1/systemone 이 됩니다
model반드시 지정 (예: typesafe/jev-1.13.0)400. 생략하면 SDK 기본값 jev-latest 가 들어가는데, 이 서비스에 없는 이름입니다
모델 목록Models 페이지, 또는
GET /api/v1/models
오류. client.models.list() 는 쓸 수 없습니다. 이 서비스의 /models 응답이 OpenAI 형식이라 SDK 가 읽지 못합니다

응답

answers 의 키는 요청한 질문 이름과 같고, 답마다 type 이 함께 옵니다. 아래는 위 curl 요청의 실제 응답입니다 (dev 실측). 확률 값은 같은 요청이어도 호출마다 조금 다를 수 있습니다 (실측: 같은 요청에서 score 0.42 / 0.40). 응답의 model 에는 요청한 대표 모델 ID 가 아니라 프로바이더에 등록된 이름(jev-1.13.0)이 옵니다.

{ "model": "jev-1.13.0", "answers": { "is_billing": { "type": "noul", "noul": 0.98 }, "team": { "type": "choice", "choice": "sales", "confidence": 1.0, "probabilities": { "support": 0.0, "sales": 1.0, "other": 0.0 } }, "urgency": { "type": "score", "score": 0.42, "confidence": 0.37, "legend": { "0": "급하지 않음", "1": "이번 주 안에 답이 필요함", "2": "지금 서비스에 문제가 있음" }, "probabilities": { "0": 0.58, "1": 0.42, "2": 0.0 } } }, "usage": { "input_tokens": 480, "output_tokens": 72 } }
필드읽는 법
noul참일 확률입니다. confidence 가 없으므로 이 값으로 기준을 정하세요
score정수 단계가 아니라 소수입니다. 실측 값은 단계별 확률의 가중 평균과 같습니다 (위 예: 0 × 0.58 + 1 × 0.42 = 0.42).
단계 하나를 고르려면 probabilities 가 가장 큰 단계를 쓰세요
confidence낮을수록 답이 불확실합니다. 자동 처리 기준값을 두고, 그보다 낮으면 사람이 확인하게 하세요

스트리밍은 없습니다. 답이 모두 나온 뒤 한 번에 응답합니다.

오류

Statuserror.code원인
400invalid_request_errormodel·state·questions 누락, 또는 questions 가 빈 객체
400400 (숫자)decision 타입이 아닌 모델. 메시지에 그 모델이 쓸 수 있는 엔드포인트가 실립니다. 계정·키에 프로바이더 지정(only/ignore/order)이 있으면 이 대신 아래 403 provider_not_allowed 가 옵니다
400provider_error질문 정의 형식 오류 (예: type 오타). message 에 프로바이더 문구가 담깁니다
403provider_not_allowed라우팅 설정이나 provider 지정에 맞는 프로바이더가 없음
403data_policy_not_allowed데이터 정책(보관·학습·처리 지역)에 맞는 프로바이더가 없음. 데이터 정책 참조
403permission_error관리(management) 키로 호출함. 추론용 키를 쓰세요
501not_implementedSystem One 을 지원하지 않는 프로바이더로 라우팅됨

과금

  • 응답 usage 의 input_tokens·output_tokens 에 모델 단가를 곱합니다. 단가는 Models 페이지에서 확인하세요.
  • state 가 길수록 입력 토큰이 늘어납니다. 판단에 필요한 부분만 보내세요.
  • 질문은 한 요청에 모으세요. 같은 state 를 요청마다 다시 보내면 그만큼 입력 토큰을 다시 냅니다.

여기부터는 LLM 을 호출하는 API 가 아니라, 발급받은 키의 사용량을 조회하고 키를 관리하는 API 입니다. 사용량은 같은 데이터를 두 가지 형태(Usage·Activity)로 제공하며, 인증은 동일하게 API Key 를 씁니다.

Usage

GET/api/v1/usage
이 API Key 의 사용량 조회. LLM 호출에 쓰는 키를 그대로 사용합니다. 관리 키로 호출하면 내 계정 전체 합산입니다.

날짜는 KST 기준이며 to 는 해당일을 포함합니다.

Query Parameters

ParameterTypeDefaultDescription
fromstring-시작일 (YYYY-MM-DD). 생략 시 조회 가능한 가장 이른 날
tostring오늘종료일 (YYYY-MM-DD). 해당일 포함
periodstringday버킷 단위. day · week · month · total
api_key_iduuid-관리 키 전용 필터 — 소유 키 하나로 좁히기 (비소유 404). 미지정 시 관리 키는 계정 전체, LLM 호출용 키는 자기 자신

Response

FieldTypeDescription
label, key_prefixstring키 이름 / 접두사
start_date, end_datestring실제 집계 구간 (KST)
requestsinteger요청 수
cached_requests, error_requestsinteger캐시 적중 / 실패 요청 수
prompt_tokens, completion_tokensinteger입력 / 출력 토큰
reasoning_tokens, total_tokensinteger추론 토큰 / 합계
cache_read_tokens, cache_creation_tokensinteger프롬프트 캐시 토큰
usagenumber비용 (KRW)
usage_krw_microinteger비용 (micro KRW). 정확한 정수값
usage_usdnumber | null비용 (USD). 참고값 — 아래 주의 참조
usd_completebooleanfalse 면 USD 단가 미등록 모델이 있어 usage_usd 가 과소
by_model[]array모델별 집계. model, model_requested, provider_name, 토큰, 비용
daily[]arrayperiod 버킷별 집계
data_completebooleanfalse 면 구간이 조정됐거나 일부 데이터만 포함
available_fromstring조회 가능한 가장 이른 날 (KST)
warningstring | null구간 조정 등이 발생한 경우의 설명
curl "https://llm-router.cafe24.com/api/v1/usage?from=2026-07-01&to=2026-07-31&period=day" \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY"
import requests res = requests.get( "https://llm-router.cafe24.com/api/v1/usage", params={"from": "2026-07-01", "to": "2026-07-31", "period": "month"}, headers={"Authorization": "Bearer sk-cafe24-YOUR_KEY"}, ) data = res.json()["data"] print(data["requests"], "requests", data["usage"], "KRW") # 모델별 비용 for m in data["by_model"]: print(m["model"], m["usage"])
{ "data": { "label": "my-api-key", "period": "day", "start_date": "2026-07-01", "end_date": "2026-07-31", "timezone": "Asia/Seoul", "currency": "KRW", "requests": 412, "prompt_tokens": 1840322, "completion_tokens": 92117, "usage": 11.83654, "usage_krw_micro": 11836540, "usage_usd": 0.00814548, "usd_complete": true, "by_model": [ { "model": "deepseek-ai/DeepSeek-V3.1", "model_requested": "cafe24/auto", "provider_name": "deepinfra", "requests": 210, "usage": 9.80 } ], "daily": [ { "date": "2026-07-31", "requests": 12, "usage": 0.41 } ], "data_complete": true, "available_from": "2026-05-03" } }

주의

  • 조회 범위는 최근 90일입니다. 더 이전을 요청해도 오류가 아니라 자동으로 조정되며, data_complete: false 와 available_from 으로 알려줍니다.
  • model 과 model_requested 가 다를 수 있습니다. cafe24/auto 나 별칭으로 호출하면 실제 선택된 모델이 model 에 들어갑니다.
  • 과금 기준은 KRW(usage_krw_micro)입니다. usage_usd 는 모델 USD 단가로 산출한 참고값이며, 단가 미등록 모델이 있으면 usd_complete: false 로 표시됩니다.
  • 조회 대상은 기본적으로 요청에 사용한 키 자신입니다. 예외로 관리 키로 호출하면 내 계정 전체 사용량이 합산되어 반환되고, api_key_id 파라미터로 소유 키 하나로 좁힐 수 있습니다 (비소유 키 지정은 404). 다른 사용자의 사용량은 어떤 경우에도 조회할 수 없습니다.
  • 요청 한도는 키당 분당 10회 · 하루 1,000회이며, /usage·/activity·/keys 호출을 합산해 셉니다 (키 생성·수정·삭제 같은 쓰기 요청 포함). 초과하면 429 를 반환합니다. LLM 호출 한도와는 별도 카운터입니다.
  • 위 표에 없는 쿼리 파라미터를 보내면 400 입니다 (지원하지 않는 쿼리 파라미터: …, 허용 목록 포함). 오타나 미지원 옵션이 조용히 무시된 채 다른 구간이 집계되는 일을 막기 위한 동작입니다.

Activity

GET/api/v1/activity
API Key 사용량을 일자 × 모델 × 프로바이더로 집계. LLM 호출용 키로 인증하면 그 키 단독, 관리 키로 인증하면 내 계정 전체 합산입니다.

표준 activity 스키마와 필드 호환이라 기존 사용량 조회 클라이언트를 그대로 붙일 수 있습니다. 조회 대상은 기본적으로 인증에 쓴 키 자신입니다. 관리 키로 호출하면 내 계정 전체 사용량이 합산되고, api_key_id 로 소유 키 하나로 좁힐 수 있습니다 (비소유 키 지정은 404).

Query Parameters

ParameterTypeDescription
datestring단일 일자 (YYYY-MM-DD). from/to 와 함께 쓸 수 없습니다 (400).
fromstring시작일 (YYYY-MM-DD).
tostring종료일 (YYYY-MM-DD, 해당일 포함).
api_key_iduuid관리 키 전용 필터 — 소유 키 하나로 좁히기 (비소유 404). 미지정 시 관리 키는 계정 전체, LLM 호출용 키는 자기 자신.
timezonestring일자 경계 기준. Asia/Seoul(기본) 또는 UTC. KST·Etc/UTC 별칭도 받으며, 응답에는 정규 표기가 실립니다.
group_bystringmetadata:<key> 형식. 요청 시 보낸 metadata 값으로 한 축 더 분해합니다 (예: metadata:team).

셋 다 생략하면 최근 30일입니다. 보존 기간은 90일이며, 더 긴 구간이 필요하면 응답의 available_from 을 보고 from 을 지정하세요. 보존 기간을 벗어난 구간은 자동으로 잘리고 warning 으로 알립니다. 요청 구간 전체가 조회 범위 밖이면 400 입니다. 위 표에 없는 쿼리 파라미터를 보내도 400 입니다 (지원하지 않는 쿼리 파라미터: …, 허용 목록 포함) — 오타나 미지원 옵션이 조용히 무시된 채 다른 구간이 집계되는 일을 막기 위한 동작입니다.

Response — data[] 항목

FieldTypeDescription
datestring집계 일자 (timezone 기준).
modelstring실제 사용된 모델 (과금 기준).
provider_namestring프로바이더.
endpoint_idstring{provider}/{model} 합성값.
requestsinteger요청 수.
prompt_tokens / completion_tokens / reasoning_tokensinteger토큰 수.
usagenumberUSD 참고값 — 아래 주의사항 참조.
usage_krw_microinteger실제 청구 근거 (micro KRW, 1,000,000 = 1원).
usd_completebooleanfalse 면 USD 단가가 없는 모델이 섞여 usage 가 과소집계입니다.
metadata_key / metadata_valuestringgroup_by 를 준 요청에만 채워집니다. 미지정 시 null.

metadata 별 분해

요청 body 에 metadata 를 실어 보냈다면(Metadata 참조),group_by=metadata:<key> 로 그 키의 값별 사용량을 나눠 볼 수 있습니다. 기존 축(일자·모델·프로바이더)은 그대로 두고 한 축이 더해지는 형태입니다.

group_by 를 주지 않으면 응답 구조가 전혀 달라지지 않습니다. 기존 호환 클라이언트를 쓰고 있다면 이 파라미터를 보내지 않는 한 영향이 없습니다. metadata 없이 보낸 요청도 누락되지 않고 metadata_value 가 빈 문자열인 행에 모이므로, 분해 전후의 합계는 항상 같습니다.

Response — 최상위 필드

FieldDescription
start_date / end_date실제 집계된 구간 (클램프 적용 후).
available_from조회 가능한 가장 이른 일자.
data_completefalse 면 요청 구간 일부가 잘렸거나 데이터가 부분적입니다.
warning잘림·부분 데이터의 사람이 읽는 설명. null 이면 정상.

주의

금액은 usage_krw_micro 를 쓰세요. usage(USD)는 조회 시점의 단가로 환산한 참고값이라, 단가가 개정되면 같은 과거 구간을 다시 조회했을 때 값이 달라집니다.usage_krw_micro 는 호출 시점에 확정된 청구액이라 변하지 않습니다.

요청 한도는 키당 분당 10회 · 하루 1,000회이며, /usage·/activity·/keys 호출을 합산해 셉니다 (키 생성·수정·삭제 같은 쓰기 요청 포함). 초과하면 429 를 반환합니다. (LLM 호출 한도와는 별도 카운터입니다.)

# 최근 30일 (기본) curl https://llm-router.cafe24.com/api/v1/activity \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" # 특정 일자 curl "https://llm-router.cafe24.com/api/v1/activity?date=2026-08-01" \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" # 구간 지정 + UTC 기준 curl "https://llm-router.cafe24.com/api/v1/activity?from=2026-07-01&to=2026-07-31&timezone=UTC" \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY" # metadata 의 team 값별로 분해 curl "https://llm-router.cafe24.com/api/v1/activity?group_by=metadata:team" \ -H "Authorization: Bearer sk-cafe24-YOUR_KEY"
import requests r = requests.get( "https://llm-router.cafe24.com/api/v1/activity", headers={"Authorization": "Bearer sk-cafe24-YOUR_KEY"}, params={"from": "2026-07-01", "to": "2026-07-31"}, ).json() # 실제 청구액 합계 (원) total_krw = sum(i["usage_krw_micro"] for i in r["data"]) / 1_000_000 if not r["data_complete"]: print("주의:", r["warning"])

Management API

관리 키(management key)로 API 키를 프로그래밍 방식으로 생성·조회·수정·삭제합니다. CI/온보딩 자동화에서 키를 발급하고, 위의 Usage 로 사용량을 함께 조회하는 식으로 씁니다. 관리 키는 콘솔 > 관리 키에서만 발급됩니다.

구분가능불가
관리 키/keys 생성·조회·수정·삭제, /usage·/activity (계정 전체 합산)LLM 호출 전부 403
LLM 호출용 키Chat 등 추론 + /usage·/activity/keys 호출 403
POST/api/v1/keys
LLM 호출용 키 생성. 응답의 key 원문은 이 응답에서만 1회 제공됩니다.
GET/api/v1/keys
내 키 목록. status=active|disabled 필터, limit/offset 페이징.
GET/api/v1/keys/{key_id}
키 단건 조회 (한도·리셋 주기·만료·활성 상태).
POST/api/v1/keys/{key_id}
키 수정 — 보낸 필드만 반영 (name, disabled, limit_krw, limit_reset). PATCH 와 같은 동작이며, 앞단 네트워크가 PATCH 를 막으므로 POST 를 쓰세요.
DELETE/api/v1/keys/{key_id}
키 삭제 (즉시 무효화, 사용 이력은 감사 목적으로 보존).

생성 Body

FieldTypeDescription
namestring필수. 키 이름 (최대 100자)
limit_krwinteger지출 한도 (KRW 정수). 미지정 시 무제한
limit_resetstringdaily | weekly | monthly — KST 자정에 한도 사용액 초기화
expires_atdatetime만료 시각 (생성 시에만 지정 가능, 이후 변경 불가)
tagsobject키 태그 (key-value 객체)
group_namestring라우팅 그룹. 미지정 시 내 최신 활성 키의 그룹을 상속

키 객체

FieldTypeDescription
idstring키 식별자 (UUID). 수정·삭제 시 경로에 사용
keystring생성 응답에만 1회 포함되는 키 원문 (sk-cafe24-...)
key_prefixstring키 앞자리 (식별용)
key_typestringinference(LLM 호출용) | management
disabledboolean비활성 여부. 수정(POST) 으로 토글
limit_krw, limit_reset, last_limit_reset_at—한도·리셋 주기·마지막 리셋 시각
expires_at, created_at, updated_atdatetime만료·생성·수정 시각
curl -X POST "https://llm-router.cafe24.com/api/v1/keys" \ -H "Authorization: Bearer sk-cafe24-YOUR_MANAGEMENT_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "team-a-key", "limit_krw": 50000, "limit_reset": "monthly", "tags": {"project": "TEAM-A"}}'
import requests # 키 발급 + 사용량 조회를 한 스크립트에서 (관리 키 / 발급된 키를 각각 사용) created = requests.post( "https://llm-router.cafe24.com/api/v1/keys", headers={"Authorization": "Bearer sk-cafe24-YOUR_MANAGEMENT_KEY"}, json={"name": "team-a-key", "limit_krw": 50000, "limit_reset": "monthly"}, ).json() print(created["key"]) # 원문은 이 응답에서만 — 안전한 곳에 보관 keys = requests.get( "https://llm-router.cafe24.com/api/v1/keys", headers={"Authorization": "Bearer sk-cafe24-YOUR_MANAGEMENT_KEY"}, ).json() for k in keys["data"]: print(k["name"], k["limit_krw"], k["disabled"])
{ "key": "sk-cafe24-0123abcd...", "id": "e40e885f-33df-458f-9d78-7d1db0ff14b7", "name": "team-a-key", "key_prefix": "sk-cafe24-0123abcd", "key_type": "inference", "disabled": false, "limit_krw": 50000, "limit_reset": "monthly", "expires_at": null, "created_at": "2026-09-02T06:23:47+00:00" }

주의

  • 키 원문은 생성 응답에서만 1회 제공됩니다. 다시 조회할 수 없습니다.
  • 생성되는 키는 항상 LLM 호출용(inference) 입니다 — 관리 키를 API 로 복제할 수는 없습니다 (발급은 콘솔에서만).
  • 수정(POST)에서 한도를 무제한으로 되돌리려면 clear_limit: true, 리셋 주기 해제는 clear_limit_reset: true 를 보내세요 (null 은 "미변경").
  • 앞단 네트워크가 PATCH 메서드를 405 로 차단합니다. 키 수정은 POST /api/v1/keys/{key_id} 로 보내세요 (PATCH 와 같은 Body·응답. PATCH 로 보내면 405 입니다).
  • 관리 키로 수행한 모든 생성·수정·삭제는 감사 기록으로 남고, 콘솔 > 관리 키의 활동 이력에 표시됩니다.
  • 관리 키로 Usage·Activity 를 호출하면 내 계정 전체 사용량 합산이 반환됩니다. 특정 키만 보려면 api_key_id 파라미터로 좁히세요. LLM 호출용 키로 호출하면 그 키 자신의 사용량만 나옵니다.
  • 요청 한도는 키당 분당 10회 · 하루 1,000회이며, /usage·/activity·/keys 호출을 합산해 셉니다 (키 생성·수정·삭제 같은 쓰기 요청 포함). 초과하면 429 를 반환합니다.
  • 요청 body 에 정의되지 않은 필드가 있으면 400 (Extra inputs are not permitted) 입니다. /usage·/activity 도 표에 없는 쿼리 파라미터를 400 으로 거부합니다 — 오타·미지원 옵션이 조용히 무시되지 않도록 의도된 동작입니다.

Request Parameters

POST /api/v1/chat/completions 요청 body 파라미터. 다른 엔드포인트도 공통 파라미터를 지원합니다.

Required

ParameterTypeDescription
modelstring모델 ID. "deepseek-ai/DeepSeek-V3.1", "cafe24/auto", "@preset/slug"
messagesarray메시지 배열. [{"role": "user", "content": "..."}]

Sampling

ParameterTypeDefaultDescription
temperaturenumber1.0랜덤성 (0~2)
top_pnumber1.0Nucleus sampling (0~1)
max_tokensinteger-최대 출력 토큰 수. 미지정 시 모델 기본값. 모델의 최대 출력 토큰을 넘으면 400
frequency_penaltynumber0반복 억제 (-2~2)
presence_penaltynumber0새 토픽 유도 (-2~2)
streambooleanfalseSSE 스트리밍
stopstring[]null생성 중단 토큰
seedintegernull재현성 시드
response_formatobjectnullJSON mode / Structured Outputs
logprobsbooleanfalse로그 확률 반환
top_logprobsintegernull상위 N개 로그 확률 (0~20)

Routing

ParameterTypeDescription
providerobject프로바이더 라우팅 설정
modelsstring[]Fallback 모델 체인
presetstring프리셋 slug
toolsarrayFunction calling 도구 정의
tool_choicestring | object도구 선택 전략. "auto", "none", 또는 {"type":"function","function":{"name":"..."}}
cost_quality_balancestringAuto Router 균형
model_poolstring[]Auto Router 후보 와일드카드
cacheobject캐시 제어. {"semantic": false}

Tracking

ParameterTypeDescription
metadataobject요청 추적용 key-value. 프로바이더에 전달되지 않음.

OpenAI 공식 SDK를 그대로 사용합니다. base_url만 LLM Router로 변경하면 됩니다. Anthropic·Google 등 다른 프로바이더의 모델도 GET /api/v1/models 가 반환한 모델 ID (예: anthropic/claude-opus-4-8)를 model 에 넣어 같은 SDK 로 호출합니다.

Python (OpenAI SDK)

OpenAI, Google, DeepSeek 등 OpenAI 호환 모델에 사용합니다.

pip install openai
from openai import OpenAI client = OpenAI( base_url="https://llm-router.cafe24.com/api/v1", api_key="sk-cafe24-YOUR_KEY", ) # Chat Completion response = client.chat.completions.create( model="deepseek-ai/DeepSeek-V3.1", messages=[{"role": "user", "content": "Hello!"}], ) print(response.choices[0].message.content) # Streaming stream = client.chat.completions.create( model="deepseek-ai/DeepSeek-V3.1", messages=[{"role": "user", "content": "Hello!"}], stream=True, ) for chunk in stream: print(chunk.choices[0].delta.content or "", end="") # Metadata, Provider Routing (extra_body) response = client.chat.completions.create( model="deepseek-ai/DeepSeek-V3.1", messages=[{"role": "user", "content": "Hello"}], extra_body={ "metadata": {"team": "backend"}, "provider": {"order": ["siliconflow"]}, }, )

Node.js (OpenAI SDK)

npm install openai
import OpenAI from 'openai'; const client = new OpenAI({ baseURL: 'https://llm-router.cafe24.com/api/v1', apiKey: 'sk-cafe24-YOUR_KEY', }); // Chat Completion const response = await client.chat.completions.create({ model: 'deepseek-ai/DeepSeek-V3.1', messages: [{ role: 'user', content: 'Hello!' }], }); // Streaming const stream = await client.chat.completions.create({ model: 'deepseek-ai/DeepSeek-V3.1', messages: [{ role: 'user', content: 'Hello!' }], stream: true, }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content || ''); }

curl

모든 엔드포인트를 curl로 직접 호출할 수 있습니다.

# 환경변수 설정 export LLM_ROUTER_URL="https://llm-router.cafe24.com" export LLM_ROUTER_KEY="sk-cafe24-YOUR_KEY" # Chat Completion curl $LLM_ROUTER_URL/api/v1/chat/completions \ -H "Authorization: Bearer $LLM_ROUTER_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "deepseek-ai/DeepSeek-V3.1", "messages": [{"role": "user", "content": "Hello"}]}' # Model List curl $LLM_ROUTER_URL/api/v1/models \ -H "Authorization: Bearer $LLM_ROUTER_KEY"
개발 문서 — OpenAI 호환 API 연동 가이드 | LLM Router · 카페24