BazaarLinkBazaarLink
로그인
문서API 레퍼런스SDK 레퍼런스에이전트 사용법AI 스킬

BazaarLink 문서

BazaarLink은 대만을 위한 통합 AI API 게이트웨이로 — OpenAI, Anthropic, Google, Meta 등 수백 개의 모델에 단일 OpenAI 호환 API 엔드포인트를 통해 접근할 수 있습니다.

AI 에이전트 스킬 파일
아래 스킬 파일을 AI 어시스턴트(Claude, Cursor, Copilot…)에 로드하여 BazaarLink API에 대한 전체 지식을 제공하세요:
Read https://bazaarlink.ai/skill.md and follow the instructions to integrate BazaarLink into your app.
무료 모델 및 속도 제한
무료 모델, 분당 요청 한도, 무료 크레딧에 대한 정보는 다음을 참고하세요: 속도 제한 · 자주 묻는 질문

요금제

BazaarLink는 제로 마크업으로 모델 사용 가격을 책정합니다(각 공급자의 공식 정가와 동일). 플랫폼 수수료는 충전(입금) 시 부과됩니다: 10% 거래 수수료와 TWD 채널의 5% 대만 VAT. TWD 견적 및 전자 통합 송장과 함께 USD로 청구됩니다. 셀프 서비스 종량제 충전; 기업은 월별 청구서를 준비할 수 있습니다(Net-30, 협상 가능).

작동 방식

  • 소비(차변): 각 API 호출은 공급자의 공식 USD 정가에 따라 실제 토큰 사용량에 따라 청구되며 잔고에서 공제됩니다. 추가 인상이 없고 소비에 대한 추가 수수료가 없습니다.
  • 탑업(입금): TWD가 실시간 판매율로 USD로 변환되어 잔액에 추가됩니다. 충전 시 10% 거래 수수료가 부과됩니다.
  • • 결제 방식과 채널별 수수료는 실시간 결제 화면에 표시됩니다.
  • • 발급 가능한 TWD 채널은 적용 세금과 대만 전자 통일영수증 조건을 결제 전에 표시합니다.
  • • 은행 송금: 대규모 또는 기업 충전의 경우 당사에 문의하여 송금 및 맞춤 송장 발행을 준비하세요.
  • 영수증은 현재 제공되며 발급 가능으로 표시된 채널 또는 확인된 기업 조건에서만 제공됩니다. 회사 통일번호, 견적 또는 월별 청구가 필요하면 결제 전에 영업팀에 문의하세요.
예시
US$10.00 크레딧 구매 시 실시간 결제 화면에 사용 가능한 방식, 최종 금액, 수수료 또는 세금, 영수증 발급 가능 여부가 확인 전에 표시됩니다. 잔액은 이후 모델 마크업 없이 공식 정가로 사용됩니다.

환율에 대하여

외환환산은 실시간 환율을 사용합니다. 월별 청구는 청구(명세서) 시점의 요율을 사용하고 선불 충전은 충전 시간 요율로 변환됩니다. 요율과 타임스탬프는 청구 기록과 함께 유지됩니다.

실패한 요청 과금 보호

업스트림 요청이 실패하고 정산할 수 있는 사용량 데이터가 없으면 BazaarLink가 예약 금액 전액을 자동으로 돌려드립니다. 스트림이 시작된 뒤 중단되었더라도 해당 시도의 청구액은 0달러입니다.

청구되지 않는 경우
별도 설정이 필요 없습니다. 공개 추론 및 미디어 API에 자동 적용됩니다. 업스트림 공급자가 BazaarLink에 비용을 청구했더라도 실패 비용을 사용자에게 넘기지 않고 BazaarLink가 부담할 수 있습니다.
  • 업스트림에 연결할 수 없거나 요청이 거부되거나 사용 가능한 결과가 없는 경우
  • 일부 콘텐츠가 전송된 뒤라도 최종 사용량 데이터를 받기 전에 스트림이 중단된 경우
  • usage가 없거나 모든 값이 0인 빈 usage 객체만 있는 경우

출력 토큰이 0이라고 항상 무료인 것은 아닙니다

usage.cost는 요청에 청구된 USD 금액입니다. 출력 토큰이 0이어도 입력 토큰 요금이 발생할 수 있습니다. 최종 금액은 usage.cost 또는 Activity 기록에서 확인하세요.

빠른 시작

세 가지 통합 방법

방식
적합한 경우
시작
원시 API모든 언어, 의존성 제로, 요청 완전 제어→
OpenAI / Anthropic SDK이미 공식 SDK 사용 중 — 기본 URL과 키만 교체→
에이전트 프레임워크LangChain, Vercel AI SDK, CrewAI 등 에이전트 앱→
모든 요청은 모델로 전달되기 전에 자동으로 검토됩니다. 이용 정책을 위반하는 요청은 거부되며 403 오류가 반환됩니다.

5분 이내에 시작하세요. BazaarLink은 OpenAI SDK와 완전히 호환됩니다 — 변경할 것은

100초를 초과하는 긴 요청에는 stream:true 사용을 권장합니다. 비스트리밍 요청은 약 12초 후(기본값이며 배포 설정으로 조정 가능) 먼저 200을 반환하고 keepalive 공백을 보내기 시작합니다. 이후 오류가 발생하면 200 + error JSON으로 반환됩니다. keepalive는 JSON 본문 앞의 공백이며 표준 JSON 파서는 이를 무시합니다.

기본 URL

https://api.bazaarlink.ai/v1

api.bazaarlink.ai는 웹사이트와 별도로 배포되는 API 전용 진입점입니다. 기존 기본 URL https://bazaarlink.ai/api/v1 도 계속 완전히 지원되므로 기존 통합을 변경할 필요가 없습니다.

OpenAI SDK 사용

BazaarLink은 OpenAI SDK와 완전히 호환됩니다. 기본 URL과 API 키만 변경하면 됩니다 — 나머지 코드는 동일합니다.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.bazaarlink.ai/v1",
    api_key="sk-bl-YOUR_API_KEY",
)

completion = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[
        {"role": "user", "content": "What is the meaning of life?"}
    ],
)

print(completion.choices[0].message.content)
API 키가 필요하신가요?
다음에서 API 키를 받으세요 API 키 페이지. 모든 키는 다음으로 시작합니다 sk-bl-.
브라우저에서 직접 호출하기 (CORS)
공개 API는 모든 /v1 응답에 Access-Control-Allow-Origin: *을 포함하므로 브라우저 JavaScript에서 fetch나 OpenAI SDK로 바로 호출할 수 있습니다. API 키를 프런트엔드 코드에 넣지 마세요 — 페이지를 여는 누구나 볼 수 있습니다. 폐기 가능하고 한도가 설정된 키를 쓰거나, 직접 운영하는 백엔드를 통해 중계하세요.
모델 ID 형식 — provider/model-name 형식 사용을 권장
GET /v1/models에는 "claude-sonnet-4.6" 같은 id와 "anthropic/claude-sonnet-4.6" 같은 canonical alias가 표시됩니다. 요청은 두 형식을 모두 지원합니다.
✓ claude-sonnet-4.6   anthropic/claude-sonnet-4.6

업스트림 키 직접 사용(BYOK)

업스트림 API 키를 개인 계정이나 조직에 연결합니다. 해당 요청은 먼저 본인의 키를 사용합니다. 업스트림 오류가 발생했을 때 다른 사용 가능한 소스를 시도할지, 오류를 반환할지 선택할 수 있습니다. 개인 키는 키 페이지에서, 조직 키는 조직 설정에서 관리합니다. BYOK 설정으로 이동 →

콘텐츠 필터링

API 트래픽에 대한 양방향 콘텐츠 보호: 프롬프트 인젝션이 감지된 요청은 차단(400)되고, 요청과 응답의 민감한 데이터(API 키, 카드 번호, 주민등록번호 등)는 자동으로 가려집니다. 규칙과 예외 목록을 커스터마이즈할 수 있으며 사용 통계도 제공됩니다. 콘텐츠 필터 설정으로 이동 →

소셜 데이터(:social)

소셜 플랫폼에 관한 질문이라면 모델 이름 뒤에 :social을 붙이세요. 모델이 답하기 전에 BazaarLink가 해당 플랫폼에서 일치하는 게시물, 프로필, 댓글을 가져와 참고 자료로 제공합니다. 플랫폼 데이터를 제때 가져오지 못하면 일반 웹 검색으로 폴백하므로 항상 답변을 받을 수 있습니다.

예시

curl https://bazaarlink.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  --max-time 60 \
  -d '{
    "model": "gpt-5.4-mini:social",
    "messages": [{ "role": "user", "content": "X에서 최근 GPT-6에 대해 올라온 게시물 알려줘" }]
  }'

알아두세요

  • 대기 시간: 소셜 데이터는 실시간으로 가져오므로 :social 요청은 답변이 시작되기까지 20~40초가 걸릴 수 있습니다. 40초가 지나면 웹 검색으로 폴백합니다. 클라이언트 타임아웃은 60초 이상으로 설정하세요. :online은 일반 웹 검색이라 속도가 그대로입니다.
  • 요금: 소셜 데이터로 답변한 쿼리는 :online과 같은 일일 무료 검색 한도를 함께 사용합니다(잔액이 없으면 하루 5회, 잔액 또는 구독이 있으면 하루 10회이며 UTC 00:00에 초기화). 한도를 넘으면 쿼리마다 모델 자체의 토큰 요금에 더해 Data API 가격표(GET /v1/data/catalog 참조)에 따라 과금됩니다. 웹 검색으로 폴백한 쿼리는 :online과 같은 방식으로 과금됩니다.
  • 지원 범위: :social은 일부 소셜 플랫폼만 읽으며 목록은 활성화된 설정에 따라 달라집니다. 현재 목록은 /solutions/data-api#social-suffix에 있습니다. Data API 카탈로그에는 있어도 이 목록에 없는 플랫폼은 :social이 읽지 않으므로, 해당 플랫폼이나 플랫폼을 지정하지 않은 쿼리는 웹 검색으로 답변합니다.
  • 호환성: POST /api/v1/chat/completions, /api/v1/messages, /api/v1/responses에서 사용할 수 있으며 스트리밍과 비스트리밍을 모두 지원하고 인용은 :online과 같습니다. :online과 :social은 한 모델 이름에 함께 쓸 수 없습니다(400 invalid_web_search_options).

OpenRouter에서 마이그레이션

BazaarLink의 API는 OpenRouter와 호환됩니다 — 대부분의 통합은 두 가지 값만 변경하면 전환됩니다: 기본 URL을 https://api.bazaarlink.ai/v1 로, API 키를 sk-bl- 로 시작하는 BazaarLink 키로 변경하세요.

  1. 기본 URL: https://openrouter.ai/api/v1 → https://api.bazaarlink.ai/v1
  2. API 키: sk-or-... → sk-bl-... (/keys 에서 생성)
  3. 모델 ID: 동일한 provider/model 형식 (예: anthropic/claude-sonnet-4.6); 전체 카탈로그는 GET /v1/models 에서 확인
  4. models[] 폴백, 스트리밍, 도구 호출, 구조화된 출력은 동일한 요청 형식을 사용합니다
  from openai import OpenAI

  client = OpenAI(
-     base_url="https://openrouter.ai/api/v1",
-     api_key="sk-or-...",
+     base_url="https://api.bazaarlink.ai/v1",
+     api_key="sk-bl-...",
  )
Note
청구는 USD 기준이며 대만 전자 세금계산서를 지원합니다. :nitro와 같은 업스트림 전용 라우팅 제어는 무시됩니다. BazaarLink에서 지원하는 라우팅 방식은 API 레퍼런스를 참조하세요.

인증

모든 API 요청에는 API 키가 포함된 Authorization 헤더가 필요합니다.

Authorization: Bearer sk-bl-YOUR_API_KEY

다음에서 API 키를 받으세요 대시보드. 키를 안전하게 보관하세요 — 클라이언트 측 코드에 노출하지 마세요.

보안 참고
클라이언트 측 JavaScript에 API 키를 노출하지 마세요. 항상 백엔드 서버를 통해 요청을 프록시하세요.

선택적 헤더

HTTP-Referer
string
사이트 URL, 사용량 추적 및 분석용 (선택사항)
X-Title
string
앱 이름, 대시보드에 표시 (선택사항)

원칙

BazaarLink은 세 가지 핵심 원칙을 기반으로 설계되었습니다:

1. 통합 인터페이스

하나의 API, 하나의 SDK, 수백 개의 모델. OpenAI, Anthropic, Google Gemini, Meta Llama 등을 코드 변경 없이 전환하세요 — 모델 ID만 변경하면 됩니다.

2. 가격 최적화

BazaarLink은 선택한 모델에 가장 비용 효율적인 공급자로 자동 라우팅합니다. 사용한 만큼만 USD로 청구되며 전체 영수증 발행을 지원합니다.

3. 요청 처리

업스트림 소스에 문제가 생기면 요청은 다른 사용 가능한 소스를 시도할 수 있습니다. 사용 가능한 소스가 없으면 요청에 오류가 반환됩니다.

멀티모달

BazaarLink은 멀티모달 입력을 지원합니다 — 지원하는 모델에 텍스트와 함께 이미지, 오디오, 파일을 전송하세요. 콘텐츠는 업스트림 공급자로 직접 전달됩니다.

지원 모달리티

입력
설명
예시 모델
텍스트표준 텍스트 메시지전체 모델
이미지URL 또는 base64 데이터 URI — PNG, JPEG, WebP, GIFopenai/gpt-6-lunaanthropic/claude-sonnet-4.6google/gemini-4-argon외 98개
파일 / PDFbase64 데이터 URI를 통한 문서 (`data:application/pdf;base64,...`)openai/gpt-6-lunaanthropic/claude-sonnet-4.6google/gemini-4-argon외 41개
오디오Raw base64 — URL 지원 없음. `format` 필드 필요google/gemini-4-argonelevenlabs/scribe-v2google/gemini-3.1-flash-lite-preview외 15개
비디오URL (CDN) 또는 base64 데이터 URIgoogle/gemini-4-argonqwen/qwen3.8-maxminimax/minimax-m3외 39개

예시:

# Image — URL or base64 data URI
curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-3.5-flash","messages":[{"role":"user","content":[
        {"type":"text","text":"What is in this?"},
        {"type":"image_url","image_url":{"url":"https://example.com/photo.jpg"}}
      ]}]}'

# File / PDF — base64 data URI only, no URL
curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-3.5-flash","messages":[{"role":"user","content":[
        {"type":"file","file":{"filename":"doc.pdf","file_data":"data:application/pdf;base64,JVBER..."}},
        {"type":"text","text":"Summarize this."}
      ]}]}'

# Audio — raw base64, no URL. "format" is required
curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-3.5-flash","messages":[{"role":"user","content":[
        {"type":"text","text":"Transcribe this."},
        {"type":"input_audio","input_audio":{"data":"UklGRi...","format":"wav"}}
      ]}]}'

