Skip to content

HTTP 엔드포인트

shunt가 Claude Code LLM 게이트웨이로서 제공하는 엔드포인트.

Updated View as Markdown
메서드 경로 용도
HEAD / Liveness 프로브
GET / 사람이 읽을 수 있는 랜딩(버전 + 엔드포인트 목록)
GET /health 헬스체크 — {"status":"ok","version":"x.y.z"}
GET /v1/models 모델 디스커버리 — [[models]] 항목을 반환
GET /routes shunt 네이티브 라우트 디스커버리 — 구성된 [[routes]] 테이블을 그대로 반환(model → provider/upstream_model/effort 매핑, claude 프리픽스 디스커버리 별칭 포함); 더 좁은 Anthropic 프로토콜 디스커버리 응답(id, display_name, 업스트림 모델 메타데이터)을 제공하는 /v1/models와 구별됨. [models.router] 테이블을 설정한 [[models]] 엔트리가 하나라도 있으면 routers 배열이 추가되어, 각 라우터의 model id와 algorithm(설정된 type), 라우팅 가능한 모든 targets id를 알려줌. 판정 모델을 설정한 라우터는 물어보기만 하고 제공하지는 않는 id를 judges로도 알려줌(없으면 생략). 스테이지 라우터와 auto 항목은 여기에 더해 두 티어 타깃과, 신호가 아무것도 결정하지 못했을 때 picker가 돌아가는 티어까지 알려줌
POST /v1/messages 추론 — 요청의 model id에 따라 라우팅
POST /v1/messages/count_tokens 토큰 카운팅
GET /managed/settings 게이트웨이 JWT별 Claude Code managed settings; ETag, If-None-Match, 304 Not Modified 지원
GET /user/bootstrap 게이트웨이 JWT용 Claude Desktop bootstrap 구성; ETag, If-None-Match, 304 Not Modified 지원
GET /v1/organizations/spend_limits 저장된 지출 제한을 방향성 커서 페이지네이션으로 조회
POST /v1/organizations/spend_limits 하나의 (scope, period)에 대한 지출 제한을 생성하거나 교체
GET /v1/organizations/spend_limits/{id} 저장된 지출 제한 하나를 조회
DELETE /v1/organizations/spend_limits/{id} 저장된 지출 제한 하나를 삭제
GET /v1/organizations/spend_limits/effective 주체·기간별 적용 상한과 기간 누적 지출
POST /v1/metrics 관리형 Claude Code 클라이언트의 인바운드 OTLP/HTTP 메트릭 — opt-in한 게이트웨이 텔레메트리 목적지로 verbatim relay
POST /v1/logs 인바운드 OTLP/HTTP log record — logs = true인 목적지에만 relay
POST /v1/traces 인바운드 OTLP/HTTP span — traces = true인 목적지에만 relay
GET /admin, /admin/ 관리자 대시보드 — 번들의 나머지와 마찬가지로 인증 없이 제공되는 SPA 셸입니다. GET /admin/api/session이 401을 반환하면 번들 자체가 /admin/login으로 이동시킵니다. 와일드카드 세그먼트는 빈 문자열에 매칭되지 않아 /admin/이 어떤 라우트에도 걸리지 않으므로, 마운트 루트는 두 표기를 모두 등록합니다. --features ui 없이 빌드한 바이너리에서는 두 경로 모두 해당 피처를 안내하는 본문과 함께 404를 반환합니다
GET, POST /admin/login 관리자 토큰 로그인 폼과 브라우저 세션 생성
POST /admin/api/logout 브라우저 세션 삭제
GET /admin/api/session 관리자 SPA가 렌더링 전에 필요한 세션별 값: 세션의 csrf 토큰, expiry_buffer_ms(claude::auth::EXPIRY_BUFFER의 밀리초 값으로, setup token이 사용 불가로 바뀌는 경계), 그리고 access — 이 세션이 인증하는 등급으로 read 또는 write이며, 대시보드는 이 값으로 쓰기 동작의 노출 여부를 결정한다. 또한 [server.admin].hide_observed의 불리언 값인 hide_observed도 담으며, 대시보드는 이 값으로 /admin/api/observed를 아예 요청할지 여부를 결정한다. 헤더 자격 증명 호출자는 CSRF 면제 대상이라 빈 csrf를 받는다. 이 표면에는 CORS 레이어가 없어 교차 출처 페이지가 요청은 보낼 수 있어도 응답은 읽지 못하므로, GET으로 토큰을 반환해도 안전하다
GET /admin/api/accounts Claude 계정 스토어 메타데이터: 이름, 종류, 만료, UUID; 토큰 자체는 절대 반환하지 않음
GET /admin/api/accounts/codex Codex 계정 스토어 메타데이터: 이름, 만료, ChatGPT 계정 ID; 토큰 자체는 절대 반환하지 않음
GET /admin/api/accounts/antigravity Antigravity 계정 스토어 메타데이터: 이름, 만료, 이메일(Google이 반환한 경우); 토큰 자체는 절대 반환하지 않음
GET /admin/api/accounts/xai xAI 계정 스토어 메타데이터: 이름, xAI 사용자 ID; 토큰 자체는 절대 반환하지 않음
GET /admin/api/observed 로컬 Claude Code, Codex, Gemini, Kimi, Grok, Cursor 신원과 프로바이더 자체 사용량을 읽기 전용으로 제공; 토큰 자체는 절대 반환하지 않으며 원본 자격 증명을 갱신하지도 않음. [server.admin].hide_observed가 true이면 이 소스들을 전혀 읽지 않고 { "accounts": [] }를 반환
GET /admin/api/pool claude_oauth, chatgpt_oauth, kimi_oauth, xai_oauth, antigravity_oauth 프로바이더별 풀 상태; 각 account 객체에는 선택적인 plan 문자열이 포함될 수 있고 파일에서 읽은 값은 이후 profile 조회로 더 정밀하게 보정될 수 있으며, Codex 행은 보고된 5시간/7일 사용량을 담으며 7d_oi에는 Codex 대응 항목이 없음; 각 account에는 불리언 needs_relogin도 실린다: 크리덴셜이 종결적으로 거부되었거나(invalid_grant), 리프레시 토큰이 아예 없거나, 회전된 토큰 쌍을 저장하지 못해 잃어버린 경우로, 어떤 재시도로도 되살릴 수 없고 운영자 재로그인만이 해결한다. 쿨다운 필드와 독립적으로 보고된다 — 쿨다운은 저절로 만료되지만 이 표식은 남는다 — 그리고 대시보드의 두 표 모두 쿼터 일시정지의 cooling이 아니라 needs re-login으로 표시한다. 인메모리라 재시작하면 초기화되고, 해당 계정의 다음 종결 실패에서 다시 세워진다. 어떤 provider 테이블도 선택한 적 없는 계정에도 — has_state: false와 함께 — 보고된다. admin refresh 프로브가 판정을 스토어 이름으로 기록하기 때문이다. 각 account에는 불리언 paused도 실리는데, 운영자가 shunt.toml을 건드리지 않고 토글하는 런타임 전용 제외 플래그다(아래 PATCH .../accounts/{account_ref} 참고); 응답 최상위의 sort_by_reset은 [server.pool] sort_by_reset 값이나 그 런타임 오버라이드를 반영하며(아래 바디 없는 PATCH 참고), 프로바이더별이 아니라 프로세스 전체에 적용된다. 각 account에는 provider 범위의 풀 식별자에서 파생된 불투명 account_ref도 포함된다. mutation은 표시 이름 name 대신 이 값을 사용하므로 같은 이름의 서로 다른 계정도 안전하게 개별 제어할 수 있다. 각 account에는 불리언 credential_override도 실린다. 풀 항목이 명시적 credentials 파일이나 token_env를 지정해 계정 이름과 같은 스토어 파일을 읽지 않으면 true이다. credential_override가 true인 xai_oauth 행은 대시보드가 스토어의 같은 이름 로그인과 매칭하지 않으므로, 다른 사용자의 Grok CLI 관측이 그 행에 합쳐지지 않는다. 각 account에는 이 프로세스가 시작된 이후의 요청 카운터도 실린다: requests_attempted는 shunt가 그 account로 보낸 프록시 요청 수이고(토큰 갱신이나 스로틀 대기 뒤 같은 account로 다시 보낸 요청도 따로 센다. 사용량 폴링, 모델 탐색, 카탈로그 조회, 토큰 갱신은 세지 않는다), 항상 다음 세 값의 합과 같다: requests_succeeded는 2xx 상태로 응답받은 수, requests_failed는 다른 상태로 응답받았거나 응답 헤더가 오기 전에 실패한(전송 오류 또는 첫 바이트 타임아웃) 수, requests_cancelled는 클라이언트가 연결을 끊었거나 기한에 걸려 결과가 나오기 전에 중단된 수다. mean_latency_ms는 헤더를 받은 요청들의 전송부터 응답 헤더까지의 평균 시간이며, 아직 하나도 없으면 null이다. Codex WebSocket 전송을 거친 요청은 성공이든 실패든 세지 않으며, WebSocket 시도가 실패한 뒤의 HTTP 폴백은 센다. 같은 계정 식별자로 해석되는 행들은 한 벌의 카운터를 공유한다. 카운터는 설정 리로드 후에도 유지되고, 재시작하면 초기화되며, admin API로 account를 삭제하면 사라진다. 각 계정은 확정된 하드 캡 max_utilization_5h, max_utilization_7d, max_utilization_fable도 [0.0, 1.0] 범위의 비율로 담는다(계정 창 → 계정 → 풀 창 → 풀 기본값 순으로 해석하며, 해당 창에 적용되는 캡이 없으면 null). has_state가 false여도 설정에서 읽어 보고하며, 대시보드는 이를 사용량 막대와 풀 표에 표시한다. max_utilization_fable은 Fable 전용 7d_oi 창에만 적용되므로 Fable 모델 요청에만 영향을 준다. chatgpt_oauth 계정에는 7d_oi 창이 없어 항상 null이고, antigravity_oauth 계정은 할당량이 캡에 반영되지 않으므로 세 캡 모두 null이다.
PATCH /admin/api/pool/{provider}/accounts/{account_ref} write 등급 전용. 바디 {"paused": true|false}로 해당 계정의 런타임 일시정지를 토글한다: disabled와 동일하게 선택 대상에서 제외되지만 인메모리라(재시작 시 초기화) shunt.toml과 무관하다. 알 수 없는 provider나 account에는 404 {account_ref}는 GET /admin/api/pool의 해당 account 객체에서 가져온다. 표시 이름은 mutation 대상을 지정하는 데 사용하지 않는다.
PATCH /admin/api/pool write 등급 전용. 바디 {"sort_by_reset": true|false}로 풀 전체의 리셋 우선 정렬을 런타임에 토글한다([server.pool]은 프로바이더별이 아니라 프로세스 전체이므로): 사용 가능한 계정이 번-레이트 헤드룸 대신 쿼터 리셋이 가장 빠른 순으로 정렬된다. {"sort_by_reset": null}은 이전에 설정한 오버라이드를 명시적으로 해제하여 설정 파일 자체 값으로 되돌린다(필드 생략은 아무 효과 없음 — 해제가 아님); 오버라이드는 인메모리이며 재시작 시에도 되돌아간다. [server.pool] 자체가 없으면 — 그 레거시 선택 경로는 이 값을 전혀 참조하지 않으므로 — 오버라이드와 무관하게 아무 효과가 없고 GET /admin/api/pool도 sort_by_reset: false를 보고한다
GET /admin/api/routes 관리자 자격 증명 뒤에서 제공하는 해석된 라우팅 표로, 대시보드가 사용할 수 있습니다 — 위의 GET /routes가 반환하는 것과 같은 본문이며, 같은 스냅샷에서 만들어지므로 운영자가 보는 표와 클라이언트가 실제로 해석하는 표가 어긋날 수 없습니다. 리다이렉트가 아니라 별도로 등록하는 이유는 관리자 네임스페이스가 자체 인증을 유지하기 위해서입니다. 공개 /routes는 의도적으로 인증을 두지 않으므로, 이 엔드포인트를 그쪽으로 넘기면 두 표면의 인증이 한데 묶입니다. 여기서 관리자 자격 증명을 요구하므로 /routes를 열어 두어도 그 자격 증명이 가리는 범위가 넓어지지 않습니다
POST /admin/api/accounts/claude {name, mode}로 Claude 브라우저 프로비저닝 시작. mode는 oauth 또는 setup_token이며, 생략하면 setup_token; {authorize_url} 반환
POST /admin/api/accounts/claude/{name}/complete <code>#<state>가 담긴 {code}로 Claude 프로비저닝 완료; 계정을 저장하고 실제 사용 여부(live)를 보고
POST /admin/api/accounts/claude/{name}/refresh imported Claude 계정의 refresh 그랜트를 즉시 실행해 로그인이 아직 살아 있는지 보고. 프로바이더 토큰 엔드포인트를 호출하므로 rate limit이 걸리며, 공용 크리덴셜 스토어를 반드시 경유해 프록시 경로의 갱신과 경합하지 않는다. 새 expires_at만 반환하고 토큰 물질은 절대 반환하지 않으며, 프로브 자신의 clear 이후 풀에서 다시 읽은 needs_relogin을 함께 싣는다 — 풀이 여전히 죽은 것으로 보는 계정에도 그랜트는 성공할 수 있으므로, /admin/api/pool과 모순되는 복구를 주장하지 않고 그대로 보고한다. setup_token 계정(refresh 그랜트 없음)이나 모든 종결 판정에는 400, 일시적 실패에는 502
DELETE /admin/api/accounts/claude/{name} 해당 이름 Claude 계정의 스토어 파일 제거
POST /admin/api/accounts/codex {name}으로 ChatGPT OAuth 시작; {authorize_url} 반환
POST /admin/api/accounts/codex/{name}/complete 전체 localhost redirect URL 또는 <code>#<state>가 담긴 {code}로 Codex 프로비저닝 완료
DELETE /admin/api/accounts/codex/{name} 해당 이름 Codex 계정의 스토어 파일 제거
POST /admin/api/accounts/antigravity {name}으로 Antigravity OAuth 시작; {authorize_url} 반환
POST /admin/api/accounts/antigravity/{name}/complete 전체 localhost redirect URL 또는 <code>#<state>가 담긴 {code}로 Antigravity 프로비저닝 완료
POST /admin/api/accounts/antigravity/{name}/refresh Antigravity 계정의 refresh 그랜트를 즉시 실행해 로그인이 아직 살아 있는지 보고. 위 Claude refresh 라우트와 같은 프로브
DELETE /admin/api/accounts/antigravity/{name} 해당 이름 Antigravity 계정의 스토어 파일 제거
GET /admin/assets/{*path} 내장된 관리자 SPA 번들 파일. 확장자에 해당하는 Content-Type과 X-Content-Type-Options: nosniff를 함께 반환합니다. --features ui로 빌드한 바이너리에만 존재
GET /admin/{*path} /admin 마운트 아래에서 다른 라우트에 걸리지 않은 경로에 대한 SPA 셸. 클라이언트 측 딥링크가 새로고침에도 유지됩니다. --features ui로 빌드한 바이너리에만 존재
GET, POST /backend-api/codex/responses 인바운드 Codex CLI 패스스루 — 실제 ChatGPT 백엔드 경로 미러
GET, POST /responses 인바운드 Codex CLI 패스스루 — bare base_url 형식
GET, POST /v1/responses 인바운드 Codex CLI 패스스루 — /v1 접미 base_url 형식
POST /backend-api/codex/alpha/search Codex CLI 웹 검색(web.run) 중계 — ChatGPT 형태 기본 경로
POST /alpha/search Codex CLI 웹 검색 중계 — bare base_url 형식
POST /v1/alpha/search Codex CLI 웹 검색 중계 — /v1 접미 base_url 형식
GET /models Codex CLI 모델 카탈로그 폴백 — {"models":[]} 반환
GET /backend-api/codex/models Codex CLI 모델 카탈로그 폴백 — ChatGPT 형태 기본 경로
POST /backend-api/codex/analytics-events/events Codex CLI 분석 sink — 수락 후 폐기하고 정제된 이벤트 이름 카운터만 기록
POST /codex/analytics-events/events Codex CLI 분석 sink — 루트형 chatgpt_base_url 형식
GET /usage 클라이언트용 정제된 풀 사용량 — 공유 계정 풀의 창별 잔여 여유와 리셋, 그리고 풀링되는 프로바이더별 동일 집계를 반환하며 계정 신원이나 용량은 반환하지 않음

