API 레퍼런스
SUB&SUB는 https://api.subnsub.com/v1에서 멀티 프로바이더 릴레이를 제공합니다. OpenAI 클라이언트는 /v1/chat/completions를, Anthropic 클라이언트는 /v1/messages를 호출합니다. 동일한 sk-cf-... 키가 양쪽 모두를 라우팅합니다 — 요청 본문에서 모델을 선택하면 릴레이가 업스트림을 선택합니다.
빠른 시작
필요한 세 가지:
- Base URL:
https://api.subnsub.com/v1(OpenAI 클라이언트) 또는https://api.subnsub.com(Anthropic 클라이언트 — SDK가 직접/v1/messages를 덧붙입니다) - API 키: 콘솔에서 발급된
sk-cf-... - 모델: 검증된 21개 모델 중 하나 — 예:
gpt-5.4-mini또는claude-haiku-4.5
인증
모든 요청에는 Authorization: Bearer sk-cf-... 헤더가 포함되어야 합니다. 키는 콘솔에서 발급되며 SHA-256 해시로 저장됩니다 — 생성 화면을 벗어나면 평문은 영구히 사라지므로 즉시 저장하세요.
엔드포인트
POST /v1/chat/completions
채팅 완성 요청을 보냅니다. 요청 형식은 OpenAI Chat Completions API와 동일합니다 — OpenAI SDK가 수정 없이 작동합니다.
| 파라미터 | 타입 | 설명 |
|---|---|---|
| model | string | 검증된 모델 ID 중 하나입니다. |
| messages | array | 대화 기록입니다. 각 항목: {role, content}, role ∈ system / user / assistant. |
| stream | boolean | true이면 응답이 SSE 청크로 전송됩니다. 스트리밍 참조. |
| stream_options | object | 선택 사항. 릴레이는 항상 업스트림에 {include_usage: true}를 강제하여 마지막 청크가 토큰 사용량 블록을 담도록 합니다 — 이를 재정의해도 효과가 없습니다. |
| max_tokens | integer | 완성 길이를 제한합니다. 기본값은 모델의 최대치입니다. |
| temperature | number | 0 – 2. 높을수록 무작위성이 커집니다. |
POST /v1/messages
claude-* 모델을 위한 Anthropic 네이티브 엔드포인트입니다 — Anthropic SDK(anthropic-sdk-python, @anthropic-ai/sdk, claude-code)가 이 경로에 대해 수정 없이 작동합니다. base URL을 https://api.subnsub.com로 지정하고 x-api-key 헤더로 인증하세요(클라이언트가 선호한다면 Authorization-Bearer 방식도 작동합니다).
| 파라미터 | 타입 | 설명 |
|---|---|---|
| model | string | claude-* 모델 ID입니다(사용 가능한 모델 참조). 여기에 OpenAI 모델을 전달하면 400 invalid_request_error가 반환됩니다. |
| max_tokens | integer | Anthropic 필수 항목 — 어시스턴트 응답 길이를 제한합니다. |
| messages | array | 대화 기록, Anthropic 형식: {role, content}, role ∈ user / assistant. |
| stream | boolean | true이면 표준 Anthropic SSE 이벤트 시퀀스를 반환합니다: message_start, content_block_delta, message_delta, message_stop. |
| thinking | object | 그대로 전달됩니다. 확장 사고를 활성화하려면 -thinking 모델 변형과 함께 사용하세요. |
| cache_control | object | 프롬프트 캐싱이 지원됩니다. 캐시 쓰기 토큰은 티어 입력 단가의 1.25×로, 캐시 읽기 토큰은 0.10×로 청구됩니다. |
GET /v1/models
실제로 호출 가능한 모델을 나열합니다. 릴레이는 sub2api에서 가져온 OpenAI 및 Anthropic 카탈로그를 병합하고, 현재 계정 풀에 대해 엔드투엔드 테스트를 마친 21개로 필터링합니다 — 라우팅 시점에 503을 내는 유령 ID나 첫 토큰에서 업스트림 400을 내는 ID는 숨겨집니다. 구성된 모든 업스트림에 연결할 수 없으면 이 엔드포인트는 오해를 일으키는 빈 목록 대신 502 models_unreachable을 반환합니다.
# sample response (truncated)
{
"object": "list",
"data": [
{ "id": "gpt-5.4-mini", "type": "model", ... },
{ "id": "gpt-5.4", "type": "model", ... },
{ "id": "claude-sonnet-4.5", "type": "model", ... },
{ "id": "claude-haiku-4.5", "type": "model", ... },
...
]
}
사용 가능한 모델
두 가지 업스트림 패밀리가 있습니다. 7개의 OpenAI 모델은 공유 ChatGPT급 계정으로 라우팅되고, 14개의 Claude 모델은 Kiro 리버스 프록시를 거쳐 AWS CodeWhisperer로 라우팅됩니다. 토큰당 단가는 티어에 따라 다릅니다(요금 참조) — 동일한 키가 양쪽 모두에서 작동합니다.
OpenAI
| 모델 ID | 패밀리 | 티어 | 비고 |
|---|---|---|---|
| gpt-5.4-mini | GPT-5.4 | Mini | 빠르고 저렴함. 채팅 & 코딩의 권장 기본값. |
| gpt-5.3-codex | Codex | Mini | 코딩에 튜닝된 5.3. mini와 동일 가격. |
| gpt-5.2 | GPT-5.2 | Standard | 안정 버전 5.2. |
| gpt-5.2-chat-latest | GPT-5.2 | Standard | 최신 5.2 채팅 튜닝을 자동 추적(현재 업스트림 gpt-5.2로 매핑). |
| gpt-5.4 | GPT-5.4 | Standard | 풀사이즈 GPT-5.4 — 더 느리지만 더 강한 추론. |
| gpt-5.4-2026-03-05 | GPT-5.4 | Standard | gpt-5.4의 날짜 스냅샷. |
| gpt-5.5 | GPT-5.5 | Premium | 최신 플래그십. |
Anthropic
| 모델 ID | 패밀리 | 티어 | 비고 |
|---|---|---|---|
| claude-haiku-4.5 | Haiku 4.5 | Mini | 가장 작은 Claude — gpt-5.4-mini와 동일한 토큰당 단가. |
| claude-haiku-4.5-thinking | Haiku 4.5 | Mini | haiku-4.5의 확장 사고 변형. thinking 요청 필드와 함께 사용하세요. |
| claude-sonnet-4.5 | Sonnet 4.5 | Standard | 중간 티어 Claude — gpt-5.4와 동일한 토큰당 단가. |
| claude-sonnet-4.5-thinking | Sonnet 4.5 | Standard | sonnet-4.5의 확장 사고 변형. |
| claude-sonnet-4.6 | Sonnet 4.6 | Standard | 최신 Sonnet 튜닝 — Standard 티어, sonnet-4.5와 동일 단가. |
| claude-sonnet-4.6-thinking | Sonnet 4.6 | Standard | sonnet-4.6의 확장 사고 변형. |
| claude-opus-4.5 | Opus 4.5 | Ultra | 프런티어 Claude. Anthropic 리스트 가격으로 청구 — 마진 없음(요금 참조). |
| claude-opus-4.5-thinking | Opus 4.5 | Ultra | opus-4.5의 확장 사고 변형(적응형 사고). |
| claude-opus-4.6 | Opus 4.6 | Ultra | 최신 Opus 튜닝. |
| claude-opus-4.6-thinking | Opus 4.6 | Ultra | opus-4.6의 확장 사고 변형. |
| claude-opus-4.7 | Opus 4.7 | Ultra | 이전 Opus 스냅샷. |
| claude-opus-4.7-thinking | Opus 4.7 | Ultra | opus-4.7의 확장 사고 변형. |
| claude-opus-4.8 | Opus 4.8 | Ultra | 최신 Opus 스냅샷. |
| claude-opus-4.8-thinking | Opus 4.8 | Ultra | opus-4.8의 확장 사고 변형. |
gpt-5.2-pro, gpt-5.2-pro-2025-12-11), gpt-4o, gpt-4o-mini, gpt-5, gpt-5-mini, 이미지 / 오디오 / 실시간 변형, claude-haiku-4-6, 그리고 날짜가 붙은 업스트림 ID(예: claude-sonnet-4-5-20250929). 이들을 호출하면 400 model_not_available이 반환됩니다. Pro 모델은 풀에 있는 소셜 티어 계정이 몇 번의 요청만으로도 작은 할당량을 소진해 버리기 때문에 메뉴에서 제외되어 있습니다.
추론 강도
위의 모든 OpenAI 모델은 추론 모델입니다 — 백엔드는 가시적인 출력을 내기 전에 더 많거나 적은 "사고" 토큰을 사용할 수 있습니다. OpenAI /v1/chat/completions 요청 본문에 reasoning_effort를 설정해 예산을 제어하세요. Claude의 경우 Anthropic 네이티브 thinking 요청 필드를 사용하거나 -thinking 모델 변형을 선택하세요 — /v1/messages 섹션을 참조하세요. OpenAI 모델은 동일한 다섯 가지 강도 값을 받습니다:
| 값 | 동작 |
|---|---|
| none | 사고 없음 — 곧바로 답변. 가장 저렴하고 빠릅니다. |
| low | 짧은 추론 단계. |
| medium | 필드를 전달하지 않을 때의 기본값. 균형 잡힘. |
| high | 더 깊은 추론. 비단순 코딩 / 다단계 문제에 권장. |
| xhigh | 최대 강도. 가장 느리고 비쌈; 정말 필요한 어려운 분석에만 사용하세요. |
# Two equivalent forms — pick whichever your SDK supports
{
"model": "gpt-5.4-mini",
"reasoning_effort": "high",
"messages": [ ... ]
}
{
"model": "gpt-5.5",
"reasoning": { "effort": "xhigh" },
"messages": [ ... ]
}
'minimal'도 정의하지만, 저희 풀의 모델은 이를 거부합니다: "'minimal' is not supported with this model". 위의 다섯 가지 값을 사용하세요.
스트리밍
Server-Sent Events를 받으려면 "stream": true로 설정하세요. 마지막 청크는 usage 블록을 담고(업스트림에 stream_options.include_usage를 강제하므로 토큰 수가 항상 방출됩니다), 그다음 리터럴 data: [DONE]이 스트림을 닫습니다.
# Streaming format (line by line)
data: {"id":"resp_...","choices":[{"delta":{"content":"Hi"}}]}
data: {"id":"resp_...","choices":[{"delta":{"content":"!"}}]}
data: {"id":"resp_...","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":11,"total_tokens":29}}
data: [DONE]
웹 검색
엔드포인트가 지원하는 모든 모델 ID에 :online을 덧붙이면 릴레이가 모델로 전달하기 전에 웹 검색을 실행하고, 그 결과를 대화 앞에 추가해 답변이 최신 데이터에 근거하도록 합니다. 이 접미사는 /v1/chat/completions와 /v1/messages에서 작동합니다(후자는 여전히 claude-* 베이스가 필요합니다). 검색 전용 요청 필드는 필요하지 않습니다.
# Same call as before — just :online on the model
curl https://api.subnsub.com/v1/chat/completions \
-H "Authorization: Bearer sk-cf-xxx" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4-mini:online",
"messages": [
{"role": "user", "content": "What did Anthropic ship this week?"}
]
}'
작동 방식: 릴레이는 :online을 제거하고, 가장 최근 사용자 메시지를 쿼리로 삼아(400자로 제한) Tavily를 호출해 가능하면 추출된 페이지 텍스트와 함께 최대 3개의 결과를, 그리고 선택적으로 Tavily가 생성한 요약을 받은 다음, 요청을 업스트림으로 보내기 전에 명확히 구분된 <search_results> 블록으로 그 동일한 사용자 턴 앞에 추가합니다. 검색 호출에는 8초 타임아웃이 있습니다. 결과는 의도적으로 user 역할에 주입되며 — 시스템 프롬프트에는 절대 주입되지 않습니다 — 따라서 신뢰할 수 없는 조각이 시스템 우선순위 지시로 격상될 수 없습니다.
<search_results> 블록은 다음과 같이 보입니다. 그 앞에는 모델에게 이 블록을 신뢰할 수 없는 외부 데이터로 취급하고 번호가 매겨진 항목을 인라인으로 인용하라고 알리는 한 줄짜리 지시가 붙습니다:
<search_results query="What did Anthropic ship this week?" retrieved="2026-05-21">
Summary: <short LLM-generated synthesis of the result set>
[1] Anthropic launches Opus 4.8
URL: https://www.anthropic.com/news/opus-4-8
<extracted page text, or short snippet if extraction failed — up to ~2000 chars>
[2] ...
</search_results>
| 동작 | 상세 |
|---|---|
| 비용 | 현재 추가 요금 없음 — 모델의 일반 토큰당 단가만 지불하며, 검색 호출 비용은 릴레이가 흡수합니다. 주입된 <search_results> 블록은 입력 토큰으로 계산되므로 :online 없이 동일한 질문을 했을 때보다 프롬프트 토큰 청구가 더 높아질 수 있습니다. |
| 실패 모드 | 소프트. Tavily가 타임아웃되거나 오류가 나면 요청은 검색 컨텍스트 없이 모델로 계속 진행됩니다(여전히 답변은 받지만 근거가 없을 뿐입니다). 유일한 하드 실패는 릴레이에 검색이 전혀 구성되어 있지 않을 때의 503 search_unavailable입니다. |
| count_tokens | /v1/messages/count_tokens는 접미사를 제거하지만 Tavily를 호출하지는 않습니다 — 카운트는 증강된 프롬프트가 아니라 원래 프롬프트를 반영합니다. |
| 멀티턴 | 마지막 사용자 턴만 쿼리되고 증강됩니다; 이전 턴은 손대지 않습니다. 다시 검색하려면 모델에 :online을 그대로 둔 채 새 사용자 메시지를 보내세요. |
:online을 사용할 시점
릴레이는 요청당 한 번의 Tavily 호출을 하고 결과를 주입합니다 — 에이전트형 검색 루프가 아닙니다. 모델은 Perplexity Sonar나 ChatGPT 브라우즈 도구처럼 본 내용에 따라 재검색을 결정하지 않습니다. 이 한계를 염두에 두고 계획하세요:
| 적합 | 부적합 |
|---|---|
| 시의성 있는 사실(뉴스, 가격, 버전 번호, 출시일) | 공개 웹에 없는 비공개 또는 붙여넣은 코드 — 근거 없이 프롬프트 노이즈만 늘립니다 |
| 공식 문서나 공지 찾기 | 수학, 추론, 번역, 창작 — 근거로 삼을 것이 없음 |
| 원래라면 검색으로 확인했을 모든 것 | 이미 학습 데이터에 있는 안정적인 지식("이진 트리란 무엇인가") |
마지막 사용자 메시지를 독립적인 검색 쿼리로 작성하세요. 검색은 가장 최근 사용자 턴의 리터럴 텍스트(400자로 제한)에 대해 실행되므로, "그럼 최신 버전은?" 같은 대화형 후속 질문은 컨텍스트가 없는 쓸모없는 쿼리가 됩니다. 멀티턴 채팅에서 :online을 추가할 때는 주제를 다시 기술하세요 — 예: "the latest one"이 아니라 "latest version of the Anthropic Python SDK"처럼.
다단계 종합이 필요한 질문(비교·대조, 심층 리서치)은 여러 턴으로 나누고 각각에 :online을 추가하세요. 모델은 각 턴의 새로운 결과를 읽으며, 다음 쿼리는 직접 조정하면 됩니다. 주입된 <search_results> 블록은 업스트림으로만 전송된다는 점에 유의하세요 — 클라이언트로 다시 반향되지 않으며 다음 요청에 보존되지도 않으므로, 이후 턴이 이전 출처의 세부 정보에 의존한다면 모델에게 그것을 가시적인 응답에 요약하도록 요청하세요. 원샷 리서치 모드는 지원되지 않습니다.
reasoning_effort: "high")와 결합해 모델이 첫 결과에 기대는 대신 반환된 출처를 실제로 따져보도록 하세요. 주입된 지시는 모델에게 번호가 매겨진 출처를 [1], [2]처럼 인라인으로 인용하라고 요청하므로 출력에는 보통 그러한 인용이 포함됩니다 — 다만 모델이 그 형식에 엄격히 구속되지는 않습니다.
오류
엔벨로프는 호출한 엔드포인트에 따라 달라집니다 — 릴레이는 호출자의 SDK에 맞는 프로토콜로 오류를 반환하며, 업스트림 오류는 그대로 전달됩니다.
OpenAI 경로(/v1/chat/completions, /v1/responses, /v1/models) — OpenAI 엔벨로프:
{ "error": { "message": "...", "type": "...", "code": "..." } }
Anthropic 경로(/v1/messages, /v1/messages/count_tokens) — Anthropic 엔벨로프:
{ "type": "error", "error": { "type": "...", "message": "..." } }
Anthropic 엔벨로프는 다른 형식을 사용합니다 — code 필드가 없고, 판별자 type: "error"가 최상위에 있습니다(내부 error.type이 카테고리를 제공, 예: authentication_error, invalid_request_error, permission_error, api_error). Anthropic SDK는 이미 이 형식을 파싱합니다; 일반 OpenAI SDK 오류 핸들러는 그렇지 않으므로 /v1/messages는 Anthropic SDK로 호출하세요(또는 raw HTTP를 사용하세요).
상태 코드는 두 프로토콜 모두에서 표준 HTTP 코드입니다:
| 상태 | OpenAI code / Anthropic error.type | 의미 |
|---|---|---|
| 401 | invalid_api_key / authentication_error | sk-cf-... 키가 없거나 알 수 없습니다. |
| 402 | insufficient_balance / permission_error | 계정 잔액이 마이너스입니다. 콘솔 청구 탭에서 충전하세요. |
| 403 | key_revoked / permission_error | 키가 취소되었습니다. |
| 400 | model_not_available / invalid_request_error | 보낸 model이 검증된 카탈로그에 없거나 엔드포인트에 맞지 않습니다(예: /v1/messages에 OpenAI 모델) — 사용 가능한 모델을 확인하세요. |
| 503 | — | 현재 요청을 처리하는 업스트림 계정이 없습니다 — 대개 설정 문제가 아니라 풀 전체의 레이트 리밋 구간입니다. |
| 503 | search_unavailable / api_error | :online을 사용했지만 이 릴레이에 웹 검색이 구성되어 있지 않습니다. 웹 검색을 참조하세요. |
| 502 | upstream_unreachable / api_error | 릴레이가 백엔드에 연결하지 못했습니다. 짧은 백오프 후 재시도하세요. |
요금 및 청구
종량제이며, 마이크로달러 단위로 토큰당 청구됩니다(1마이크로 = $0.000001 = 1센트의 1/10,000)므로 1센트 미만 요청도 정확히 추적됩니다. 단가는 티어별 1M 토큰 기준입니다 — 각 모델이 어느 티어에 매핑되는지는 모델 표를 참조하세요.
| 티어 | 모델 | 입력 / 1M | 출력 / 1M |
|---|---|---|---|
| Mini | gpt-5.4-mini, gpt-5.3-codex, claude-haiku-4.5, claude-haiku-4.5-thinking | $0.20 | $1.60 |
| Standard | gpt-5.2, gpt-5.2-chat-latest, gpt-5.4, gpt-5.4-2026-03-05, claude-sonnet-4.5, claude-sonnet-4.5-thinking, claude-sonnet-4.6, claude-sonnet-4.6-thinking | $0.75 | $6.00 |
| Premium | gpt-5.5 | $1.10 | $8.80 |
| Ultra | claude-opus-4.5, claude-opus-4.5-thinking, claude-opus-4.6, claude-opus-4.6-thinking, claude-opus-4.7, claude-opus-4.7-thinking, claude-opus-4.8, claude-opus-4.8-thinking | $5.00 | $25.00 |
Ultra 티어 단가는 Anthropic이 공개한 Opus 리스트 가격과 동일합니다 — 그대로 패스스루, 마진 없음. 다른 티어는 풀링된 구독 기반 덕분에 업스트림 단가보다 낮게 운영됩니다.
추론 토큰(OpenAI에서 reasoning_effort를 설정하거나 Claude -thinking 변형을 사용할 때)은 모델 티어 단가의 출력 토큰으로 계산됩니다 — 높은 강도에 대한 별도 추가 요금은 없지만, 심층 사고 요청은 노력 없는 요청보다 출력 토큰을 쉽게 10–50× 더 방출할 수 있으므로 달러 청구액도 그에 비례합니다.
Anthropic 프롬프트 캐싱은 별도 항목으로 청구됩니다: 캐시 쓰기는 티어 입력 단가의 1.25×, 캐시 읽기는 0.10×입니다. 따라서 haiku-4.5 캐시 적중 비용은 0.20 × 0.10 = $0.02 per 1M tokens, sonnet-4.5 캐시 적중 비용은 0.75 × 0.10 = $0.075 per 1M tokens입니다. 캐시 열은 각 정산 행에 기록되어 콘솔이 세부 내역을 표시할 수 있습니다.
잔액은 각 요청이 반환될 때 실시간으로 차감됩니다 — 스트리밍 요청의 경우 [DONE] 청크가 도착한 후 정산이 실행됩니다. 실시간 잔액과 요청별 정산은 /console#billing에서 확인하세요.
사용량 제한
현재 키별 레이트 리밋은 없습니다. 업스트림 계정 풀의 동시성 & OpenAI 서버 측 스로틀링이 적용됩니다; 이에 걸리면 릴레이는 retry-after 헤더와 함께 429를 반환합니다. 키별 RPM / TPM 제한은 MVP 이후에 도입될 예정입니다.