# Video — URL (CDN) or base64 data URI
curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-3.5-flash","messages":[{"role":"user","content":[
        {"type":"text","text":"Describe this video."},
        {"type":"video_url","video_url":{"url":"https://example.com/clip.mp4"}}
      ]}]}'

이미지 전송

image_url 부분과 함께 content 배열 형식을 사용하세요. 지원 형식: PNG, JPEG, WebP, GIF(애니메이션 포함). 단일 메시지에 여러 이미지를 포함할 수 있습니다 — 각각 별도의 image_url 부분으로:

curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer sk-bl-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role":"user","content":[
      {"type":"text","text":"What is in this image?"},
      {"type":"image_url","image_url":{"url":"https://example.com/photo.jpg","detail":"auto"}}
    ]}]
  }'
이미지 전송
이미지와 함께 항상 텍스트 부분을 포함하세요. 텍스트 우선 순서(이미지 부분 앞에 텍스트 부분)가 모든 공급자에서 최상의 호환성을 위해 권장됩니다.
이미지 전송
각 모델의 지원 입력 모달리티는 모델 페이지에서 확인하세요. 모달리티 열에 각 모델이 허용하는 입력이 표시됩니다.

제한

BazaarLink에는 두 가지 독립된 제한이 있습니다: 분당 요청 수에 대한 속도 제한과 계정 지출에 대한 크레딧 제한입니다. 속도 제한을 초과하면 HTTP 429가, 크레딧이 소진되면 HTTP 402가 반환됩니다.

속도 제한

속도 제한은 사용자별(키별이 아님)이며 분당 요청 수(RPM)로 측정됩니다. 일일 상한은 없습니다. 등급은 계정 크레딧 잔액에 따라 자동으로 결정됩니다.

등급
RPM
일일 사용량
비고
무료 (< $5 크레딧)20 RPM무제한개발 & 테스트
유료 (≥ $5 크레딧)200 RPM무제한프로덕션 워크로드

속도 제한이 초과되면 Retry-After 헤더와 함께 429 응답을 받습니다. 요청 재시도 시 지수 백오프를 구현하세요.

응답 헤더

응답에는 x-request-id, 비스트리밍 응답의 x-generation-id, x-ratelimit-*, 해당 시 retry-after, auto 또는 auto:free 라우팅의 x-auto-resolved-model이 포함될 수 있습니다.

x-request-id: 85e6f35c71a31f19-SJC
x-generation-id: 85e6f35c71a31f19-SJC
x-ratelimit-limit: 200
x-ratelimit-remaining: 198
x-ratelimit-reset: 1740000060
retry-after: 5
x-auto-resolved-model: openai/gpt-4o

크레딧 제한

402 응답은 요청이 너무 빠른 것이 아니라 계정 잔액 또는 키의 지출 한도가 0에 도달했음을 의미합니다. 이 응답에는 속도 제한 헤더가 포함되지 않으며, 스트리밍 도중 한도에 도달하면 HTTP 상태 변경이 아닌 SSE 오류 이벤트로 반환됩니다.

402 크레딧이 부족합니다.
잔액이 $0에 도달하면 API는 HTTP 402와 함께 "Insufficient credits. Please top up to continue." 메시지를 반환합니다 — 응답의 usage.cost를 모니터링하여 실시간으로 지출을 추적하세요.

IP 허용 목록

각 API 키에 별도의 IP 허용 목록을 설정하여 지정된 소스 IP에서 온 요청만 해당 키를 사용하도록 제한할 수 있습니다.

사용하기 좋은 경우

고정된 아웃바운드 IP를 사용하는 프로덕션 서버 배포에 적합합니다. 홈 네트워크, 모바일 네트워크 또는 변경되는 주소에서 요청을 보내는 애플리케이션이라면 먼저 아웃바운드 IP가 안정적인지 확인하세요. 그렇지 않으면 스스로 접속을 차단할 수 있습니다.

설정 방법

「 /keys 」로 이동한 뒤 해당 키의 "⋯" 메뉴에서 "IP 허용 목록"을 선택하고 항목을 입력한 후 저장하세요.

로그인된 세션 또는 Management API 키와 함께 PATCH /api/v1/keys/:id를 사용할 수도 있습니다:

PATCH https://api.bazaarlink.ai/v1/keys/KEY_ID
Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY
Content-Type: application/json

{
  "allowedCidrs": [
    "203.0.113.7",
    "198.51.100.0/24"
  ]
}

# Clear the allowlist and return to unrestricted access
{"allowedCidrs": []}

항목 형식

UI에서는 한 줄에 하나의 값을 입력하세요. API에서는 같은 값을 `allowedCidrs` 배열로 보내세요. 일반 IPv4, IPv4 CIDR 또는 IPv6 리터럴(정확한 일치만)을 사용할 수 있습니다.

203.0.113.7
198.51.100.0/24
2001:db8::1

동작 방식

비워 두거나 빈 [] 배열을 보내면 소스 IP를 제한하지 않습니다. 이것이 기본값이므로 기존 키의 동작은 변하지 않습니다.

소스 IP는 `cf-connecting-ip` 헤더에서 가져옵니다.

목록이 비어 있지 않은데 소스 IP를 확인할 수 없으면 요청이 거부됩니다(fail-closed).

⚠️ 중요: 거부 응답은 일반 401뿐입니다
목록 밖의 IP에서 온 요청이나 소스 IP를 확인할 수 없는 요청은 유효하지 않은 키와 정확히 같은 일반 HTTP 401을 받으며, 전용 오류 메시지는 없습니다. 이는 키를 훔친 사람이 허용 목록의 존재를 알 수 없도록 하는 의도적인 보안 설계입니다. 따라서 잘못된 설정은 유효하지 않은 키와 똑같이 보이고 디버깅이 매우 어렵습니다. 저장하기 전에 서버의 아웃바운드 IP가 목록에 포함되어 있는지 확인하세요.
⚠️ 중요: IPv6는 정확한 문자열 일치만 지원합니다
IPv6에는 서브넷 계산을 사용하지 않으며 주소 문자열이 정확히 같아야 합니다. IPv6 주소가 변경되면 접속이 차단될 수 있습니다. /0–/32 CIDR 범위는 IPv4에서만 지원됩니다.
변경 사항 적용 시점
PATCH 또는 UI 저장이 성공하면 업데이트를 수행한 인스턴스의 캐시가 즉시 삭제됩니다. 정상적인 경우 다른 인스턴스도 약 15초 이내에 동기화됩니다. 공유 Redis를 일시적으로 사용할 수 없으면 인스턴스 간 무효화가 즉시 전파되지 않아 캐시 TTL인 최대 1시간까지 지연될 수 있습니다.

개인 서킷 브레이커

모든 API 키에 적용되는 고정된 1분 및 1시간 USD 지출 한도입니다. 창 임계값에 도달하면 새 요청은 HTTP 429를 받으며, 창은 정시 경계에서 자동으로 초기화됩니다.

cbEnabled
boolean
활성화
cbMinuteUsd
number | null
분당 USD 한도 · 기본값 사용
cbHourlyUsd
number | null
시간당 USD 한도 · 기본값 사용
(기본값 상속 중)
0.01 이상의 값을 입력하세요 (기본값은 빈칸)
개인 서킷 브레이커 · 조정 →

계정 보안

비밀번호 외에도 BazaarLink는 로그인 시 보호를 강화하는 2단계 인증을 지원합니다.

2단계 인증(TOTP) 사용

  1. 「설정」 페이지로 이동해 「2단계 인증(TOTP)」 항목을 찾은 뒤 「2단계 인증 사용」을 클릭합니다.
  2. Google Authenticator 등 인증 앱으로 화면의 QR 코드를 스캔하거나, 아래에 표시된 비밀 키를 직접 입력합니다.
  3. 인증 앱이 생성한 6자리 코드를 입력하고 확인하면 활성화가 완료됩니다.

활성화하면 8개의 백업 코드(이번 한 번만 표시)가 나타납니다. 각 코드는 10자이며 1회만 사용할 수 있습니다. 휴대폰이 아닌 안전한 곳에 즉시 적어 두거나 복사해 보관하세요. 휴대폰을 분실했거나 인증 앱을 사용할 수 없을 때 백업 코드로 로그인할 수 있습니다.

활성화 이후 로그인 방식
이후에는 로그인할 때마다 비밀번호(또는 Google 로그인) 외에 인증 앱의 코드나 백업 코드를 추가로 입력해야 합니다.

계정을 보호하는 다른 방법

다음 기능을 2단계 인증과 함께 사용하면 키 유출이나 오남용으로 인한 피해를 더욱 줄일 수 있습니다:

  • IP 허용 목록 — API 키를 지정한 출발지 IP에서만 사용하도록 제한합니다.
  • 개인 서킷 브레이커 — 분당 및 시간당 지출 한도를 설정해 초과 시 자동으로 일시 중지합니다.
  • 키별 지출 한도 — API 키를 생성하거나 수정할 때 일간·주간·월간 지출 한도를 설정합니다.

이미지 생성

modalities:["image"]를 붙인 /v1/chat/completions 또는 OpenAI DALL·E 호환 /v1/images/generations로 이미지를 생성합니다.

curl -N https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-5.4-image-2","messages":[{"role":"user","content":"a red cat on a sofa"}],"modalities":["image","text"],"stream":true}'

전체 흐름(스트리밍, 이미지 편집, SSE 프로토콜, 모델 목록)은 API 레퍼런스에서 →

비디오 생성

비동기 3단계 흐름(submit → poll → content). 동영상 생성에는 30초~5분이 걸립니다.

curl https://api.bazaarlink.ai/v1/videos \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"bytedance/seedance-2.0","prompt":"a bird flying over mountains","duration":3}'
# → 202 { "id": "vjob_xxx", "status": "pending" }

전체 흐름(폴링, 다운로드, 작업 유형, 주의사항)은 API 레퍼런스에서 →

PDF 입력

PDF를 네이티브로 지원하는 모델(Claude, Gemini 등)에 메시지로 PDF 문서를 직접 전송할 수 있습니다. BazaarLink는 파일을 그대로 모델에 전달합니다 — 일반 input tokens로 과금, 추가 비용이나 추가 처리 없음.

지원 형식

  • PDF 문서 (텍스트, 이미지, 테이블, 스캔)
  • Base64 인코딩 데이터 URL (`data:application/pdf;base64,...`)
  • 다중 페이지 문서
  • 비밀번호 없는 PDF만
import base64

with open("document.pdf", "rb") as f:
    pdf_data = base64.b64encode(f.read()).decode()

response = client.chat.completions.create(
    model="anthropic/claude-sonnet-4.6",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "file",
                "file": {
                    "filename": "document.pdf",
                    "file_data": f"data:application/pdf;base64,{pdf_data}",
                },
            },
            {"type": "text", "text": "Summarize this document."},
        ],
    }],
)

비디오 입력

동영상 입력을 지원하는 모델에 동영상 파일을 전송하여 분석, 캡션 생성, 장면 및 이벤트에 대한 질문에 답하게 합니다. 직접 URL 또는 base64 데이터 URI를 사용할 수 있습니다 — URL은 공개적으로 접근 가능한 동영상에 효율적이며, base64는 로컬 파일이나 비공개 동영상에 사용합니다.

지원 형식

MP4(H.264)MPEGMOVWebM
response = client.chat.completions.create(
    model="google/gemini-3.5-flash",
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "video_url",
                "video_url": {"url": "https://example.com/video.mp4"},
            },
            {"type": "text", "text": "What is happening in this video?"},
        ],
    }],
)

전체 API 레퍼런스 →

OAuth PKCE

OAuth 2.0 PKCE (Proof Key for Code Exchange)는 공개 클라이언트 앱(브라우저 SPA, 모바일 앱)이 클라이언트 측에 장기 서버 시크릿을 저장하지 않고도 개별 사용자를 대신하여 API 호출을 할 수 있게 합니다.

OAuth PKCE 사용 시기

  • 사용자별 과금이 필요한 브라우저 SPA 또는 모바일 앱 구축 시
  • 멀티테넌트 SaaS — 각 최종 사용자가 자체 API 사용량을 지불
  • 클라이언트 측에 공유 시크릿을 저장할 수 없는 경우 (공개 클라이언트)
  • 단일 공유 API 키 대신 사용자별로 독립적이고 폐기 가능한 키(사용자가 폐기할 때까지 유효)가 필요한 경우

사용자에게 보이는 화면