/admin* 라우트는 [server.admin]이 구성된 경우에만 존재합니다; 그 테이블이 없으면 하나도 등록되지 않습니다. 관리자 자격 증명은 구성된 헤더 또는 x-api-key로 받으며, read_keys 자격 증명은 위의 모든 GET을 통과하지만 모든 변경 작업에서는 403으로 거부됩니다. 로그인은 할 수 있습니다: POST /admin/login이 이를 받아들여 read 등급 세션을 발급하고, 그 세션의 변경 작업도 같은 403으로 거부됩니다. 이 로그인 POST에는 same-origin 가드가 걸려 있습니다: 교차 사이트 폼 제출은 자격 증명을 검사하기도 전에 403으로 거부되므로, 어떤 자격 증명 보유자도 이미 로그인한 운영자의 세션 쿠키를 자기 것으로 바꿔치기할 수 없습니다. 스크립트 로그인은 영향을 받지 않습니다 — Sec-Fetch-Site와 Origin이 모두 없으면 검사를 통과합니다. 다만 SPA 셸과 번들 파일은 예외로, GET /admin(두 표기 모두), GET /admin/{*path}, GET /admin/assets/{*path}는 관리자 인증 없이 제공됩니다. 이들은 운영자 데이터를 담지 않고, SPA가 읽는 값은 모두 요청마다 인증하는 /admin/api/* 뒤에 있으므로 안전합니다. 와일드카드 라우트 둘은 [server.admin]이 구성되고 --features ui로 빌드한 바이너리에서만 존재합니다. GET /admin/api/observed는 게이트웨이 호스트에서 지원되는 Claude Code, Codex CLI, Gemini CLI, Kimi Code, Grok CLI, Cursor.app 자격 증명을 자동으로 탐색하며, 그 소스를 갱신하거나 쓰지 않습니다. 그 탐색을 건너뛰려면 [server.admin].hide_observed를 설정하세요: 라우트는 여전히 인증을 거친 뒤 { "accounts": [] }를 반환하고, GET /admin/api/session은 hide_observed: true를 보고하며, 대시보드는 그 요청을 건너뛰고 관리형 풀 계정만 나열합니다.

관리자 SPA 번들(--features ui)

/admin/assets/{*path}와 /admin/{*path} SPA 폴백은 --features ui로 빌드한 바이너리에만 존재하며, 이 빌드는 ui/ 패키지에서 만든 번들을 바이너리에 내장합니다. 기본 cargo build는 Node 툴체인이 필요 없고 번들도 없으며 두 라우트 모두 등록하지 않습니다. 미리 빌드된 릴리스 바이너리는 이 기능을 켜고 빌드합니다.

폴백은 /admin 마운트 안으로 한정됩니다:

  • /admin/ 아래에서 다른 라우트에 걸리지 않은 경로는 200과 text/html로 SPA 셸을 반환하므로, 클라이언트 측 딥링크가 새로고침에도 유지됩니다.
  • /admin/api/ 아래에서 걸리지 않은 경로는 Anthropic 오류 형태의 404를 반환합니다 — 이 네임스페이스는 UI가 아니라 JSON이며, HTML로 답하면 클라이언트의 오류 처리가 깨집니다.
  • 마운트 밖의 경로는 영향을 받지 않고 그대로 404입니다.

GET /admin도 셸이고, GET /admin/도 마찬가지입니다. 와일드카드 세그먼트는 빈 문자열에 매칭되지 않아 /admin/은 정확 일치 라우트에도 폴백에도 걸리지 않고 대시보드 자신의 루트에서 맨 404를 반환하게 되므로, 마운트 루트는 두 표기로 각각 등록합니다.

이 둘은 양쪽 빌드 모두에 등록되어 있으면서 응답이 피처에 따라 달라지는 관리자 경로로, 피처가 켜져 있으면 셸을, 꺼져 있으면 본문에 --features ui를 명시한 404를 반환합니다. 어느 쪽이든 등록해 두는 이유는 그 404가 해당 안내 문장을 담게 하기 위해서입니다 — 라우트를 아예 빼면 axum이 본문 없는 404를 돌려주고, 운영자는 그것을 [server.admin] 미설정과 구분할 수 없습니다.

관리자 경로 마이그레이션

호환성이 깨지는 변경입니다. 모든 관리자 JSON 라우트와 변경 라우트가 /admin/*에서 /admin/api/*로 이동했습니다. 이전 경로는 별칭으로 남지 않고 제거되어 이제 어떤 요청도 admin 핸들러에 도달하지 않습니다.

이전 경로에서 무엇이 돌아오는지는 빌드에 따라 다르므로, 그곳의 200을 성공으로 취급하면 안 됩니다:

  • 기본 빌드 — 경로가 어디에도 등록되지 않아 404를 반환합니다.
  • --features ui (미리 빌드된 릴리스 바이너리가 이쪽입니다) — GET은 마운트 하위의 다른 딥링크와 마찬가지로 /admin/{*path} SPA 폴백으로 넘어가 200 text/html 셸을 반환합니다. HEAD도 같습니다. 그 외 메서드는 Allow: GET,HEAD와 함께 405를 반환합니다 — 폴백이 any가 아니라 get으로 등록돼 있기 때문입니다.

따라서 이전 GET URL에 남아 있는 스크립트는 마이그레이션 신호가 아니라 HTML을 받습니다. /admin/api/*로 옮기세요. 응답의 Content-Type이 확실한 판별 기준입니다.

/admin은 대시보드 셸로 남고, /admin/login과 /admin/oidc/callback도 그대로입니다 — 이들은 API 라우트가 아니라 서버에서 렌더링되는 페이지입니다. 나머지는 모두 이동했으며, 이는 대시보드가 /admin/*을 탐색 가능한 딥 링크로 쓸 수 있게 하기 위해서입니다: 한 경로가 JSON 엔드포인트인 동시에 클라이언트 측 라우트일 수는 없으므로 호환용 별칭은 남기지 않았습니다.

스크립트로 호출하는 쪽은 기계적으로 한 번만 고치면 됩니다 — 경로에는 /admin 뒤에 /api 세그먼트 하나가 추가됩니다:

이전 이후
GET /admin/accounts GET /admin/api/accounts
GET /admin/accounts/codex GET /admin/api/accounts/codex
GET /admin/observed GET /admin/api/observed
GET /admin/pool GET /admin/api/pool
GET /admin/status GET /admin/api/status
POST /admin/accounts/claude POST /admin/api/accounts/claude
POST /admin/accounts/claude/{name}/complete POST /admin/api/accounts/claude/{name}/complete
POST /admin/accounts/claude/{name}/refresh POST /admin/api/accounts/claude/{name}/refresh
DELETE /admin/accounts/claude/{name} DELETE /admin/api/accounts/claude/{name}
POST /admin/accounts/codex POST /admin/api/accounts/codex
POST /admin/accounts/codex/{name}/complete POST /admin/api/accounts/codex/{name}/complete
DELETE /admin/accounts/codex/{name} DELETE /admin/api/accounts/codex/{name}
POST /admin/oidc/start POST /admin/api/oidc/start
POST /admin/logout POST /admin/api/logout

인증은 그대로입니다: 같은 관리자 자격 증명을 같은 헤더 또는 x-api-key로 보내며, 읽기/쓰기 등급도 동일합니다.

spend-limit 라우트는 부팅 시 [server.spend]가 구성된 경우에만 존재하며, [server.admin] 자격 증명으로 인증하므로 [server.gateway]와는 무관합니다. 자격 증명은 구성된 관리자 헤더(기본값 x-shunt-admin-token) 또는 x-api-key로 보냅니다 — 두 슬롯 모두 허용됩니다. 쓰기 자격 증명(write_keys 항목 또는 tokens_env/tokens_file 쌍)은 모든 작업을 사용할 수 있고, read_keys 자격 증명은 GET만 사용할 수 있으며 변경 작업에서는 403을 받습니다. POST는 user와 organization scope, daily/weekly/monthly period, user scope에서는 1–256바이트인 user_id, 1–19자리의 음수가 아닌 USD 센트 정수 문자열 또는 null인 amount를 받아 (scope, period) 기준으로 upsert합니다. 목록 페이지네이션은 limit(1–1000, 기본값 20), after_id, before_id, scope_type을 받으며 두 커서는 함께 사용할 수 없습니다. 모든 응답에는 request-id가 포함되고 오류는 Anthropic 오류 형태를 사용합니다. 제한과 변경 감사 레코드는 구성한 버전 JSON 상태 파일에 함께 저장되며, 각 변경은 admin-key:<id> 또는 admin-token:<name>으로 귀속됩니다 — 두 슬롯이 같은 등급의 서로 다른 자격 증명을 실은 경우 구성된 관리자 헤더 쪽이 귀속 대상입니다. GET /v1/organizations/spend_limits/effective(read 또는 write 자격 증명)는 주체·기간마다 한 행씩, 적용 상한(amount, source, spend_limit_id)과 미국 센트 단위 period_to_date_spend를 반환합니다. limit(1–1000, 기본값 20, 주체 수 기준), period[], user_ids[](최대 100개, 페이지네이션 없음), q, sort=spend_desc(period[]가 정확히 하나일 때), page를 받고 잘못된 입력에는 400 invalid_request_error로 응답합니다. period_to_date_spend는 meter가 읽을 수 있었던 카운터만 반영합니다. 저장된 카운터 레코드 복원에 실패한 주체는 unavailable 플래그가 풀릴 때까지 지출이 0이나 일부로만 보일 수 있으며, 로그의 복원 경고에 해당 주체가 기록됩니다. 제한은 /v1/messages와 인바운드 Codex 엔드포인트의 Responses 라우트 및 /alpha/search 별칭에 적용되며(상한을 넘은 Codex 턴은 429 usage_limit_reached를 받습니다. 인바운드 Codex 엔드포인트 참고), passthrough 또는 type = "noop" 라우트만으로 이루어진 체인에는 적용하지 않습니다. /audit은 노출하지 않습니다.

/user/bootstrap 라우트는 부팅 시 [server.gateway]가 활성화된 경우에만 존재하며 유효한 게이트웨이 bearer JWT를 요구합니다. static [server.auth] 토큰으로는 인증되지 않습니다. [server.gateway.desktop_bootstrap] 템플릿을 application/json으로 반환하며, 문자열 값 안의 ${user.email}, ${user.sub}, ${user.name}은 치환됩니다. 오류와 304를 포함한 모든 응답에 Cache-Control: no-store가 붙고, 라우트는 리다이렉트하지 않습니다.

상태 오류 타입 의미
200 해당 없음 템플릿 본문과 quoted ETag("sha256:<body-hash>")
304 해당 없음 If-None-Match가 현재 ETag와 일치; 빈 본문
401 authentication_error 게이트웨이 bearer가 없거나, 유효하지 않거나, 만료됨
403 permission_error 유효한 bearer이지만 [[server.gateway.policies]]상 대상이 아님
404 not_found_error desktop_bootstrap 미구성
500 api_error 템플릿을 읽을 수 없게 되었거나 더 이상 JSON object가 아님

policy가 없으면 로그인한 모든 사용자가 대상이고, policy가 있으면 policy의 match.emails에 포함되거나 catch-all policy(match 없음)가 있을 때 대상이 됩니다. 디바이스 코드 엔드포인트는 client_id가 없는 요청(Claude Desktop은 보내지 않습니다)과 client_id=claude-code 요청을 받으며, 다른 값은 거부합니다. client_id가 없는 요청에서 거부된 refresh 토큰은 400 {"error":"invalid_grant"}를 반환하고, claude-code 요청은 401을 유지합니다. Claude Desktop 연결을 참고하세요.

GET /managed/settings와 POST /v1/{metrics,logs,traces} 텔레메트리 ingest 라우트는 부팅 시 [server.gateway]가 활성화된 경우에만 존재하며, 둘 다 같은 게이트웨이 bearer JWT를 요구합니다. ingest 라우트는 관리형 Claude Code 클라이언트가 export하는 OTLP/HTTP 페이로드를 받아([server.gateway.telemetry]가 그 exporter들을 게이트웨이로 향하게 합니다) 요청 바이트를 해당 signal에 opt-in한 모든 목적지로 그대로 relay합니다. 인바운드 content-type과 content-encoding은 유지되고 목적지에 구성된 headers가 그 위에 적용됩니다(구성된 키는 전달값을 대체하며 헤더를 중복시키지 않습니다). 클라이언트의 Authorization 헤더는 전달되지 않고 relay는 리다이렉트를 따르지 않습니다. 목적지는 signal별로 opt-in하며(metrics 기본 on, logs/traces 기본 off), 어떤 목적지도 opt-in하지 않은 signal은 수신 후 폐기됩니다. relay는 분리되어 실행되므로 목적지 상태와 무관하게 응답은 항상 즉시 200이고, 성공 바디는 OTLP/HTTP에 따라 요청 프로토콜을 미러링합니다(application/json에는 {}, 그 외에는 빈 application/x-protobuf 바디). 32 MiB 인바운드 상한을 넘는 바디는 413을 받습니다.

인바운드 Codex Responses, 웹 검색, 모델 카탈로그, 분석 라우트는 [server.codex_endpoint]가 구성된 경우에만 존재합니다. Responses 라우트는 OpenAI Responses 요청과 응답을 HTTP/SSE(POST) 또는 WebSocket 업그레이드(GET)로 그대로 중계하며, [[server.codex_endpoint.routes]]로 모델별로 다른 Responses 호환 업스트림에 라우팅할 수도 있습니다. Codex 전용 두 모델 경로는 {"models":[]}을 반환하고, 공유 /v1/models는 쿼리에 client_version이 있을 때만 그 형태를 반환하며, 없으면 기존 Anthropic 계약을 유지합니다. 모든 카탈로그 변형은 일반 모델 탐색 인증 게이트를 사용합니다. 두 분석 라우트는 같은 인바운드 인증 정책을 적용하고, 클라이언트 payload를 전달하거나 보관하지 않으며, 인증 후에는 잘못된 JSON이나 초과 크기 본문에도 200 {}를 반환합니다. 정제된 이벤트 이름만 shunt.codex_client_events에 기록되며, 메트릭 sink가 없으면 순수 폐기 sink로 동작합니다. 세 웹 검색 경로는 Codex CLI의 내장 웹 검색을 Responses 경로와 같은 계정 풀과 인바운드 인증 정책으로 백엔드의 /codex/alpha/search에 그대로 중계합니다. POST만 받으며 [[server.codex_endpoint.routes]] 항목은 따르지 않습니다.

/usage 라우트는 [server.usage]가 구성된 경우에만 존재하며, [server.auth] 또는 [server.gateway]도 필요합니다. GET /v1/messages와 같은 클라이언트 토큰이나, Authorization: Bearer로 보낸 게이트웨이 로그인 액세스 토큰(shunt gateway claude로 시작한 세션이 보내는 값)으로 인증합니다. 유효한 게이트웨이 로그인은 [server.auth]를 거치지 않고 받아들이므로, [[server.auth.jwt]] 키 세트에 접근할 수 없어도 막히지 않습니다. 공유 계정 풀의 창별 잔여 여유(해당 창을 보고한 비활성 아님 계정들의 mean(clamp(cap - utilization, 0, 1)). cap은 그 창에 대해 계정에 적용되는 max_utilization 하드 캡이며 적용되는 캡이 없으면 1.0입니다. 즉 캡이 계정을 제외하기 전까지 풀 전체 용량 중 아직 쓸 수 있는 비율. 캡이 이미 해당 창의 요청에서 제외한 계정은 0으로 계산되며, 5h 또는 7d 캡은 Fable 요청에서도 그 계정을 제외합니다), 그 계정들이 보고한 리셋 시각 중 가장 이른 값(캡 때문에 0으로 계산되는 계정은 그 캡이 풀리는 시각 포함), ok/degraded/exhausted/capped 상태를 반환합니다. 계정 신원, 수, priority, disabled, 임계값, 계정별 수치는 공개하지 않습니다. 비활성 계정이 아닌 계정 중 해당 창을 보고한 계정이 하나도 없을 때만 null입니다. Codex 응답의 x-codex-* 헤더와 선택적인 wham/usage 폴링은 관측된 5시간 및 공유 주간 창을 채웁니다. WebSocket 전송에서는 스트림 안의 codex.rate_limits 이벤트가 재사용 연결을 포함한 모든 턴에서 같은 창을 채웁니다. Codex에는 Fable 범위(7d_oi) 신호가 없지만 혼합 프로바이더 풀에서는 다른 프로바이더가 집계 Fable 값을 제공할 수 있습니다. pool은 풀링되는 모든 프로바이더를 통틀은 집계이고, providers는 같은 정제된 집계를 풀링되는 프로바이더별로 구성된 프로바이더 이름을 키로 담으므로, 특정 프로바이더로 라우팅하는 클라이언트는 풀 전체 평균 대신 해당 프로바이더의 여유분과 상태를 읽을 수 있습니다. 풀링되지 않는 인증 모드의 프로바이더는 생략됩니다. 전체 응답 형태는 영문 엔드포인트 레퍼런스를 참고하세요. Claude Code 클라이언트라면 curl 없이도 읽을 수 있습니다. 이 저장소의 플러그인 마켓플레이스에 있는 shunt 모드가 /shunt:usage를 이 엔드포인트로 답하며, 창별 잔여 여유와 리셋 시각을 출력합니다. 함수 훅(CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1)이 필요하며 아직 얼리 액세스입니다.

풀 상태 capped는 사용 가능한 계정이 없고 활성화된(disabled가 아닌) 계정 중 일시 정지되지 않은 계정 하나 이상이 max_utilization* 하드 캡으로 제외되었음을 뜻하며([server.pool] 참고), exhausted와는 구분됩니다.

GET /와 GET /health는 [server.auth]가 활성화되어 있어도 열린 채로 유지되며(헬스체크 도구는 보통 토큰을 첨부할 수 없음) 민감한 것을 노출하지 않습니다 — 오직 상태, 버전, 그리고 이미 공개된 엔드포인트 목록만입니다. [[server.auth.jwt]] 항목을 구성하면 Authorization: Bearer의 검증된 외부 JWT가 클라이언트 토큰과 같은 게이팅 라우트를 인증합니다. 어떤 항목으로도 검증되지 않은 토큰은 401이고, 검증된 항목이 없으면서 토큰의 issuer와 일치하는 항목 중 캐시된 key set이 없는데 가져오기도 실패한 것이 있으면 503입니다.

게이트웨이 프로토콜

shunt는 공식 Claude Code LLM 게이트웨이 프로토콜을 구현합니다: 올바른 헤더 및 바디 필드 전달, 기능 패스스루, 시스템 프롬프트 어트리뷰션 처리. 게이트웨이 소유 오류는 Anthropic 오류 형태로 반환되고, 업스트림 컨텍스트 오버플로 오류는 Anthropic의 prompt is too long 표현으로 다시 쓰여 Claude Code의 압축-재시도가 발동하며, 스트리밍 응답은 버퍼링 없이 릴레이됩니다(선택적 keepalive ping 포함).

Navigation

Type to search…

↑↓ navigate↵ selectEsc close