자체 로그인 화면에서 다음 단계를 안내하세요:

  1. 앱에서 "BazaarLink로 로그인"(또는 원하는 버튼 이름)을 선택합니다.
  2. 브라우저에 BazaarLink 승인 페이지가 열립니다. 아직 로그인하지 않았다면 먼저 로그인하고 자동으로 이 페이지로 돌아옵니다.
  3. 페이지에 앱 주소와 허용했을 때 일어나는 일이 표시됩니다: 앱 전용 새 API 키가 생성되고, 사용량은 BazaarLink 잔액에서 과금되며, 언제든 키를 폐기할 수 있습니다. 키 이름과 월 지출 한도를 지정할 수 있습니다(둘 다 선택 사항).
  4. "허용"을 클릭하면 앱으로 돌아갑니다. "거부"를 클릭하면 키가 생성되지 않고 앱에도 알리지 않으며 "접근이 거부되었습니다" 페이지가 표시됩니다.
  5. 나중에 접근을 취소하려면 API 키 페이지(https://bazaarlink.ai/keys)를 열어 앱 이름이 붙은 키를 비활성화하거나 삭제하세요.

동작 방식

단계 1 — 인증 시작 — 랜덤 code_verifier(긴 랜덤 문자열)와 그 SHA-256 해시를 code_challenge로 생성한 다음, 사용자를 BazaarLink 인증 페이지로 리디렉션합니다.

https://bazaarlink.ai/auth?callback_url=https://yourapp.com/callback&code_challenge=CODE_CHALLENGE&code_challenge_method=S256

인증 URL 매개변수

  • callback_url (필수) — 사용자가 허용한 뒤 돌아올 주소. 규칙은 아래를 참고하세요.
  • code_challenge (필수) — code_verifier의 SHA-256을 base64url로 인코딩한 값(43자, 패딩 없음).
  • code_challenge_method (필수) — 반드시 S256이어야 합니다.
  • state (선택) — 자체 불투명 CSRF 값으로, 출력 가능한 ASCII 문자 1~256자. BazaarLink는 code 바로 뒤에 &state=…로 그대로 돌려줍니다. 형식이 잘못된 state는 승인 페이지에 "잘못된 승인 요청"이 표시되게 합니다.
  • key_label (선택) — 최대 100자. 동의 페이지의 키 이름을 미리 채워 줍니다(사용자가 변경할 수 있음). 너무 길거나 빈 라벨은 무시됩니다.
  • Headless tools (CLI / desktop, no callback_url) — omit callback_url. After the user allows, the page shows a one-time code (valid 5 minutes, single use) for them to enter into your tool; exchange it exactly like a redirected code. The page cannot show which app is asking, so tell users to enter the code only in a tool they started themselves.

지원하지 않음

  • workspace_id와 required_workspace_id — 지원하지 않습니다. 키는 항상 사용자 본인 계정에 속합니다.
  • code_challenge_method=plain — 지원하지 않습니다(S256만 가능).

callback_url 규칙

  • https://여야 합니다. http://는 localhost, 127.0.0.1, [::1](모든 포트)에만 허용되며, 이 경우 동의 페이지에 로컬 개발 경고가 표시됩니다.
  • 프래그먼트(#), URL 내 사용자 이름·비밀번호는 허용되지 않으며 최대 2048자입니다.
  • 동의 페이지에 callback 호스트 이름이 표시되어 사용자가 어떤 앱이 요청하는지 알 수 있습니다.
  • 사용자가 허용하면 브라우저가 code=…가 덧붙은 callback_url로 이동합니다(state를 보냈다면 state=…도 덧붙으며, 기존 쿼리 문자열은 유지됩니다). code는 10분간 유효하며 한 번만 사용할 수 있습니다.

단계 2 — 코드를 API 키로 교환 — 사용자가 요청을 승인하면 BazaarLink이 일회용 code와 함께 callback_url로 리디렉션합니다. code는 10분간 유효하며 한 번만 사용할 수 있고, code_verifier가 틀리면 code가 폐기됩니다. code, code_verifier, code_challenge_method(세 가지 모두 필수)를 POST하면 해당 사용자의 API 키를 받을 수 있습니다.

curl https://bazaarlink.ai/api/v1/auth/keys \
  -H "Content-Type: application/json" \
  -d '{
    "code": "<CODE_FROM_CALLBACK_URL>",
    "code_verifier": "<CODE_VERIFIER>",
    "code_challenge_method": "S256"
  }'

# Response
# { "key": "sk-bl-...", "user_id": "..." }

단계 3 — 사용자 범위 키 사용 — 반환된 키는 승인한 사용자에게 속한 일반 BazaarLink API 키입니다. 사용량은 귀하가 아니라 해당 사용자의 잔액에서 과금됩니다.

curl https://bazaarlink.ai/api/v1/chat/completions \
  -H "Authorization: Bearer sk-bl-..." \
  -H "Content-Type: application/json" \
  -d '{"model": "google/gemini-3.5-flash", "messages": [{"role": "user", "content": "Hello"}]}'

JavaScript 예제 (브라우저)

// 1) Create a verifier + S256 challenge, then send the user to BazaarLink
const b64url = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
  .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
const verifier = b64url(crypto.getRandomValues(new Uint8Array(32)));
const challenge = b64url(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(verifier)));
sessionStorage.setItem("bl_verifier", verifier);
// "state" is optional: BazaarLink hands it back unchanged next to the code.
const state = b64url(crypto.getRandomValues(new Uint8Array(16)));
sessionStorage.setItem("bl_state", state);
location.href =
  "https://bazaarlink.ai/auth?callback_url=" + encodeURIComponent(location.origin + "/callback") +
  "&code_challenge=" + challenge + "&code_challenge_method=S256&state=" + state;

// 2) On /callback: check your own state, then exchange the one-time code for a user key
const params = new URLSearchParams(location.search);
if (params.get("state") !== sessionStorage.getItem("bl_state")) throw new Error("state mismatch");
const res = await fetch("https://bazaarlink.ai/api/v1/auth/keys", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    code: params.get("code"),
    code_verifier: sessionStorage.getItem("bl_verifier"),
    code_challenge_method: "S256",
  }),
});
if (!res.ok) throw new Error((await res.json()).error?.message ?? "exchange failed"); // 403 invalid_code: ask the user to authorize again
const { key } = await res.json(); // use as: Authorization: Bearer <key>
보안: S256만 지원
code_challenge_method를 S256 (SHA-256 해시)으로 설정하세요. S256만 지원합니다. plain 이거나 code_challenge_method가 없는 요청은 HTTP 400으로 거부됩니다.
참고
사용자가 거부하면 BazaarLink는 callback_url로 리디렉션하지 않으며 앱에도 알리지 않습니다. "접근이 거부되었습니다" 페이지만 표시하므로 /auth가 오픈 리디렉션이 되지 않습니다. 앱 안에서 미승인 상태를 처리하세요(예: 타임아웃 또는 재시도 버튼).

/auth 페이지와 POST /api/v1/auth/keys는 https://bazaarlink.ai 에서 제공됩니다(api.bazaarlink.ai 아님). 발급받은 키는 https://bazaarlink.ai/api/v1 과 https://api.bazaarlink.ai/v1 두 기본 URL 모두에서 작동합니다.

사용자가 승인 시 지출 한도를 설정하면 그 한도는 월 한도이며 계정의 월간 주기에 맞춰 초기화됩니다.

오류

오류는 OpenAI 방식의 {"error":{"message","type","code"}} 형식입니다. POST /api/v1/auth/keys는 다음을 반환할 수 있습니다:

  • 400 invalid_code_challenge_method — code_challenge_method가 없거나 plain이거나 S256이 아닙니다.
  • 400 — JSON 본문이 올바르지 않거나 code / code_verifier가 없습니다.
  • 403 invalid_code — code를 알 수 없거나 만료되었거나 이미 사용되었거나, code_verifier가 틀렸거나, 계정이 더 이상 허용되지 않습니다. 호출자가 구분할 수 없도록 모두 의도적으로 같은 메시지를 반환합니다. code_verifier가 틀리면 code도 폐기되므로 사용자에게 다시 승인하도록 요청하세요.
  • 429 rate_limited — 한 IP에서 10분 동안 30회를 초과해 교환을 시도했습니다(Retry-After 헤더 참고).
  • 429 key_total_cap — 계정이 이미 최대 200개의 API 키를 보유하고 있습니다.
  • 405 — POST만 허용됩니다.

서버에서 인증 코드 생성하기 (관리 키)

개인 관리 키(Management Key)의 소유자는 브라우저 인증 페이지를 거치지 않고 POST /api/v1/auth/keys/code 로 직접 인증 코드를 생성할 수 있습니다(OpenRouter와 호환). 코드는 해당 관리 키의 소유자에게 묶이므로, 교환해서 받는 키는 그 소유자 계정의 표준 키이며 한도, 주기, 만료 시각, 이름은 여기에서 지정한 값이 적용됩니다. 자체 도구가 이미 관리 키를 보유하고 있고 앱에 제한된 키를 발급하려는 경우에 사용합니다. 교환 단계(POST /api/v1/auth/keys)는 위와 동일합니다.

  • callback_url (필수) 및 code_challenge + code_challenge_method=S256 (필수) — 인증 URL과 동일한 규칙입니다.
  • key_label (선택) — 최대 100자, 키 이름. 기본값: "App: <콜백 호스트>".
  • limit (선택) — USD 사용 한도, 0 이상. 0 또는 생략하면 한도 없음입니다.
  • usage_limit_type (선택) — daily, weekly, monthly: 한도가 초기화되는 주기. limit과 함께 사용할 때만 적용되며 기본값은 monthly입니다.
  • expires_at (선택) — 키 만료 시각: 미래의 ISO 8601 UTC 시각(초 단위 포함), 예: 2026-12-31T23:59:59Z. 분 단위까지만 있는 값은 거부됩니다. 생략하면 키는 폐기할 때까지 유효합니다.
  • workspace_id — 지원하지 않음 (400). spawn_agent 와 spawn_cloud 는 허용되지만 무시됩니다.
curl https://bazaarlink.ai/api/v1/auth/keys/code \
  -H "Authorization: Bearer sk-bl-YOUR_MGMT_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "callback_url": "https://yourapp.com/callback",
    "code_challenge": "<CODE_CHALLENGE>",
    "code_challenge_method": "S256",
    "key_label": "My app",
    "limit": 10,
    "usage_limit_type": "monthly",
    "expires_at": "2026-12-31T23:59:59Z"
  }'

# Response
# { "data": { "id": "<ONE_TIME_CODE>", "app_id": 123456789, "created_at": "2026-10-22T12:00:00.000Z" } }
# Then POST { "code": "<ONE_TIME_CODE>", "code_verifier": "<CODE_VERIFIER>", "code_challenge_method": "S256" } to /api/v1/auth/keys

응답: { "data": { "id", "app_id", "created_at" } }. id 는 교환에 사용하는 일회용 코드입니다(10분간 유효, 1회만 사용). BazaarLink에는 앱 등록 체계가 없으므로 app_id 는 콜백 주소에서 도출한 고정 정수입니다. 같은 주소는 항상 같은 app_id 를 받습니다.

  • 401 unauthorized — Bearer 키가 없거나 알 수 없는 키입니다.
  • 403 management_key_required — 개인 관리 키가 아닙니다(표준 키와 조직 관리 키는 거부됩니다).
  • 403 account_not_allowed — 키 소유자가 정지되었거나 삭제되었습니다.
  • 400 — invalid_callback_url, invalid_code_challenge_method, invalid_code_challenge, invalid_expires_at, workspace_not_supported 또는 잘못된 본문.
  • 429 rate_limited — 한 소유자가 시간당 30개 초과 또는 한 IP에서 시간당 120개 초과의 코드를 생성했습니다(Retry-After 참조).

발급되는 키

  • 표준 BazaarLink API 키(sk-bl-…)로, API 키 페이지에서 만든 키와 같은 종류입니다. 사용자가 폐기할 때까지 유효합니다.
  • 사용량은 사용자의 BazaarLink 잔액에서 과금됩니다. 사용자가 동의 페이지에서 지출 한도를 설정했다면 월 한도입니다.
  • 두 기본 URL 모두에서 작동합니다: https://bazaarlink.ai/api/v1 및 https://api.bazaarlink.ai/v1.
  • 계정의 키 한도 200개에 포함되며 사용자의 API 키 목록에 표시되어, 사용자가 언제든 비활성화하거나 삭제할 수 있습니다.
  • 정지되었거나 삭제된 계정은 앱을 승인할 수 없으며, 정지 전에 발급된 code는 교환 시 거부됩니다(403 invalid_code).

제공되는 것

  • 공개 클라이언트 애플리케이션을 위한 Authorization Code + PKCE 흐름
  • 사용자별 과금: 각 사용자가 자신의 잔액으로 자신의 사용량을 지불
  • 사용자마다 별도의 키가 발급되며, 사용자의 API 키 페이지에 표시되어 직접 폐기할 수 있음

관리 API 키

관리 키는 프로그래밍 방식의 키 관리를 위해 설계되었습니다. 표준 API 키를 생성, 나열, 업데이트, 비활성화, 삭제할 수 있지만 — AI 모델 호출은 불가합니다.

참고
관리 키로는 AI 모델(chat/completions/messages/embeddings)을 호출할 수 없습니다. 모델 접근에는 표준 API 키를 사용하세요.

관리 키 생성

Management API Keys 페이지로 이동하여 "Create"를 클릭하세요 — 일반 API Keys 페이지의 유형 선택이 아니라 별도의 페이지입니다.

키 목록

GET https://api.bazaarlink.ai/v1/keys
Authorization: Bearer sk-bl-YOUR_MGMT_KEY

# Response
{
  "keys": [
    {
      "id": "clxyz123...",
      "name": "Production Key",
      "keyType": "standard",
      "keyPrefix": "sk-bl-abc1",
      "keySuffix": "XyZ9",
      "enabled": true,
      "spendLimitUsd": 10.00,
      "spendLimitPeriod": "month",
      "expiresAt": null,
      "createdAt": "2026-01-01T00:00:00.000Z",
      "lastUsed": "2026-03-01T12:34:56.000Z",
      "requestCount": 1234,
      "totalTokens": 5678901
    }
  ]
}

하위 키 생성

POST https://api.bazaarlink.ai/v1/keys
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
Content-Type: application/json

{
  "name": "Agent Key",
  "limit": 10.00,
  "limit_reset": "monthly",
  "expires_at": "2026-12-31T23:59:59Z"
}

# limit_reset: daily | weekly | monthly
# expires_at:  ISO 8601 datetime (optional)

# Response — save the key value, it won't be shown again
{
  "id": "clxyz789...",
  "name": "Agent Key",
  "key": "sk-bl-xyz789abcdef...",
  "keyType": "standard",
  "spendLimitUsd": 10.00,
  "spendLimitPeriod": "month",
  "expiresAt": "2026-12-31T23:59:59.000Z",
  "enabled": true,
  "createdAt": "2026-03-01T00:00:00.000Z"
}

키 업데이트

PATCH https://api.bazaarlink.ai/v1/keys/:id
Authorization: Bearer sk-bl-YOUR_MGMT_KEY
Content-Type: application/json

{"enabled": false}              # disable key
{"spendLimitUsd": 5, "spendLimitPeriod": "week"}  # set spend limit
{"spendLimitUsd": null}         # remove spend limit
# Response: {"updated": true}

키 해지

DELETE https://api.bazaarlink.ai/v1/keys/:id
Authorization: Bearer sk-bl-YOUR_MGMT_KEY

# Returns 204 No Content on success

잔액 조회

GET https://api.bazaarlink.ai/v1/credits
Authorization: Bearer sk-bl-YOUR_MGMT_KEY

# Response
{
  "data": {
    "total_credits": 12.345,
    "total_usage": 3.210
  }
}

사용량 조회

GET https://api.bazaarlink.ai/v1/usage?period=month
Authorization: Bearer sk-bl-YOUR_MGMT_KEY

# period: day | week | month | year

앱 어트리뷰션

요청 헤더에서 애플리케이션을 식별하여 사용량 추적, 대시보드 가시성, 세분화된 분석을 활성화합니다.

참고
이 헤더는 완전히 선택사항이며 API 기능에 영향을 미치지 않습니다. 그러나 디버깅 및 사용량 어트리뷰션을 위해 설정하는 것이 권장됩니다.

사용 가능한 헤더

HeaderDescription
HTTP-Referer사이트 URL, 사용량 추적 및 분석용 (선택사항)
X-Title앱 이름, 대시보드에 표시 (선택사항)
from openai import OpenAI

client = OpenAI(
    base_url="https://api.bazaarlink.ai/v1",
    api_key="sk-bl-YOUR_KEY",
    default_headers={
        "HTTP-Referer": "https://yourapp.com",  # Optional: your site URL
        "X-Title": "My Application",             # Optional: your app name
    },
)

response = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)

오류 코드

오류 응답 형식

오류 envelope는 엔드포인트마다 다릅니다. HTTP 상태와 존재하는 경우 error.type을 사용하세요. error.code는 문자열 또는 숫자이며 생략될 수 있습니다. error.message는 표시용입니다.

{
  "error": {
    "message": "Insufficient credits. Please top up to continue.",
    "type": "invalid_request_error",
    "code": "insufficient_credits"
  }
}

HTTP 상태 및 오류.코드

오류 envelope는 엔드포인트마다 다릅니다. HTTP 상태와 존재하는 경우 error.type을 사용하세요. error.code는 문자열 또는 숫자이며 생략될 수 있습니다. error.message는 표시용입니다.

코드
이름
설명
424종속성 실패직접 설정한 BYOK 키가 업스트림 제공자에 의해 거부되었습니다. BYOK 설정에서 확인하거나 교체하세요. strict 모드에서만 발생합니다
400잘못된 요청잘못된 요청, 빈 messages 배열, 또는 필수 필드 누락
401승인되지 않음API 키가 누락, 잘못됨, 또는 비활성화됨
402결제 필요계정 크레딧 부족, 키별 지출 한도 도달, 또는 월간/주간 예산 상한 초과
403금지됨계정이 정지되었거나 권한이 없음
404찾을 수 없음Requested model, generation, key, or other resource does not exist
409충돌Resource is not in the required state, such as an incomplete video job
410사라Requested model has been retired and must be replaced
413페이로드가 너무 큼요청 바디가 10 MB 초과; 콘텐츠 크기를 줄이거나 요청을 분할하세요
416범위가 만족스럽지 않음Requested byte range is invalid for generated video content
429요청이 너무 많습니다속도 제한 초과; 재시도 전 Retry-After 헤더를 확인하세요
432무료 한도 소진Tavily 호환 엔드포인트(/v1/search, /v1/extract, /v1/crawl, /v1/map): 무료 검색 한도를 모두 사용했거나 잔액이 0 이하입니다. 크레딧을 충전한 뒤 계속하세요. 응답 본문은 Tavily 형식입니다: {"detail":{"error":"..."}}
500서버 오류BazaarLink 내부 오류
502잘못된 게이트웨이모든 업스트림 소스가 요청을 처리하지 못했습니다. 요청에 오류가 반환됩니다.
503서비스를 이용할 수 없습니다이 모델에 구성된 업스트림 공급자 없음; 관리자에게 문의하세요
504게이트웨이 시간 초과Upstream connection or stream stalled and timed out

기계 판독 가능한 청구 코드

A 402 can represent different controls. Use these stable codes to choose the correct action.

코드
설명
byok_key_invalid직접 설정한 BYOK 키가 업스트림 제공자에 의해 거부되었습니다. BYOK 설정에서 확인하거나 교체하세요. strict 모드에서만 발생합니다.
budget_cap_reachedA weekly or monthly budget cap was reached; raise or reset the cap.
credit_limit_exceededA monthly-billing organization's credit line was exhausted; contact billing.
insufficient_creditsThe prepaid balance is insufficient; add credits.
spend_limit_exceededThe API key reached its daily, weekly, or monthly spend limit.
capacity_unavailableThis model is temporarily at capacity. Retry shortly; the Retry-After header says how long to wait.

Stable error.code catalog

These string codes are emitted by public inference and media paths. Branch on the string code when present; the HTTP status remains the broad failure class.

모델 및 엔드포인트
모델 조회, 수명 주기, 가격 책정, 양식 및 엔드포인트 호환성 오류입니다.
코드
HTTP 상태
unknown_model400
invalid_model_id400
model_not_found404
model_retired410
model_endpoint_mismatch400
embedding_on_chat_endpoint400
model_not_priced400
invalid_modality_for_model400
요청 및 안전
잘못된 매개변수, 컨텍스트, 도구, 스키마 및 콘텐츠 안전 거부.
코드
HTTP 상태
missing_required_field400
unsupported_param400
max_tokens_invalid400
context_too_long400
tool_use_unsupported400
malformed_tool_messages400
invalid_response_format_schema400
invalid_tools_definition400
content_moderation403
content_filter403
unknown_4xx400
이미지 생성 및 편집
이미지 입력, 멀티파트 편집, 출력 및 이미지 파이프라인 오류입니다.
코드
HTTP 상태
invalid_image_url400
input_images_not_supported400
invalid_content_type400
mask_not_supported400
unsupported_response_format400
missing_prompt400
missing_image400
too_many_images400
invalid_image_type400
image_too_large400
invalid_n400
pipeline_error502
no_images502
업스트림 라우팅
공급자 연결, 인증, 제한 및 가용성 오류를 삭제했습니다.
코드
HTTP 상태
upstream_unreachable502
upstream_auth_failed502
upstream_rate_limited429
capacity_unavailable429
upstream_unavailable502/503
byok_key_invalid424

콘텐츠 검토

모든 요청은 모델로 전달되기 전에 자동 콘텐츠 검토를 거칩니다. 이용 정책을 위반하는 요청은 모델에 전달되지 않고 거부되며 403 오류가 반환됩니다.

차단되는 콘텐츠 카테고리

검토는 당사의 이용 정책(Acceptable Use Policy)에 따라 이루어지며, 주로 다음 카테고리의 콘텐츠를 차단합니다:

  • 성적 착취 콘텐츠
  • 폭력적 위협
  • 불법 행위 실행 안내
  • 생물학적 위해 관련 콘텐츠

403 응답 형식

검토에 의해 차단된 요청은 다음 형식의 오류를 반환합니다:

{
  "error": {
    "message": "Your prompt was blocked by content moderation.",
    "type": "invalid_request_error",
    "code": "content_filter"
  }
}

차단된 요청은 과금되지 않습니다——거부된 요청에 대한 비용은 청구되지 않습니다.

오탐 이의 제기

요청이 잘못 차단되었다고 생각되면 요청 시각과 (가능하다면) request id를 첨부하여 지원팀에 문의해 주세요. 검토해 드리겠습니다.

개인정보 보호

요청은 자동 콘텐츠 안전 검토를 거치며, 최신 입력의 텍스트와 이미지는 제3자 콘텐츠 안전 점수 서비스로 전송될 수 있습니다.

위반, 위반 의심, 기준 근접 또는 무작위 표본으로 판정된 요청은 컴플라이언스 증빙, 분쟁 처리 및 감사를 위해 전문 또는 앞부분을 보관할 수 있으며, 고정된 삭제 기간은 약속하지 않습니다.

그 외 일반 성공 요청은 프롬프트와 응답 내용을 보관하지 않으며, ZDR 키 요청에는 앞의 두 항목이 적용되지 않습니다.

속도 제한, 예산 및 비상 브레이크

These controls can reject an otherwise valid request and require different recovery actions.

제어
HTTP 상태
식별 방법
요청 속도 제한429문자열 코드 또는 숫자 코드 429입니다. Retry-After와 X-RateLimit-* 헤더를 사용하세요.
속도 제한 페널티 블록429숫자 코드 429 및 임시 제한 메시지; 재시도 후를 사용하십시오.
글로벌 소비 비상 브레이크503숫자 코드 503, 글로벌 지출 한도 메시지 및 30초 또는 300초 후 재시도.
Scoped spend brake429Numeric code 429 and a spend circuit-breaker message naming the scope.
청구 및 예산 관리402위에 나열된 안정적인 청구 문자열 코드를 사용하세요.

오류 envelope는 엔드포인트마다 다릅니다. HTTP 상태와 존재하는 경우 error.type을 사용하세요. error.code는 문자열 또는 숫자이며 생략될 수 있습니다. error.message는 표시용입니다.

비디오 및 미디어 리소스 상태

Video validation commonly returns numeric code 400. Missing jobs return 404, retired models 410, unfinished video content 409, and invalid video byte ranges 416.

재시도 정책

Retry only failures that may recover without changing the request. Honor Retry-After or use exponential backoff with jitter. Do not stack SDK and manual retries.

백오프로 재시도
429, 502, 503, and 504. Check the original generation job before creating another after an ambiguous network failure.
재시도하기 전에 수정하세요
400, 401, 402, 403, 404, 409, 410, 413, and 416. Fix the request, credentials, balance, permissions, resource state, or Range header first.

오류 처리

import random
import time
from openai import OpenAI, APIStatusError

client = OpenAI(
    base_url="https://api.bazaarlink.ai/v1",
    api_key="sk-bl-YOUR_API_KEY",
    max_retries=0,  # Avoid double retries; this example handles them.
)

RETRYABLE = {429, 502, 503, 504}

for attempt in range(5):
    try:
        response = client.chat.completions.create(
            model="openai/gpt-4o",
            messages=[{"role": "user", "content": "Hello!"}],
        )
        break
    except APIStatusError as error:
        if error.status_code not in RETRYABLE or attempt == 4:
            raise
        retry_after = error.response.headers.get("Retry-After")
        delay = (
            float(retry_after)
            if retry_after
            else min(8, 0.5 * (2 ** attempt)) + random.uniform(0, 0.25)
        )
        time.sleep(delay)

스트리밍 오류 형식

토큰 스트리밍 전에 발생한 오류는 JSON 바디와 함께 표준 HTTP 오류 응답을 반환합니다.

스트림이 시작되면 HTTP 응답은 이미 200입니다. 각 SSE 데이터 프레임을 파싱하고, 최상위 error 또는 choices[0].finish_reason === "error"가 나타나면 실패한 불완전 응답으로 처리하세요.

스트림이 시작된 후 실패하면 BazaarLink가 최상위 error 객체가 담긴 마지막 SSE 이벤트를 보내고 이어서 data: [DONE]을 보낼 수 있습니다. 응답을 불완전한 것으로 처리하고, 부분 출력을 완료된 결과로 사용하지 마세요.

data: {"error":{"message":"The request could not be completed.","type":"upstream_error","code":502}}

data: [DONE]

// Branch on error.code; error.type can vary by failure path.

도구 호출

도구 호출(함수 호출이라고도 함)은 모델이 정의한 외부 함수를 호출할 수 있게 합니다. 모델이 도구 호출 시점을 결정하고 구조화된 인수를 생성합니다 — 코드에서 함수를 실행하고 결과를 반환하여 대화를 계속합니다.

지원 모델

대부분의 프론티어 모델이 도구 호출을 지원합니다. 인기 있는 선택지:

도구 정의

각 도구는 모델이 호출할 수 있는 함수를 설명하는 JSON 객체입니다. parameters 필드는 JSON Schema를 사용합니다.

name필수
string
함수 이름 (a-z, A-Z, 0-9, 밑줄, 대시)
description필수
string
함수를 언제, 어떻게 사용해야 하는지에 대한 명확한 설명
parameters필수
object
함수 파라미터를 정의하는 JSON Schema 객체

tool_choice 옵션

값
동작
"auto"모델이 도구 호출 여부를 결정 (기본값)
"none"모델이 도구를 호출하지 않음
"required"모델이 최소 하나의 도구를 호출해야 함
{"type": "function", "function": {"name": "get_weather"}}모델이 지정된 함수를 호출해야 함

전체 흐름

도구 호출은 멀티턴 프로세스입니다: (1) 도구와 함께 요청 전송 → (2) 모델이 tool_calls 반환 → (3) 함수 실행 → (4) 결과 다시 전송 → (5) 모델이 최종 응답 생성.

curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role":"user","content":"What is the weather in Taipei?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "City name"},
            "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
          },
          "required": ["city"]
        }
      }
    }],
    "tool_choice": "auto"
  }'
# Response carries tool_calls — run get_weather() yourself, then send the
# result back with role:"tool" (same shape as the Python/TS steps 3-5) to
# get the model's final answer.

병렬 도구 호출

일부 모델은 단일 응답에서 여러 도구를 호출할 수 있습니다. 각 도구 호출을 처리하고 모든 결과를 반환하세요:

# Model may return multiple tool_calls
if message.tool_calls:
    messages = [
        {"role": "user", "content": "Weather and time in Tokyo?"},
        message,
    ]

    for tool_call in message.tool_calls:
        # Execute each function
        if tool_call.function.name == "get_weather":
            result = {"temperature": 22, "condition": "Clear"}
        elif tool_call.function.name == "get_time":
            result = {"time": "2026-02-23T15:30:00+09:00"}

        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result),
        })

    # Send all results back at once
    final = client.chat.completions.create(
        model="openai/gpt-4o",
        messages=messages,
        tools=tools,
    )
    print(final.choices[0].message.content)

스트리밍 중 도구 호출

스트리밍 시 도구 호출은 위치별로 인덱싱된 부분 델타로 도착합니다——각 델타의 인자 문자열을 인덱스별로 누적하다가 finish_reason이 "tool_calls"가 되면 호출이 완료된 것입니다.

# Streaming: tool_calls arrive as partial deltas indexed by position —
# accumulate function.arguments per index until finish_reason == "tool_calls".
stream = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "What's the weather in Taipei?"}],
    tools=tools,
    tool_choice="auto",
    stream=True,
)

tool_calls = {}
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta.tool_calls:
        for tc in delta.tool_calls:
            entry = tool_calls.setdefault(tc.index, {"id": "", "name": "", "arguments": ""})
            if tc.id:
                entry["id"] = tc.id
            if tc.function.name:
                entry["name"] = tc.function.name
            if tc.function.arguments:
                entry["arguments"] += tc.function.arguments
    if chunk.choices[0].finish_reason == "tool_calls":
        for call in tool_calls.values():
            print(call["name"], json.loads(call["arguments"]))

간단한 에이전트 루프

모델이 도구를 계속 요청하는 동안 계속 호출하고, 최종 답변을 반환하면 멈추는 범용 패턴——무한 루프를 막기 위해 max_iterations를 사용하세요.

# Generic loop: keep calling the model while it keeps requesting tools,
# stop once it returns a plain answer. max_iterations guards against loops.
messages = [{"role": "user", "content": "What's the weather in Taipei, and what time is it there?"}]
max_iterations = 10

for _ in range(max_iterations):
    response = client.chat.completions.create(
        model="openai/gpt-4o",
        messages=messages,
        tools=tools,
    )
    message = response.choices[0].message
    messages.append(message)

    if not message.tool_calls:
        break  # model gave a final answer

    for tool_call in message.tool_calls:
        args = json.loads(tool_call.function.arguments)
        result = TOOL_MAPPING[tool_call.function.name](**args)
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call.id,
            "content": json.dumps(result),
        })
else:
    print("Warning: max_iterations reached without a final answer")

print(messages[-1].content)

함수 정의 모범 사례

  • 구체적이고 명확한 이름 사용——단순히 weather가 아니라 get_weather_forecast처럼.
  • 함수의 목적과 사용 시점을 명확히 설명——모델은 이 텍스트만으로 호출 여부를 판단합니다.
  • 가능하면 enum으로 값을 제한하고 description에 예시를 포함해 잘못된 인자 생성을 줄이세요.
  • 정말 필요한 필드만 required로 표시하고, 선택적 필드는 실제로 생략 가능해야 합니다.

구조화된 출력

모델이 스키마에 맞는 유효한 JSON을 반환하도록 강제합니다. 모델 출력을 프로그래밍 방식으로 파싱하는 신뢰할 수 있는 애플리케이션 구축에 필수적입니다.

방법 1: response_format (JSON Schema)

를 사용하여 엄격한 JSON Schema 준수를 강제합니다:

type필수
string
"json_schema"여야 합니다
json_schema.name필수
string
스키마 이름 (캐싱에 사용)
json_schema.strict
boolean
true이면 정확한 스키마 준수를 보장
json_schema.schema필수
object
JSON Schema 정의
curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o",
    "messages": [{"role":"user","content":"Review the movie Inception"}],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "movie_review",
        "strict": true,
        "schema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"},
            "rating": {"type": "integer", "description": "Rating 1-10"},
            "summary": {"type": "string"},
            "pros": {"type": "array", "items": {"type": "string"}},
            "cons": {"type": "array", "items": {"type": "string"}}
          },
          "required": ["title", "rating", "summary", "pros", "cons"],
          "additionalProperties": false
        }
      }
    }
  }'

팁

  • 명확하고 설명적인 속성 이름을 사용하세요 — 모델이 컨텍스트로 사용합니다.
  • 모델을 안내하기 위해 스키마 속성에 설명을 추가하세요.
  • 보장된 스키마 준수를 위해 strict: true를 설정하세요 (지연 시간이 약간 증가할 수 있음).
  • 스키마를 단순하게 유지하세요 — 깊게 중첩된 스키마는 출력 품질을 저하시킬 수 있습니다.
  • 다른 모델로 테스트하세요 — 일부 모델이 복잡한 스키마를 더 잘 처리합니다.

어시스턴트 프리필

메시지 배열의 마지막에 미완성 assistant 메시지를 추가하여 호환되는 모델 경로에 이어서 생성하도록 요청합니다.

curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.6",
    "messages": [
      {"role":"user","content":"What is the capital of France?"},
      {"role":"assistant","content":"The capital of France is"}
    ]
  }'
# Model continues: " Paris, known for the Eiffel Tower..."
작동 방식
BazaarLink는 마지막 assistant 메시지를 보존하여 전달합니다. 이어쓰기 동작은 선택한 업스트림 모델과 공급자가 구현하므로 모든 경로에서 보장되지는 않습니다.

메시지 변환

The client-supplied transforms field is ignored and removed before an upstream request. It cannot enable or disable message transformations. BazaarLink may apply context handling under its own server-side rules; shorten the input or select a model with a larger context window when needed.

Unsupported request field
Do not rely on transforms values such as middle-out; they do not change how this request is routed or processed.

제로 데이터 보존

일반 성공 요청에서 BazaarLink은 메시지 내용을 저장하지 않습니다(예외는 개인정보 처리방침 참조). ZDR 키 모드는 더 엄격한 제로 데이터 보존을 제공합니다. 이 페이지는 데이터 처리 방법을 설명합니다. 민감한 데이터를 처리하는 애플리케이션에 적합합니다.

현재 데이터 처리

  • 메시지 내용: 일반 성공 요청은 저장하지 않음(예외는 개인정보 처리방침 참조), ZDR 키 모드는 더 엄격
  • 과금·운영 사용 기록: 토큰 수, 시간, 모델, 비용, 지연 시간, 상태
  • 사용 로그: 일반 성공 요청은 사용 통계만, 메시지 내용 없음
  • 업스트림 전달: 메시지가 업스트림 공급자에 전달됨 — 해당 개인정보 정책 적용

프롬프트 캐싱

프롬프트 캐싱은 이전에 계산된 프롬프트 토큰을 재사용하여 비용과 지연 시간을 크게 줄입니다 — 특히 반복되는 대규모 시스템 프롬프트가 있는 애플리케이션에 효과적입니다.

Note
BazaarLink은 캐시 절감액을 자동으로 추적하여 과금에 반영합니다. 응답의 `cached_tokens` 필드는 실제 캐시 히트를 표시하고, `cacheDiscount`는 해당 요청에서 절약된 금액을 표시합니다.

작동 방식

설정이 필요한지 여부는 공급자에 따라 다릅니다. OpenAI 계열 모델은 길고 반복되는 프롬프트 접두사를 자동으로 캐싱합니다 — 요청을 변경할 필요가 없습니다. Claude(Anthropic) 모델은 요청에 명시적인 cache_control 브레이크포인트가 있을 때만 캐싱되며, BazaarLink는 이를 대신 추가하지 않으므로 마커가 없는 Claude 요청은 절대 캐싱되지 않습니다. BazaarLink는 보낸 캐시 마커를 그대로 전달하고 실제 캐시 읽기/쓰기 토큰 수를 사용량 응답에 보고합니다.

# OpenAI-family models: nothing to add, long repeated prefixes cache automatically.
response = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[
        {"role": "system", "content": "You are an expert..."},  # cached automatically if long/repeated
        {"role": "user", "content": "Question here"},
    ],
)

# Check cache savings in the response usage
usage = response.usage
print(f"Prompt tokens: {usage.prompt_tokens}")
print(f"Cached tokens: {usage.prompt_tokens_details.cached_tokens}")
print(f"Cache savings: {usage.prompt_tokens_details.cached_tokens / usage.prompt_tokens * 100:.1f}%")
Claude에는 명시적인 cache_control 마커가 필요합니다
캐싱하려는 콘텐츠 블록에 cache_control: {"type": "ephemeral"}을 추가하세요(아래 예시 참고). Anthropic은 자체적으로 최소 프롬프트 길이 제한도 두고 있어, 이보다 짧으면 마커가 있어도 오류 없이 조용히 캐싱되지 않습니다. 응답의 cached_tokens(OpenAI 형식) 또는 cache_read_input_tokens / cache_creation_input_tokens(Anthropic 형식)를 확인해 캐시 히트 여부를 확인하세요.
# Claude models: you must mark the block to cache yourself.
response = client.chat.completions.create(
    model="anthropic/claude-sonnet-4.6",
    messages=[
        {
            "role": "system",
            "content": [
                {"type": "text", "text": "You are an expert...", "cache_control": {"type": "ephemeral"}}
            ],
        },  # BazaarLink does not add cache_control on your behalf
        {"role": "user", "content": "Question here"},
    ],
)

usage = response.usage
print(f"Cache read tokens: {getattr(usage, 'cache_read_input_tokens', 0)}")
print(f"Cache write tokens: {getattr(usage, 'cache_creation_input_tokens', 0)}")

추론 토큰

추론 모델(예: DeepSeek R1, o1 시리즈)은 최종 답변을 생성하기 전에 내부적으로 사고합니다. 이러한 내부 토큰을 추론 토큰이라 하며 별도로 과금됩니다.

Note
BazaarLink은 `usage.completion_tokens_details.reasoning_tokens`에 추론 토큰을 보고하고 과금에서 별도로 표시합니다.

응답에서 추론 토큰 읽기

response = client.chat.completions.create(
    model="deepseek/deepseek-r1",
    messages=[{"role": "user", "content": "Solve: if f(x) = x^2 + 3x, what is f(5)?"}],
)

# Read reasoning tokens from usage
usage = response.usage
print(f"Completion tokens: {usage.completion_tokens}")
if hasattr(usage, "completion_tokens_details"):
    details = usage.completion_tokens_details
    print(f"Reasoning tokens: {details.reasoning_tokens}")
    print(f"Output tokens: {details.accepted_prediction_tokens}")
const response = await client.chat.completions.create({
  model: "openai/gpt-5.5",
  messages: [{ role: "user", content: "Prove that sqrt(2) is irrational." }],
  // @ts-ignore - BazaarLink extension
  reasoning_effort: "high",  // low | medium | high
});

const usage = response.usage;
console.log("Reasoning tokens:", usage?.completion_tokens_details?.reasoning_tokens);

사고 모드 제어

일부 모델은 "사고" 모드를 토글할 수 있습니다. 사고 모드는 최종 답변을 생성하기 전에 내부 추론 토큰을 생성하여 더 많은 토큰 비용으로 품질을 향상시킵니다.

모델 패밀리파라미터기본값
qwen3-*enable_thinking: booleanfalse (플랫폼 기본값)
openai/gpt-5.5, gpt-5.6-sol, gpt-5.4reasoning_effort: "low" | "medium" | "high"medium
deepseek/deepseek-r1—항상 활성화 (비활성화 불가)
# Qwen3: explicitly enable thinking mode
response = client.chat.completions.create(
    model="qwen/qwen3.7-flash",
    messages=[{"role": "user", "content": "Prove the Pythagorean theorem"}],
    extra_body={"enable_thinking": True},  # opt-in to thinking
)

# usage.completion_tokens_details.reasoning_tokens shows thinking token count

통합 reasoning 객체 (새 형식)

BazaarLink은 모든 모델 패밀리에서 단일 일관된 API로 작동하는 통합 reasoning 객체도 지원합니다:

필드값적용 대상
reasoning.effort"xhigh" | "high" | "medium" | "low" | "none"OpenAI o-series, Grok
reasoning.max_tokensintegerAnthropic Claude, Gemini
reasoning.excludeboolean응답에서 사고 숨기기 (모델은 여전히 추론)
// Claude extended thinking — specify thinking budget in tokens
const response = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-4.5",
  messages: [{ role: "user", content: "Prove the Pythagorean theorem" }],
  // @ts-ignore - BazaarLink extension
  reasoning: { max_tokens: 5000 },
});

// OpenAI GPT-5.6 Sol — specify effort level
const response2 = await client.chat.completions.create({
  model: "openai/gpt-5.6-sol",
  messages: [{ role: "user", content: "Solve this math problem..." }],
  // @ts-ignore - BazaarLink extension
  reasoning: { effort: "high" },
});

// Hide thinking content from response (model still thinks)
const response3 = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-4.5",
  messages: [{ role: "user", content: "What is 2+2?" }],
  // @ts-ignore - BazaarLink extension
  reasoning: { max_tokens: 2000, exclude: true },
});

생각 내용 읽기

추론 모델은 답변과 함께 생각 내용을 반환할 수 있습니다. 아래에 나열된 모델은 생각이 기본으로 켜져 있습니다. 추론 파라미터를 하나도 보내지 않은 요청은 생각을 켠 상태로 실행되어 생각 내용을 반환하고, 실제로 사용된 생각 토큰만큼 과금됩니다. 끄려면 reasoning: { exclude: true } 또는 include_reasoning: false를 보내세요. 그 밖의 모델은 명시적으로 요청할 때만 생각 내용을 반환합니다: reasoning_effort, reasoning 객체, include_reasoning: true, thinking 또는 enable_thinking 중 하나를 보내세요.

기본으로 생각하는 모델: gemini-4-argon, deepseek-v4.1-flash, deepseek-v4.1-flash-1017

생각 내용을 요청하는 방법

요청에 다음 중 하나를 포함하세요: reasoning_effort(low, medium, high), reasoning 객체(effort, max_tokens), include_reasoning: true, thinking: { type: "enabled" }, enable_thinking: true. reasoning.exclude: true 또는 include_reasoning: false를 보내면 생각 내용을 끌 수 있습니다(모델은 계속 추론합니다).

필드위치설명
reasoningchoices[].message.reasoning생각 내용(문자열)
reasoning_detailschoices[].message.reasoning_details생각 내용의 항목 목록이며, 각 항목에는 type과 text만 있습니다
reasoningchoices[].delta.reasoning스트리밍: 생각 내용이 조각으로 전달됩니다(delta.reasoning 및 delta.reasoning_details). delta.content의 답변 텍스트보다 먼저 도착합니다
Note
파라미터가 없을 때: 위에 나열된 모델은 기본으로 생각하므로 생각 내용을 받고 생각 토큰(usage.completion_tokens_details.reasoning_tokens)에 대해 비용을 냅니다. 그 밖의 모델은 파라미터가 없으면 생각 내용도 없습니다. 답변(message.content)만 받으며 예전과 완전히 같습니다. 나열된 모델에서 생각을 끄려면 reasoning.exclude: true 또는 include_reasoning: false를 보내세요. 생각이 실행되지 않고 생각 토큰도 과금되지 않습니다. 다른 추론 모델에서 exclude는 텍스트만 숨길 뿐이며 추론 토큰은 계속 집계됩니다.

GET /v1/models로 모델별 지원 강도를 확인하세요: 추론 모델마다 reasoning.supported_efforts, reasoning.default_effort, reasoning.mandatory가 나열됩니다(예: gemini-4-argon은 high, medium, low를 지원).

예시: gemini-4-argon

response = client.chat.completions.create(
    model="gemini-4-argon",
    messages=[{"role": "user", "content": "Which is larger, 9.11 or 9.9?"}],
    reasoning_effort="high",  # or: extra_body={"include_reasoning": True}
)

message = response.choices[0].message
print(message.reasoning)          # the thinking text (only returned because we asked)
print(message.content)            # the answer
const stream = await client.chat.completions.create({
  model: "gemini-4-argon",
  messages: [{ role: "user", content: "Which is larger, 9.11 or 9.9?" }],
  stream: true,
  // @ts-ignore - BazaarLink extension
  reasoning: { effort: "high" },
});

for await (const chunk of stream) {
  const delta: any = chunk.choices[0]?.delta;
  if (delta?.reasoning) process.stdout.write(delta.reasoning); // thinking text
  if (delta?.content) process.stdout.write(delta.content);     // answer
}

/v1/responses에서는 reasoning: { effort, summary: "auto" }로 요청하면 생각 내용이 output 배열의 reasoning 항목에 담깁니다. /v1/messages에서는 thinking: { type: "enabled", budget_tokens }를 보내면 thinking 블록을 받습니다.

가격
사고 토큰은 완성 토큰으로 과금됩니다. 일부 공급자는 사고 모드에 더 높은 요금을 부과합니다 — Qwen3는 사고가 활성화되면 표준 가격의 2배입니다. BazaarLink은 예상치 못한 비용을 피하기 위해 Qwen3의 기본값을 enable_thinking=false로 설정합니다.

지연 시간 & 성능

AI API 응답 지연 시간 최적화는 사용자 경험에 중요합니다. BazaarLink 아키텍처에서 지연 시간에 영향을 미치는 핵심 요소와 최적화 모범 사례를 아래에서 확인하세요.

Note
BazaarLink은 모든 요청에 대해 `duration_ms`(엔드투엔드 지연 시간)와 `throughput`(tokens/sec)를 기록합니다——GET /v1/generation?id=...로 조회하거나 Activity Export CSV에서 확인할 수 있습니다.

지연 시간에 영향을 미치는 요소

  • 모델 크기: 대형 모델(70B+)은 일반적으로 생성이 느림
  • 공급자 부하: 공급자와 시간대에 따라 다름
  • 토큰 수: max_tokens가 높을수록 완성 시간이 길어짐
  • 스트리밍 vs. 비스트리밍: stream: true가 첫 토큰을 더 빨리 전달
  • 컨텍스트 길이: 매우 긴 컨텍스트는 전처리 시간 증가

최적화 팁

  • 체감 지연 시간을 개선하기 위해 스트리밍(stream: true) 선호
  • 지연 시간에 민감한 시나리오에서는 소형 모델(flash/mini/haiku) 선택
  • 반복 요청의 지연 시간을 줄이기 위해 프롬프트 캐싱 활성화
import time

# Measure time to first token with streaming
start = time.time()
first_token_time = None

stream = client.chat.completions.create(
    model="google/gemini-3.5-flash",  # Fast model
    messages=[{"role": "user", "content": "Hello!"}],
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content and not first_token_time:
        first_token_time = time.time() - start

print(f"Time to first token: {first_token_time:.3f}s")
# Look up per-request latency and throughput after the fact, using the
# generation ID from the response (or the final streamed chunk).
curl "https://api.bazaarlink.ai/v1/generation?id=BAZAARLINK_REQUEST_ID" \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY"

# Response
{
  "data": {
    "id": "85e6f35c71a31f19-SJC",
    "model": "google/gemini-3.5-flash",
    "duration_ms": 842,
    "throughput": 61.2,
    "usage": { "prompt_tokens": 12, "completion_tokens": 48, "total_tokens": 60 }
  }
}

가동 시간 최적화

업스트림 오류가 발생하면 다른 사용 가능한 소스를 시도할 수 있습니다. 처리할 소스가 없으면 요청에 오류가 반환됩니다. 서킷 브레이커는 반복 시도를 제한하고 공급자 상태를 모니터링합니다.

Note
BazaarLink은 모든 업스트림 공급자의 가용성을 추적합니다. 공급자의 오류율이 임계값을 초과하면 서킷 브레이커가 자동으로 트리거되어 다음 가용 공급자로 요청을 라우팅합니다.

가용성 메커니즘

  • 서킷 브레이커: 실패하는 공급자를 자동 감지하고 격리
  • 업스트림 소스에 문제가 생기면 요청은 다른 사용 가능한 소스를 시도할 수 있습니다. 사용 가능한 소스가 없으면 요청에 오류가 반환됩니다.
  • 공급자 상태 모니터링: 공급자별 오류율과 지연 시간을 지속적으로 추적
  • 재시도 로직: 일시적 오류(5xx)는 자동으로 재시도

서킷 브레이커

# If an upstream source returns an error, the request can try another available source.
# Requests handled by a platform model are billed at that model's catalog price.

response = client.chat.completions.create(
    model="openai/gpt-4o",       # Primary model
    messages=[{"role": "user", "content": "Hello!"}],
    extra_body={
        "models": [              # Local fallback chain, tried in order
            "openai/gpt-4o",
            "anthropic/claude-sonnet-4.6",
            "google/gemini-3.5-flash",
        ],
    },
)

# Check whether another source handled the request (in usage logs)
# "is_failover": true indicates the primary provider was bypassed
공급자 상태 모니터링은 내부 운영 전용입니다
GET /api/admin/provider-health는 운영 대시보드용 내부 엔드포인트로 관리자 인증이 필요합니다. 공급자별 요청량, 오류율, 지연 시간 백분위수, 장애 조치 통계 등을 포함한 전체 운영 데이터를 반환합니다——일반 고객용 공개 API가 아니므로 실제 필드를 여기에 재현하지 않습니다.

가드레일

유해 콘텐츠를 필터링하고 규정 준수 정책을 시행하기 위해 API 요청에 콘텐츠 안전 메커니즘을 추가합니다. BazaarLink는 현재 조직(Organization) 수준에서만 사용자 정의 가능한 콘텐츠 필터 가드레일을 제공합니다. 개인(비조직) API 키에는 해당 설정이 없으며, 콘텐츠 안전은 전적으로 각 업스트림 모델 공급자 자체의 내장 안전 시스템에 의존합니다.

현재 범위
개인 API 키에는 내장된 사용자 정의 가드레일이 없습니다——콘텐츠 안전은 전적으로 업스트림 공급자 자체의 안전 시스템에 의존합니다. 사용자 정의 콘텐츠 필터 규칙(차단/편집/기록, 키워드 및 정규식 규칙, 내장 PII 템플릿)이 필요하면 조직을 만들고 조직 API 키를 사용하세요——설정은 "콘텐츠 필터 가드레일"에 있습니다.

계획된 기능 (개인·조직 키 모두 아직 제공되지 않음)

가드레일
설명
PII 감지개인 식별 정보 감지 및 편집
주제 제한승인된 주제에만 모델 응답 제한
출력 검증반환 전 사용자 정의 규칙에 대해 모델 출력 검증

현재 동작

개인 API 키: 모든 업스트림 공급자는 자체 콘텐츠 안전 시스템을 갖추고 있으며, 콘텐츠 필터를 트리거하는 모델 응답은 finish_reason: "content_filter"로 반환되고 BazaarLink는 추가 필터링을 하지 않습니다. 조직 API 키: org_admin이 "콘텐츠 필터 가드레일"에서 사용자 정의 규칙(차단/편집/기록)을 설정할 수 있으며, 텍스트가 모델에 전달되기 전에 적용됩니다.

커서 IDE 통합

BazaarLink을 Cursor의 OpenAI Override URL로 설정하여 모든 모델을 Cursor 내에서 즉시 호출하세요. Responses API 자동 변환, 도구 형식 정규화, Claude 모델용 bz- 접두사 규약을 지원합니다.

빠른 설정

Cursor에서 설정 → 모델을 열고 다음을 수행합니다:

  1. Override OpenAI Base URL을 https://api.bazaarlink.ai/v1로 설정
  2. Override OpenAI API Key를 sk-bl-... BazaarLink 키로 설정
  3. 원하는 모델 이름을 추가 — Claude 모델은 아래의 bz- 접두사를 참고하세요.
하위 호환성
이전 방식의 /cursor 호환 엔드포인트는 계속 작동하며, 두 호스트(https://api.bazaarlink.ai/v1/cursor 및 https://bazaarlink.ai/api/v1/cursor) 모두에서 사용할 수 있습니다. 이는 /v1/chat/completions를 재내보내는 얇은 래퍼입니다 — 새로 설정할 때는 위의 기본 URL을 사용하세요.

bz- 접두사(Claude 모델용)

Cursor의 클라이언트 측 검증은 claude-로 시작하는 모델 이름을 Cursor 자체 Anthropic 통합으로 라우팅하여 Override URL을 우회합니다. Cursor가 BazaarLink로 요청을 보내도록 하려면 모델 이름 앞에 bz-를 붙이세요. 서버가 접두사를 제거하고 alias map으로 나머지를 해석합니다.

Cursor에 입력다음으로 해석됨
bz-claude-sonnet-4.6anthropic/claude-sonnet-4.6
bz-claude-opus-4.7anthropic/claude-opus-4.7
gpt-4oopenai/gpt-4o
gemini-3.5-flashgoogle/gemini-3.5-flash

점과 하이픈 변형은 정규화됩니다: bz-claude-sonnet-4.6과 bz-claude-sonnet-4-6은 모두 같은 모델로 해석됩니다.

CURSOR_MODEL_MAP 환경 변수(운영자 재정의)

BazaarLink을 자체 호스팅하는 경우 이 환경 변수를 설정하면 Cursor 측의 임의 모델 이름을 카탈로그의 canonical id로 재매핑할 수 있습니다:

CURSOR_MODEL_MAP=gpt-claude-sonnet:anthropic/claude-sonnet-4.6,gpt-opus:anthropic/claude-opus-4.7

이제 Cursor에 gpt-claude-sonnet을 입력하면 서버 측에서 anthropic/claude-sonnet-4.6으로 매핑됩니다. Cursor가 모델을 GPT 계열로 인식하여 Override URL을 통해 라우팅하도록 하면서 실제로는 Claude를 제공하고 싶을 때 유용합니다.

자동으로 처리되는 작업

요청이 /v1/chat/completions에 도달하면 BazaarLink는 다음 호환성 변환을 투명하게 적용합니다 — 클라이언트 측에서 할 일이 없습니다:

  • Responses API 본문 자동 감지 — 본문에 messages 대신 input이 있으면 Chat Completions 형식으로 변환됩니다(Cursor는 GPT 계열 모델에 Responses API 형식을 보냅니다).
  • 평면적인 도구 정의 래핑 — Cursor Agent는 function 래퍼 없이 { name, description, parameters }를 보냅니다. 업스트림이 Tool '' not found in provided tools로 거부하지 않도록 래핑합니다.
  • 잘못된 tool_choice 강제 변환 — Cursor는 { type: "auto" }(객체 형식, function 없음)를 보냅니다. OpenAI 사양은 auto/none/required에 문자열 형식을 요구하므로 강제 변환합니다.
  • 업스트림이 지원하지 않는 공급자 전용 필드 제거 — parallel_tool_calls, logprobs, top_logprobs, logit_bias, service_tier, user는 전달 전에 제거됩니다(그렇지 않으면 업스트림이 400을 반환).
  • max_output_tokens → max_tokens로 매핑하고 Responses-API 전용 필드(previous_response_id, truncation, background, store)를 제거합니다. reasoning 필드는 Chat-Completions 네이티브 본문에서 보존됩니다.

Cursor Agent 모드

도구 호출은 표준 Chat Completions 도구 호출 흐름으로 작동합니다. Cursor는 tools(Shell, Read, Write, Grep 등)와 tool_choice: "auto"를 보냅니다; BazaarLink가 선택한 모델의 공급자로 전달하면 해당 공급자가 도구를 호출할지 결정합니다. 도구 호출은 표준 OpenAI tool_calls 델타로 반환되고 Cursor가 로컬에서 실행하고 대화를 계속합니다. gpt-4o(네이티브 OpenAI)를 선택하든 bz-claude-sonnet-4.6을 선택하든 동일하게 작동합니다.

상류 거부 디버깅
공급자 4xx 오류가 보이면 admin Provider Health 패널을 확인하세요. 모든 4xx 응답은 전체 상류 오류 본문과 전달한 요청 본문 요약과 함께 저장됩니다 — 🔴 행을 클릭하면 JSON이 확장됩니다.

모델 라우팅

BazaarLink은 provider/model-name 형식을 사용하여 요청을 올바른 업스트림 공급자로 라우팅합니다. 이를 통해 단일 API 엔드포인트로 주요 모델에 접근할 수 있습니다.

모델 ID 형식

{provider}/{model-name}

# Examples
openai/gpt-5.4-mini
anthropic/claude-sonnet-4.6
google/gemini-3-flash-preview
deepseek/deepseek-v4.1-flash

라우팅 우선순위

요청을 보내면 BazaarLink은 다음 순서로 업스트림 공급자를 결정합니다:

  1. 정확한 일치 — 전체 모델 ID에 일치하는 모델 라우트 검색
  2. 공급자 와일드카드 — provider/* 라우트로 폴백 (예: openai/*)
  3. 전역 와일드카드 — * 와일드카드 라우트로 폴백
  4. 기본 공급자 키 — 카탈로그에 등록된 모델에 한해 활성화되고 기본으로 표시된 키 사용

다음에서 사용 가능한 모든 모델을 탐색하세요 모델 페이지.

자동 라우터

Auto Router v3는 요청을 14개 작업 tier 중 하나로 평가한 뒤 해당 tier에 현재 설정된 primary와 fallback 체인을 사용합니다. 유료 및 무료 표는 관리자 화면에서 별도로 관리됩니다.

  • auto — 유료 라우팅 표를 사용하며 성공한 실제 모델의 공개 가격으로 청구됩니다.
  • auto:free — 무료 라우팅 표를 사용하며 무료 한도 내 비용은 0달러입니다. 한도 소진 후 잔액이 있으면 유료 fallback을 끄지 않은 경우 유료 auto로 전환될 수 있습니다.

사용 방법

자동 라우팅을 활성화하려면 모델을 "auto" (유료) 또는 "auto:free" (무료)로 설정하세요:

curl https://api.bazaarlink.ai/v1/chat/completions \
  -H "Authorization: Bearer $BAZAARLINK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto","messages":[{"role":"user","content":"Review this TypeScript function"}]}'

v3 tier 선택 방식

일반 tier는 simple, standard, complex, reasoning이며 전문 tier는 coding, vision, image, video, data, search, social, email, calendar, trading입니다. 경계 신뢰도가 낮으면 난이도를 한 단계 올립니다.

  • tier 평가: messages, tools, 길이, 키워드 및 구조 신호로 14개 tier 중 하나를 선택
  • 강제 규칙: 이미지, 형식 추론 및 전문 작업은 tier를 직접 선택할 수 있음
  • 라우트 조회: 현재 primary와 최대 5개 fallback을 읽고 비활성 tier는 503 반환
  • 실행: primary 다음에 설정된 순서대로 fallback 시도
  • 응답 추적: 결정된 모델이 응답 바디와 X-Auto-Resolved-Model 헤더에 반환

현재 모델 표

아래 표는 추론과 관리자 화면이 함께 사용하는 실시간 설정입니다. 각 tier의 primary, fallback 순서 및 활성 상태를 재배포 없이 변경할 수 있습니다.

auto

Tier
Primary
Fallbacks
State
simpleopenai/gpt-5.4-nano
google/gemini-3.1-flash-lite-previewanthropic/claude-haiku-4.5
enabled
standardgoogle/gemini-3-flash-preview
openai/gpt-5.4-minianthropic/claude-haiku-4.5
enabled
complexgoogle/gemini-3.1-pro-preview
anthropic/claude-sonnet-4.6openai/gpt-5.4-pro
enabled
reasoninganthropic/claude-opus-4.7
openai/gpt-5.4-progoogle/gemini-3.1-pro-preview
enabled
codingopenai/gpt-5.3-codex
anthropic/claude-sonnet-4.6openai/gpt-5.4-pro
enabled
visionopenai/gpt-5.4-image-2
—
enabled
imageopenai/gpt-5.4-image-2
—
enabled
videobytedance/seedance-2.0-fast
bytedance/seedance-2.0anthropic/claude-sonnet-4.6
enabled
dataopenai/gpt-5.4-pro
anthropic/claude-sonnet-4.6google/gemini-3.1-pro-preview
enabled
searchperplexity/sonar-pro
perplexity/sonar-reasoning-proopenai/gpt-5.4-pro
enabled
socialopenai/gpt-5.4-nano
google/gemini-3.1-flash-lite-previewanthropic/claude-haiku-4.5
enabled
emailopenai/gpt-5.4-nano
google/gemini-3.1-flash-lite-previewanthropic/claude-sonnet-4.6
enabled
calendaropenai/gpt-5.4-nano
google/gemini-3.1-flash-lite-preview
enabled
tradinganthropic/claude-opus-4.7
openai/gpt-5.4-progoogle/gemini-3.1-pro-preview
enabled

auto:free

Tier
Primary
Fallbacks
State
simpledeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
standarddeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
complexdeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
reasoningdeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
codingdeepseek/deepseek-v4-flash-0731free
reflection/beamnvidia/nemotron-3.5-lightning-free
enabled
visionopenai/gpt-5.4-image-2
—
disabled
imageopenai/gpt-5.4-image-2
—
disabled
videogoogle/gemini-2.5-flash-lite
—
disabled
datadeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
searchdeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
socialdeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
emaildeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
calendardeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled
tradingdeepseek/deepseek-v4-flash-0731free
nvidia/nemotron-3.5-lightning-freereflection/beam
enabled

일부 모델은 속도 제한이 있는 무료 티어를 제공합니다. 무료 자격은 플랫폼이 모델 단위로 부여합니다 — 일반 모델 ID로 호출하면 됩니다. :free 접미사는 선택적 별칭입니다(유료 모델에 붙여도 무료가 되지 않습니다).

무료 할당량 소진 이후
무료 할당량을 모두 사용한 뒤에도 계정 잔액이 있으면 초과 요청은 해당 모델의 유료 요금으로 청구됩니다. 초과 시 429를 받으려면 `X-Free-Fallback: false` 헤더를 보내거나 키 설정에서 유료 전환을 끄세요. 잔액이 없으면 초과 요청은 429를 반환합니다. 실제로 이렇게 다운그레이드된 요청의 응답에는 어떤 한도가 발동했는지 나타내는 x-bl-free-fallback: daily 또는 x-bl-free-fallback: rpm 헤더가 포함되어, 청구서를 보기 전에 요청 시점에 전환을 감지할 수 있습니다. 다운그레이드되지 않은 요청에는 이 헤더가 없습니다.
X-Auto-Resolved-Model
실제로 선택된 모델은 X-Auto-Resolved-Model 헤더와 응답의 model 필드에 반환됩니다.

모델 변형

고객 라우팅 필드는 무시됩니다
provider(객체 전체), transforms, route, 최상위 service_tier 및 preset은 업스트림으로 보내기 전에 제거되며 업스트림이나 가격 등급을 선택할 수 없습니다. Chat Completions 및 Responses 엔드포인트에서는 models 배열을 로컬 대체 모델 목록으로 지원합니다. BazaarLink가 각 모델을 자체 라우팅으로 처리하고 해당 모델의 고객 가격을 적용하며, 목록은 업스트림으로 전달되지 않습니다. 고객이 지정한 :nitro, :floor, :exacto 접미사는 무시됩니다. :eco는 BazaarLink의 경제형 티어로 유지되며 내부적으로 BazaarLink :floor에 매핑됩니다. :free는 별도의 카탈로그 모델 변형입니다.

독립 모델 ID

:free, :extended, :thinking 같은 카탈로그 변형은 기능이나 카탈로그 가격이 다른 항목을 나타낼 수 있습니다. 업스트림 경로와 고객 가격은 BazaarLink 카탈로그 및 서버 측 규칙으로 결정됩니다.

:free
:extended
:thinking
:nitro
:floor
:exacto
웹 검색 추가 비용
plugins, :online 또는 web_search_options로 요청하는 웹 검색 동작은 유지되지만 업스트림 추가 요금이 발생할 수 있습니다. 요금은 요청에 사용된 키, 즉 BazaarLink 플랫폼 키 또는 고객 BYOK 키에 청구됩니다.
:online

무료 모델

일부 모델은 속도 제한이 있는 무료 티어를 제공합니다. 무료 자격은 플랫폼이 모델 단위로 부여합니다 — 일반 모델 ID로 호출하면 됩니다. :free 접미사는 선택적 별칭입니다(유료 모델에 붙여도 무료가 되지 않습니다).

  • 일반 모델 ID(예: deepseek/deepseek-v4-flash)로 호출하세요. 무료 한도 내 요청은 자동으로 무료 처리됩니다.
  • 무료 사용량은 사용자별 분당 요청 수(RPM)와 일일 한도로 제한됩니다. 한도는 계정 등급(무충전 / 충전)에 따라 조정됩니다.
  • 무료 한도를 초과해도 크레딧이 있으면 요청이 표시된 가격의 유료 티어로 자동 계속됩니다. X-Free-Fallback: false를 보내면 자동 전환을 끄고 대신 429를 받습니다. 크레딧이 없으면 초과 요청은 429를 반환합니다.
  • GET /v1/models는 무료 티어가 있는 모델마다 :free 항목을 나열합니다. auto:free는 항상 무료 모델로 라우팅됩니다.

현재 무료 할당량이 있는 모델

이 모델 ID로 바로 호출하면 무료 할당량이 적용됩니다. 목록은 수시로 바뀌므로 최신 정보는 API로 조회하세요.

qwen/qwen3.7-flash
reflection/beam-free
stealth/glyph-cluster
nvidia/nemotron-3.5-lightning-free
inclusionai/ling-3.1-flash-1019
deepseek/deepseek-v4-flash-0731free

무료 할당량 상한

항목
값
분당 요청 수 (RPM)10 / min
일일 요청 할당량60 / day
계정 등급 배율 — 미충전× 1
계정 등급 배율 — 충전됨× 2

일일 할당량 = 위 표의 일일 요청 할당량 × 계정 등급 배율이며, 무료 모델별로 따로 계산됩니다. auto:free에는 IP 단위 병렬 상한이 추가로 적용됩니다. 개별 모델은 플랫폼이 더 엄격하거나 느슨한 한도를 지정할 수 있으며, 실제 값은 모델 페이지의 "무료 할당량" 블록에 표시됩니다. 무료 할당량은 단순 요청 횟수가 아니라 "유닛" 단위로 계산됩니다. 요청 한 번이 소비하는 유닛 수는 프롬프트의 컨텍스트 길이에 따라 증가하므로, 같은 일일 할당량이라도 긴 컨텍스트 요청은 짧은 프롬프트보다 실제 사용 가능 횟수가 눈에 띄게 적어집니다.

무료 할당량 소진 이후

무료 할당량을 모두 사용한 뒤에도 계정 잔액이 있으면 초과 요청은 해당 모델의 유료 요금으로 청구됩니다. 초과 시 429를 받으려면 `X-Free-Fallback: false` 헤더를 보내거나 키 설정에서 유료 전환을 끄세요. 잔액이 없으면 초과 요청은 429를 반환합니다.

실제로 이렇게 다운그레이드된 요청의 응답에는 어떤 한도가 발동했는지 나타내는 x-bl-free-fallback: daily 또는 x-bl-free-fallback: rpm 헤더가 포함되어, 청구서를 보기 전에 요청 시점에 전환을 감지할 수 있습니다. 다운그레이드되지 않은 요청에는 이 헤더가 없습니다.

# Return 429 instead of switching to paid routing
-H "X-Free-Fallback: false"

조직 관리

BazaarLink 조직은 3단계 아키텍처를 사용합니다: 조직 → 팀 → 구성원. 크레딧은 조직 수준에 저장되며; 각 팀과 구성원에게 월간 지출 상한을 설정할 수 있습니다. API 요청은 구성원 → 팀 → 조직 크레딧을 순서대로 확인합니다.

조직 관리
팀 추가, 멤버 초대 또는 조직 설정 변경은 설정에서 관리할 조직 선택

3단계 예산 시스템

모든 API 요청에서 세 가지 예산 계층이 순서대로 확인됩니다. 어떤 계층이든 초과하면 HTTP 429를 반환합니다:

  1. 구성원 월간 예산 (OrgMember.monthlyBudget)
  2. 팀 월간 예산 (Team.monthlyBudget)
  3. 조직 크레딧 잔액 (Organization.credits)

사용량 보고서

조직 포털의 보고서 페이지는 네 가지 차원에서 월간 지출 분석을 제공합니다:

  • 개요: 총 지출, 마진율, 일일 추세 차트
  • 팀별: 팀별 지출, 점유율 %, 모델 세분화, 예산 활용률
  • 모델별: 모델별 지출, 평균 가격 ($/1M 토큰)
  • 구성원별: 구성원별 지출 — org_admin만

모든 뷰는 Excel과의 직접 호환성을 위해 BOM 접두사가 포함된 CSV 내보내기를 지원합니다.

조직 생성 & 관리

  1. 설정 → 조직 → 새 조직 만들기로 이동
  2. 조직 포털에서 팀 생성 (선택사항: 비용 센터 코드 및 월간 예산)
  3. 이메일로 구성원 초대, 역할과 팀 배정
  4. 구성원에게 API 키 발급 — 사용량이 올바른 팀/구성원에 자동 태깅
  5. 월간 지출을 팀, 모델, 구성원별로 세분화하여 보고서 페이지에서 확인
  6. 팀, 모델 또는 멤버별로 분류된 월별 지출에 대한 보고서 페이지 보기

구성원 역할

org_admin전체 제어: 구성원, 팀, 결제, 설정
billing_viewer재무 보고서 읽기 전용 접근 (구성원별 세부 정보 불가)
team_admin자체 팀 내 구성원 및 예산 관리
회원API 사용, 팀 및 조직 예산 한도 적용

조직이 관리할 수 있는 다른 항목은 무엇입니까?

구성원과 팀을 넘어서 조직 관리 영역은 다음을 제공합니다.

  • API keys and model restrictions
  • Content filtering before text reaches a model
  • Allowed Models by organization, team, member, or key
  • Monthly budgets and spend emergency brakes
  • Reports and billing
  • Change logs and security logs

콘텐츠 필터링

Organization-owned rules inspect text before it reaches a model. An org_admin can enable, edit, and test them in Settings.

  • block: reject with HTTP 403
  • redact: replace matches with [REDACTED]
  • flag: send unchanged and record an audit event
  • Built-in sensitive-data and prompt-injection templates plus custom keyword or regex rules
  • Up to 100 safety-checked rules with a test preview
현재 텍스트 입력으로 제한되어 있습니다.
Images, audio, video, some structured or multimodal content, and model output are not inspected.

관리 API (v1)

/v1/orgs/ 엔드포인트는 Bearer 관리 키(sk-bl-...)와 세션 쿠키를 모두 지원하여, 브라우저 세션 없이 서버 간 조직 관리를 가능하게 합니다.

인증
모든 /v1/orgs/ 엔드포인트는 org_admin 역할이 필요합니다. Authorization: Bearer sk-bl-<key> 또는 세션 쿠키를 전달하세요. 관리 키는 설정 → API 키에서 생성할 수 있습니다.

조직

GET/v1/orgs

호출자가 속한 모든 organization을 role 및 joinedAt과 함께 나열합니다.

GET/v1/orgs/:orgId

team 및 member 수를 포함한 org 상세 정보를 가져옵니다.

curl https://api.bazaarlink.ai/v1/orgs \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY"

팀

GET/v1/orgs/:orgId/teams

이름순으로 정렬된, member 수가 포함된 team 목록을 가져옵니다.

POST/v1/orgs/:orgId/teams
name필수
string
Team 표시 이름 (org 내에서 고유해야 합니다)
costCenterCode
string
회계 cost center 코드
monthlyBudget
number | null
USD 단위의 team 월간 지출 한도
PATCH/v1/orgs/:orgId/teams/:teamId

부분 업데이트 — 변경할 필드만 포함하세요.

DELETE/v1/orgs/:orgId/teams/:teamId
# Create a team
curl https://api.bazaarlink.ai/v1/orgs/{orgId}/teams \
  -X POST \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Engineering", "costCenterCode": "ENG-001", "monthlyBudget": 500}'

구성원

GET/v1/orgs/:orgId/members

중첩된 user (id/name/email) 및 team 정보를 포함하여 모든 member를 나열합니다.

POST/v1/orgs/:orgId/members
email필수
string
기존 BazaarLink 사용자의 email
role
string
org_admin | billing_viewer | team_admin | member (기본값: member)
teamId
string
Team에 할당 (role이 team_admin인 경우 필수)
monthlyBudget
number | null
USD 단위의 member별 월간 지출 한도

이메일 주소에 BazaarLink 계정이 없으면 404. 이미 구성원이면 409. 기본 역할: member.

PATCH/v1/orgs/:orgId/members/:memberId

role, teamId 또는 monthlyBudget의 부분 업데이트.

DELETE/v1/orgs/:orgId/members/:memberId

대상이 마지막 org_admin이면 400을 반환합니다.

# Add a member
curl https://api.bazaarlink.ai/v1/orgs/{orgId}/members \
  -X POST \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "alice@example.com", "role": "member", "monthlyBudget": 50}'

# Remove a member
curl https://api.bazaarlink.ai/v1/orgs/{orgId}/members/{memberId} \
  -X DELETE \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY"

보고서 API

월간 지출 데이터를 프로그래밍 방식으로 조회합니다. org_admin과 billing_viewer에게 접근 가능. 웹 세션과 Bearer 관리 키 모두 지원.

쿼리 파라미터: year (기본값 현재), month (기본값 현재, 1–12).

엔드포인트
설명
GET /api/orgs/:orgId/reports/overview총 지출, margin rate, 일별 추세
GET /api/orgs/:orgId/reports/by-teamTeam별 지출, 점유율 %, model 분류, 예산 사용률
GET /api/orgs/:orgId/reports/by-modelModel별 지출, 평균 단가 ($/1M tokens)
GET /api/orgs/:orgId/reports/by-memberMember별 지출 — org_admin 전용
GET /api/orgs/:orgId/reports/exportCSV 다운로드; ?view=overview|by-team|by-model|by-member 추가
# Monthly overview via management key
curl "https://bazaarlink.ai/api/orgs/{orgId}/reports/overview?year=2026&month=3" \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY"

# By-team breakdown
curl "https://bazaarlink.ai/api/orgs/{orgId}/reports/by-team?year=2026&month=3" \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY"

# Export CSV (downloads file)
curl "https://bazaarlink.ai/api/orgs/{orgId}/reports/export?year=2026&month=3&view=by-team" \
  -H "Authorization: Bearer sk-bl-YOUR_MANAGEMENT_KEY" \
  -o report.csv

오류 응답 대조표

401API key 유효하지 않거나 취소됨
403RBAC 차단 (호출자 역할 부족) 또는 Allowed Models 화이트리스트에 없는 모델
4023계층 예산 중 어느 한 계층 초과, response body에 scope (member / team / org)와 reset time 포함
429Spend Circuit Breaker 트립, Retry-After header에 복구 시간 (초) 표시
503플랫폼 전체에서 비상 브레이크 사용 또는 임시 서비스 중단

허용 모델 (화이트리스트)

조직, 팀 또는 개별 멤버가 호출할 수 있는 모델을 제한합니다. 비싸거나 검증되지 않은 모델 차단, 모델 표준 강제, 특정 팀을 단일 provider로 한정하는 데 유용합니다.

동작 방식

  • 세 개의 독립된 계층 — 조직, 팀, 멤버 — 각각 자체 목록을 보유합니다 (DB 상 String[]).
  • 세 계층이 모두 비어 있으면 모든 모델이 허용됩니다 (기본 동작).
  • 하나 이상의 계층이 비어 있지 않으면 effective list는 비어 있지 않은 계층들의 교집합입니다 — 모델은 제한된 모든 계층에서 허용되어야 통과합니다.
  • 변경 사항은 몇 초 이내에 반영됩니다 (60초 in-memory + 5분 Redis 캐시; 업데이트 시 둘 다 비워집니다).

패턴 형식

  • 정확 일치 — 예: openai/gpt-4o (이 모델만 허용).
  • Provider 와일드카드 — 예: openai/* (openai/ prefix 하위의 모든 모델).
  • 소문자만 허용. 목록당 최대 200개 항목, 항목당 100자.

관리 위치

Org Portal → Allowed Models. org_admin은 조직 / 팀 / 멤버 목록을 편집할 수 있고, team_admin은 자신의 팀과 그 팀 내 멤버를 편집할 수 있습니다.

차단 시 오류 응답

허용되지 않은 모델 호출은 다음 body와 함께 HTTP 403을 반환합니다:

HTTP/1.1 403 Forbidden
Content-Type: application/json

{
  "error": {
    "message": "Model is not allowed for this account",
    "code": "model_not_allowed"
  }
}

관리 API

모든 endpoint는 Web Session 또는 Bearer Management Key (sk-bl-...)를 받습니다. PATCH는 전체 목록을 교체합니다; 비우려면 []를 전달하세요.

# Org-level list
GET    /api/orgs/:orgId/allowed-models
PATCH  /api/orgs/:orgId/allowed-models

# Team-level list
GET    /api/orgs/:orgId/teams/:teamId/allowed-models
PATCH  /api/orgs/:orgId/teams/:teamId/allowed-models

# Member-level list
GET    /api/orgs/:orgId/members/:memberId/allowed-models
PATCH  /api/orgs/:orgId/members/:memberId/allowed-models

# Example: restrict an org to OpenAI + a specific Anthropic model
curl -X PATCH https://bazaarlink.ai/api/orgs/$ORG_ID/allowed-models \
  -H "Authorization: Bearer sk-bl-..." \
  -H "Content-Type: application/json" \
  -d '{"allowedModels": ["openai/*", "anthropic/claude-sonnet-4.6"]}'

지출 차단기 (Spend Kill Switch)

upstream 비용이 급증할 때 추가 요청을 차단하는 dual-window 지출 한도입니다. 폭주하는 스크립트, 무한 루프, 도난 키 남용이 실제 비용을 발생시키기 전에 봉쇄하도록 설계되었습니다.

동작 방식

  • scope별로 두 개의 고정된 window가 Redis에 추적됩니다: 1분 및 1시간 upstream 비용 (USD).
  • 어느 한 window의 지출이 임계값에 도달하면 해당 scope의 모든 후속 요청은 window가 리셋될 때까지 거부됩니다.
  • 기본값: $5 / 분, $20 / 시간. 기본적으로 비활성화되어 있으며, 직접 활성화해야 합니다.
  • 카운터는 TTL과 함께 Redis에 저장됩니다 — 복구는 자동이며, org / team / member trip에는 수동 reset이 필요 없습니다.

Scope (member가 team을 override, team이 org를 override)

각 계층은 자체 임계값을 설정할 수 있습니다. 해석 순서는 member → team → org → platform 기본값 — 필드별로 첫 번째 non-null 값이 적용됩니다 (cbEnabled, cbMinuteUsd, cbHourlyUsd).

  • Org 레벨 — 조직 산하 모든 키에 적용됩니다. Org Portal → Circuit Breaker에서 설정.
  • Team 레벨 — 해당 팀에 태그된 모든 키에 적용됩니다. 해당 키에 대해 org를 override합니다.
  • Member 레벨 — 해당 멤버에 태그된 키에만 적용됩니다. team과 org를 override합니다.

Trip 동작

트립되면 요청은 빠르게 실패합니다 (upstream 호출은 발생하지 않음). 응답은 다음 body와 함께 HTTP 429입니다:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json

{
  "error": {
    "message": "Spend circuit breaker tripped at member scope (minute window: $5.2341 ≥ $5.00). Try again later or contact your organization owner."
  }
}
글로벌 대 범위 지정
별도의 글로벌 platform-wide circuit breaker (operator가 제어, org portal에서는 보이지 않음)는 Retry-After header와 함께 HTTP 503을 반환합니다. operator가 multi-tenant 남용으로부터 platform을 방어하기 위해 설정하며, org 설정에서 override할 수 없습니다.

감사 로그

모든 trip 이벤트와 모든 설정 변경이 기록됩니다:

  • Trip 이벤트 — action org.cb.tripped / team.cb.tripped / org_member.cb.tripped. 시간당 scope+window별 한 항목으로 중복 제거되어 지속적인 trip이 로그를 범람시키지 않습니다.
  • 설정 변경 — action org.cb.update / team.cb.update / org_member.cb.update. before / after 값과 actor를 기록합니다.

관리 API

Org admin은 API를 통해 설정을 읽고 업데이트할 수 있습니다. 모든 endpoint는 Web Session 또는 Bearer Management Key (sk-bl-...)를 받습니다. PATCH body에 필드의 어떤 부분집합이든 보내세요; null은 필드를 비우고 부모 계층으로 fallback합니다.

# Org-level config
GET    /api/orgs/:orgId/circuit-breaker
PATCH  /api/orgs/:orgId/circuit-breaker

# Team-level config
GET    /api/orgs/:orgId/teams/:teamId/circuit-breaker
PATCH  /api/orgs/:orgId/teams/:teamId/circuit-breaker

# Member-level config
GET    /api/orgs/:orgId/members/:memberId/circuit-breaker
PATCH  /api/orgs/:orgId/members/:memberId/circuit-breaker

# Example: tighten the org-level cap to $2/min, $10/hr
curl -X PATCH https://bazaarlink.ai/api/orgs/$ORG_ID/circuit-breaker \
  -H "Authorization: Bearer sk-bl-..." \
  -H "Content-Type: application/json" \
  -d '{"cbMinuteUsd": 2, "cbHourlyUsd": 10, "cbEnabled": true}'

# GET response (org scope)
{
  "settings":         { "cbEnabled": true, "cbMinuteUsd": 2,  "cbHourlyUsd": 10  },
  "resolvedSettings": { "cbEnabled": true, "cbMinuteUsd": 2,  "cbHourlyUsd": 10  },
  "liveSpend":        { "minuteSpend": 0.4123, "hourSpend": 3.8721 }
}

API 키 순환

API 키를 정기적으로 교체하는 것은 보안에 도움이 됩니다. 새 키를 만들고 애플리케이션을 업데이트해 동작을 확인한 뒤 이전 키를 폐기하세요. 이 절차는 다운타임이 없음을 보장하지 않습니다.

참고
API 키는 대시보드 또는 관리 API를 통해 언제든지 해지할 수 있습니다. 해지는 즉시 적용됩니다 — 해당 키를 사용하는 모든 요청이 즉시 실패합니다.

순환 단계

  1. 새 API 키 생성
  2. 새 키를 사용하도록 애플리케이션 또는 환경 변수 업데이트
  3. 새 키가 올바르게 작동하는지 확인
  4. 이전 키 비활성화 또는 삭제
# Key CRUD via Bearer auth requires a MANAGEMENT key (keyType: "management").
# Standard keys get 403 on /v1/keys — create a management key first,
# or rotate keys from the dashboard UI instead.

# Step 1: Create new key (management key auth)
POST https://api.bazaarlink.ai/v1/keys
Authorization: Bearer $BL_MANAGEMENT_KEY
{"name": "Production v2"}
# → saves new key: sk-bl-NEW_KEY_VALUE

# Step 2: Update your application
# export BAZAARLINK_API_KEY=sk-bl-NEW_KEY_VALUE

# Step 3: Verify new key works
curl https://api.bazaarlink.ai/v1/models \
  -H "Authorization: Bearer sk-bl-NEW_KEY_VALUE"

# Step 4: Revoke old key (management key auth again)
DELETE https://api.bazaarlink.ai/v1/keys/:old_key_id
Authorization: Bearer $BL_MANAGEMENT_KEY

활동 내보내기

재무 감사, 비용 분석, 규정 준수 보고를 위해 전체 API 사용 기록을 CSV로 다운로드합니다.

CSV 내보내기

로그인 후 로그 페이지로 이동하세요. 오른쪽 상단의 CSV 내보내기 버튼을 클릭하여 전체 기록을 CSV 파일로 다운로드합니다. API 호출이 필요 없습니다.

CSV 열

Column
Description
dateISO 8601 timestamp (UTC)
modelModel ID (e.g. openai/gpt-4o)
prompt_tokensInput token count
completion_tokensOutput token count
total_tokensTotal tokens (prompt + completion)
reasoning_tokensReasoning tokens (o-series / thinking models)
cached_tokensPrompt cache hit tokens
cost_ntd대만 달러 청구액
duration_msEnd-to-end latency in milliseconds
finish_reasonstop / length / content_filter / error
statusBazaarLink 응답 상태 코드
app_nameX-Title header value (app attribution)

JSON 사용량 API

프로그래밍 방식 접근을 위해, 기간, 모델, 키별로 그룹화된 집계 통계를 조회하세요:

# Query usage data (grouped / aggregated)
GET https://api.bazaarlink.ai/v1/usage
Authorization: Bearer sk-bl-YOUR_KEY

# With period filtering (day | week | month | year)
GET https://api.bazaarlink.ai/v1/usage?period=month

# Response
{
  "period": "month",
  "since": "2025-01-01T00:00:00.000Z",
  "credits": 10.5000,
  "totals": {
    "spend": 0.1812,
    "requests": 309,
    "tokens": 161200,
    "promptTokens": 95000,
    "completionTokens": 66200
  },
  "byModel": [{ "model": "openai/gpt-4o", "spend": 0.0028, "tokens": 1200, "requests": 5 }],
  "byKey":   [{ "keyName": "My Agent", "spend": 0.0028, "tokens": 1200, "requests": 5 }],
  "byApp":   [{ "appName": "MyApp", "spend": 0.0015, "tokens": 600, "requests": 3 }],
  "timeSeries": [{ "date": "2025-01-15", "model": "openai/gpt-4o", "cost": 0.0012, "tokens": 500, "requests": 2 }]
}

사용량 회계

토큰 소비, 비용 분석, 요청 기록을 포함한 상세 사용량 통계를 API를 통해 조회합니다.

참고
사용량 데이터는 USD로 과금됩니다. 개별 요청 기록은 로그 페이지 또는 CSV 내보내기에서 확인 가능합니다. 집계 통계(기간, 모델, 키별)는 Bearer 토큰 인증을 사용하는 `/v1/usage` 엔드포인트에서 확인 가능합니다.

응답 필드 레퍼런스

FieldTypeDescription
modelstringModel ID used (e.g., openai/gpt-4o)
providerstring고정 값: bazaarlink (BazaarLink)
prompt_tokensnumberInput tokens consumed
completion_tokensnumberOutput tokens generated
total_tokensnumberTotal tokens (prompt + completion)
reasoning_tokensnumberReasoning tokens (for thinking models)
cached_tokensnumberPrompt tokens served from cache
costnumber이 요청에 대해 고객에게 청구된 USD 금액
duration_msnumberEnd-to-end latency in milliseconds
throughputnumberGeneration speed in tokens/sec
finish_reasonstringstop | length | content_filter | error
statusnumberBazaarLink 응답 상태 코드
app_namestring | nullApplication name (X-Title header)
key_namestringAPI key name used for the request
import httpx

# Aggregated stats (Bearer token — period: day | week | month | year)
response = httpx.get(
    "https://api.bazaarlink.ai/v1/usage",
    headers={"Authorization": "Bearer sk-bl-YOUR_KEY"},
    params={"period": "month"},
)

data = response.json()
totals = data["totals"]
print("This month: US$%.4f  (%d requests)" % (totals["spend"], totals["requests"]))

# Cost breakdown by model
for m in data["byModel"]:
    print("  %s: US$%.4f  (%d reqs, %d tokens)" % (m["model"], m["spend"], m["requests"], m["tokens"]))

피드백 보고

문제, 버그, 제안을 보고하여 BazaarLink 개선에 도움을 주세요. 모든 피드백 채널을 적극적으로 모니터링합니다.

보고 방법

채널
최적 용도
응답 시간
문의 페이지일반 피드백, 기능 요청1-2 영업일
이메일버그 리포트, 기술 문제24시간 이내
API 응답 헤더자동 보고된 오류 및 메트릭자동

포함할 내용

  • 요청 ID (응답 id 필드에서)
  • 사용한 모델과 전송한 파라미터
  • 예상 동작 vs 실제 동작
  • 타임스탬프 및 문제 빈도
  • 오류 메시지 또는 HTTP 상태 코드

피드백을 제출하려면 문의 페이지를 방문하세요.

FAQ

BazaarLink은 OpenAI를 직접 호출하는 것과 어떻게 다른가요?
BazaarLink은 NTD 견적 가격과 함께 USD 결제, 통합 영수증, 중국어 지원, 주요 모델에 대한 단일 API를 제공합니다. 동일한 코드로 OpenAI, Anthropic, Google 등에 접근할 수 있습니다.
기존 코드를 변경해야 하나요?
기본 URL과 API 키만 변경하면 됩니다. 나머지 설정(모델 ID 제외)은 변경 없습니다.
BazaarLink은 내 메시지를 저장하나요?
일반 성공 요청은 메시지 내용을 저장하지 않고, 과금과 운영에 필요한 사용 기록(모델, 토큰 수, 시간, 비용 등)만 보관합니다. 실패한 요청, 콘텐츠 안전 장치, 동영상 등 작업, 직접 켠 기능은 예외이며 개인정보 처리방침에 설명되어 있습니다. ZDR 키 모드는 더 엄격한 제로 데이터 보존을 제공합니다.
통합 영수증(統一發票)을 받으려면 어떻게 하나요?
통합 영수증은 Business 플랜 이상에서 월말에 자동 발행됩니다. 즉시 발행은 지원팀에 문의하세요.
어떤 결제 수단을 지원하나요?
모든 주요 신용카드가 지원됩니다 (Visa, Mastercard, American Express).
어떤 OpenAI SDK 기능이 지원되나요?
채팅 완성, 스트리밍, 도구 호출, 구조화된 출력(response_format), 어시스턴트 프리필이 모두 작동합니다. 기능은 업스트림 공급자에 직접 전달됩니다.
LangChain이나 CrewAI 같은 에이전트 프레임워크와 BazaarLink을 사용할 수 있나요?
네! OpenAI API를 지원하는 모든 프레임워크가 BazaarLink과 함께 작동합니다. 기본 URL을 설정하고 BazaarLink API 키를 사용하면 됩니다. 에이전트 사용법 섹션에서 예제를 확인하세요.
Support
Support
Hi! How can we help you?
Send a message and we'll get back to you soon.