BazaarLinkBazaarLink
ログイン
ドキュメントAPIリファレンスSDKリファレンスエージェント利用AIスキル

BazaarLinkドキュメント

BazaarLinkは台湾の統合AI APIゲートウェイです — 単一のOpenAI互換APIエンドポイントを通じて、OpenAI、Anthropic、Google、Metaなどの数百のモデルにアクセスできます。

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% の取引手数料、台湾ドル決済ではさらに 5% の台湾営業税。米ドル建てで記帳し、台湾ドル見積りと電子統一発票を提供します。セルフサービスの従量課金チャージに対応し、企業は月次請求(Net-30、応相談)も手配できます。

仕組み

  • 消費(引き落とし):各 API コールは実際のトークン使用量に基づき、プロバイダーの公式米ドル定価で残高から差し引かれます。ゼロ加算で、消費時に追加費用はかかりません。
  • チャージ(入金):台湾ドルはリアルタイム売りレートで米ドルに換算され残高に加算されます。チャージ時に 10% の取引手数料が徴収されます。
  • • 支払い方法とチャネル別手数料は最新の決済画面に表示されます。
  • • 対象となる台湾ドル決済では、適用税と台湾電子統一発票の条件を支払い前に表示します。
  • • 銀行電信送金:大口・法人のチャージについては、お問い合わせのうえ送金と個別請求書の手配をいたします。
  • 発票:現在提供中で発票対応と表示された決済方法、または確認済みの法人契約でのみ利用できます。統一編号、見積書、月次請求が必要な場合は支払い前に法人営業へご確認ください。
例
US$10.00 の残高を購入する際、最新の決済画面に利用可能な方法、最終金額、手数料・税、領収書または発票の可否が確認前に表示されます。入金後の US$10.00 は公式定価で消費され、モデル利用時の追加上乗せはありません。

為替レートについて

Foreign-exchange conversion uses the real-time rate; monthly billing uses the rate at billing (statement) time, while prepaid top-ups convert at the top-up-time rate. The rate and timestamp are retained with billing records.

失敗したリクエストの課金保護

アップストリームのリクエストが失敗し、精算可能な使用量データがない場合、BazaarLink は予約額を全額自動返金します。ストリーム開始後に中断した場合でも、その試行の請求額は 0 ドルです。

請求されない場合
設定は不要です。公開推論 API とメディア API に自動適用されます。アップストリームから BazaarLink に費用が請求されても、失敗分をお客様へ転嫁せず BazaarLink が負担する場合があります。
  • アップストリームに接続できない、リクエストが拒否される、または利用可能な結果が返らない場合
  • 一部の内容が返った後でも、最終使用量データを受け取る前にストリームが中断した場合
  • usage がない、またはすべて 0 の空の usage オブジェクトだけが返った場合

出力トークンが 0 でも必ず無料とは限りません

usage.costはこのリクエストの請求額(米ドル)です。出力トークンが0でも入力トークンの料金が発生する場合があります。最終額はusage.costまたはActivity記録で確認してください。

クイックスタート

3つの統合方法

アプローチ
適した用途
スタート
Raw 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 と同じ毎日の無料検索枠を共有します(残高がない場合は 1 日 5 回、残高またはサブスクリプションがある場合は 1 日 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 は 1 つのモデル名で併用できません(400 invalid_web_search_options)。

OpenRouterからの移行

BazaarLinkのAPIはOpenRouter互換です — ほとんどの統合は2つの値を変更するだけで切り替えられます:ベース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
料金は米ドル建てで、台湾の電子請求書に対応しています。:nitro など上流固有のルーティング指定は無視されます。BazaarLink がサポートするルーティング方法は API リファレンスをご覧ください。

認証

すべてのAPIリクエストには、APIキーを含むAuthorizationヘッダーが必要です。

Authorization: Bearer sk-bl-YOUR_API_KEY

APIキーは ダッシュボードから取得できます。キーを安全に保管し、クライアントサイドのコードに公開しないでください。

セキュリティに関する注意
クライアントサイドのJavaScriptでAPIキーを公開しないでください。常にバックエンドサーバーを経由してリクエストをプロキシしてください。

オプションヘッダー

HTTP-Referer
string
サイトURL、使用状況の追跡と分析用(任意)
X-Title
string
アプリ名、ダッシュボードに表示(任意)

設計原則

BazaarLinkは3つのコア原則に基づいて設計されています:

1. 統一インターフェース

1つのAPI、1つのSDK、数百のモデル。OpenAI、Anthropic、Google Gemini、Meta Llamaなどをコード変更なしで切り替え — モデルIDを変更するだけ。

2. 価格最適化

BazaarLinkは選択したモデルに対して最もコスト効率の良いプロバイダーに自動ルーティング。使った分だけ支払い、米ドルで請求、完全な発票サポート。

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 件
音声生の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パーツを含むコンテンツ配列形式を使用します。対応フォーマット:PNG、JPEG、WebP、GIF(アニメーション含む)。1つのメッセージに複数の画像を含めることができます — それぞれ別の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"}}
    ]}]
  }'
画像の送信
常に画像とともにテキストパーツを含めてください。すべてのプロバイダーとの最善の互換性のために、テキストファースト順序(テキストパーツを画像パーツの前に)が推奨されます。
画像の送信
各モデルの対応入力モダリティはモデルページで確認してください。modalityカラムで各モデルが受け付ける入力が表示されます。

制限

BazaarLinkには2種類の独立した制限があります。リクエスト頻度によるレート制限と、アカウントの支出によるクレジット制限です。レート制限を超えるとHTTP 429、クレジットが尽きるとHTTP 402が返されます。

レート制限

レート制限はユーザーごと(キーごとではない)で、1分あたりのリクエスト数(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 Insufficient Credits
残高が $0 に達すると、API は HTTP 402 を返し、メッセージ "Insufficient credits. Please top up to continue." が含まれる。リアルタイムで支出を追跡するにはレスポンスの usage.cost を監視すること。

IP 許可リスト

各 API キーに個別の IP 許可リストを設定でき、指定した送信元 IP からのリクエストだけがそのキーを使用できます。

適した利用場面

固定の送信元 IP を持つ本番サーバーや企業内ネットワークへのデプロイに適しています。自宅ネットワーク、モバイルネットワーク、その他変動するアドレスから利用する場合は、まず送信元 IP が安定していることを確認してください。確認しないと自分を締め出す可能性があります。

設定方法

「 /keys 」で対象キーの「…」メニューを開き、「IP 許可リスト」を選択して項目を入力し、保存します。

ログイン済みセッションまたは Management API key で 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 では 1 行に 1 つの値を入力します。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 を解決できないリクエストには、無効なキーの場合と完全に同じ一般的な HTTP 401 が返され、専用のエラーメッセージはありません。これはキーを入手した第三者に許可リストの存在を知らせないための意図的な設計です。その代わり、設定ミスの症状は無効なキーと同じで、デバッグが非常に困難です。保存前に、ご利用のサーバーの送信元 IP がリストに含まれていることを確認してください。
⚠️ 重要:IPv6 は文字列の完全一致のみをサポートします
IPv6 ではサブネット計算を行わず、アドレス文字列が完全に一致する必要があります。IPv6 アドレスが変わる場合は締め出される可能性があります。CIDR 範囲 /0–/32 に対応するのは IPv4 のみです。
変更が反映されるタイミング
PATCH または UI の保存が成功すると、更新を処理したインスタンスのキャッシュは直ちに消去されます。通常は他のインスタンスにも最大約 15 秒で同期されます。共有 Redis が一時的に利用できない場合、インスタンス間の無効化は即時伝播できず、最大 1 時間のキャッシュ TTL の影響を受ける可能性があります。

個人サーキットブレーカー

すべてのAPIキーに適用される、1分間・1時間の固定USD支出上限です。ウィンドウの閾値に達すると新規リクエストはHTTP 429を受け取り、時刻境界でウィンドウが自動リセットされます。

cbEnabled
boolean
有効
cbMinuteUsd
number | null
1分あたりのUSD上限 · デフォルトを使用
cbHourlyUsd
number | null
1時間あたりのUSD上限 · デフォルトを使用
(デフォルト継承中)
0.01 以上の値を入力してください(空欄でデフォルト)
個人サーキットブレーカー · 調整 →

アカウントセキュリティ

パスワードに加えて、BazaarLink はログイン時の保護を強化する 2 段階認証にも対応しています。

2 段階認証(TOTP)を有効にする

  1. 「設定」ページを開き、「2 段階認証(TOTP)」の項目を見つけて「2 段階認証を有効にする」をクリックします。
  2. Google Authenticator などの認証アプリで画面の QR コードをスキャンするか、下に表示されるシークレットを手動で入力します。
  3. 認証アプリが生成した 6 桁のコードを入力して確認すると、有効化が完了します。

有効化すると、8 組のバックアップコード(この画面でのみ表示)が表示されます。各コードは 10 文字で 1 回限り有効です。スマートフォン以外の安全な場所にすぐに控えるかコピーして保存してください。スマートフォンを紛失した場合や認証アプリが使えない場合は、バックアップコードでログインできます。

有効化後のログインについて
以降、ログインのたびにパスワード(または Google ログイン)に加えて、認証アプリのコードまたはバックアップコードの入力が必要になります。

その他のアカウント保護機能

以下の機能を組み合わせることで、キーの漏洩や誤用による被害をさらに抑えられます。

  • IP 許可リスト — API キーを指定した送信元 IP からのみ使用できるように制限します。
  • 個人サーキットブレーカー — 1 分間および 1 時間ごとの支出上限を設定し、超過すると自動的に一時停止します。
  • キーごとの支出上限 — API キーの作成・更新時に、1 日・1 週間・1 か月単位の支出上限を設定します。

画像生成

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(必須)— ユーザーが許可した後に戻る 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 分で、1 回だけ使えます。

ステップ2 — コードをAPIキーと交換 — ユーザーがリクエストを承認すると、BazaarLinkはワンタイムの code を付けて callback_url にリダイレクトします。code の有効期間は10分で、1回だけ使用できます。code_verifier が誤っていると code は無効になります。code、code_verifier、code_challenge_method(3つとも必須)を 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 ではありません)。取得したキーは、ベース URL が https://bazaarlink.ai/api/v1 でも https://api.bazaarlink.ai/v1 でも使えます。

ユーザーが承認時に利用上限を設定した場合、それは月間上限で、アカウントの月次サイクルに合わせてリセットされます。

エラー

エラーは 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 — 同一所有者で1時間に30件超、または同一 IP で1時間に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!"}],
)

エラーコード

Error response format

エラー形式はエンドポイントによって異なります。HTTPステータスと、存在する場合はerror.typeを使用してください。error.codeは文字列または数値で、省略されることもあります。error.messageは表示用です。

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

HTTP status and error.code

エラー形式はエンドポイントによって異なります。HTTPステータスと、存在する場合はerror.typeを使用してください。error.codeは文字列または数値で、省略されることもあります。error.messageは表示用です。

コード
名前
説明
424依存関係の失敗ご自身で設定した BYOK キーがアップストリームプロバイダーに拒否されました。BYOK 設定で確認またはローテーションしてください。strict モードでのみ発生します
400Bad Request不正なリクエスト、空のmessages配列、または必須フィールドの欠落
401UnauthorizedAPIキーが欠落、無効、または無効化されている
402Payment Requiredアカウントクレジット不足、キーごとの支出制限到達、または月次/週次予算上限超過
403Forbiddenアカウントが停止されているか、権限がない
404Not FoundRequested model, generation, key, or other resource does not exist
409ConflictResource is not in the required state, such as an incomplete video job
410GoneRequested model has been retired and must be replaced
413Payload Too Largeリクエストボディが10MBを超えています。コンテンツサイズを縮小するかリクエストを分割してください
416Range Not SatisfiableRequested byte range is invalid for generated video content
429Too Many Requestsレート制限超過。リトライ前にRetry-Afterヘッダーを確認してください
432無料枠の上限Tavily 互換エンドポイント(/v1/search、/v1/extract、/v1/crawl、/v1/map):無料の検索枠を使い切ったか、残高が 0 以下です。クレジットを追加してください。レスポンス本文は Tavily 形式です:{"detail":{"error":"..."}}
500Server ErrorBazaarLink内部エラー
502Bad Gatewayすべての上流接続先で処理できませんでした。リクエストにはエラーが返されます。
503Service Unavailableこのモデルにアップストリームプロバイダーが設定されていません。管理者に連絡してください
504Gateway TimeoutUpstream connection or stream stalled and timed out

Machine-readable billing codes

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_unavailableこのモデルは一時的に容量が不足しています。しばらくしてから再試行してください。待機秒数は Retry-After ヘッダーに入ります。

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.

Model and endpoint
Model lookup, lifecycle, pricing, modality, and endpoint compatibility errors.
コード
HTTP status
unknown_model400
invalid_model_id400
model_not_found404
model_retired410
model_endpoint_mismatch400
embedding_on_chat_endpoint400
model_not_priced400
invalid_modality_for_model400
Request and safety
Invalid parameters, context, tools, schemas, and content-safety refusals.
コード
HTTP status
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
Image generation and editing
Image input, multipart editing, output, and image-pipeline errors.
コード
HTTP status
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
Upstream routing
Sanitized provider connectivity, authentication, throttling, and availability errors.
コード
HTTP status
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を添えてサポートまでご連絡ください。確認いたします。

プライバシーについて

リクエストは自動的にコンテンツ安全の審査を受け、最新の入力のテキストと画像が第三者のコンテンツ安全スコアリングサービスに送信されることがあります。

違反、違反の疑い、しきい値付近、またはランダム抽出と判断されたリクエストは、コンプライアンス上の証拠、紛争対応および監査のため、全文または冒頭部分を保存することがあり、固定の削除期間は約束しません。

それ以外の通常の成功リクエストでは、プロンプトや応答の内容を保持しません。ZDRキーのリクエストには最初の2点は適用されません。

Rate limits, budgets, and emergency brakes

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

Control
HTTP status
How to identify it
リクエストレート制限429文字列コードまたは数値コード429。Retry-AfterとX-RateLimit-*ヘッダーを使用してください。
Rate-limit penalty block429Numeric code 429 and a temporary restriction message; use Retry-After.
Global spend emergency brake503Numeric code 503, global spend-limit message, and Retry-After of 30 or 300 seconds.
Scoped spend brake429Numeric code 429 and a spend circuit-breaker message naming the scope.
Billing and budget controls402Use the stable billing string codes listed above.

エラー形式はエンドポイントによって異なります。HTTPステータスと、存在する場合はerror.typeを使用してください。error.codeは文字列または数値で、省略されることもあります。error.messageは表示用です。

Video and media resource state

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 policy

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.

Retry with backoff
429, 502, 503, and 504. Check the original generation job before creating another after an ambiguous network failure.
Fix before retrying
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"モデルは少なくとも1つのツールを呼び出す必要がある
{"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.

並列ツールコール

一部のモデルは1つのレスポンスで複数のツールを呼び出せます。各ツールコールを処理し、すべての結果を返します:

# 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"]))

シンプルなAgentループ

モデルがツールを要求し続ける限り呼び出しを続け、最終的な回答を返したら停止する汎用パターン——無限ループを防ぐため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は統一reasoningオブジェクトもサポートしており、すべてのモデルファミリーで一貫したAPIで動作します:

フィールド値適用対象
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`(トークン/秒)を記録——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は「コンテンツフィルターガードレール」でカスタムルール(ブロック/編集/記録)を設定でき、テキストがモデルに到達する前に適用されます。

Cursor IDE Integration

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 ボディを自動検出 — body に 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 deltas として返り、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 の1つを選択
  • 強制ルール:画像、形式推論、専門タスクは 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)と1日の上限で制限されます。上限はアカウント階層(未入金 / 入金済み)に応じて変動します。
  • 無料枠を超過してもクレジット残高があれば、リクエストは表示価格の有料枠で自動的に継続されます。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
1日あたりのリクエスト枠60 / day
アカウント階層倍率 — 未入金× 1
アカウント階層倍率 — 入金済み× 2

1日あたりの枠 = 上表のリクエスト枠 × アカウント階層倍率で、無料モデルごとに個別に計算されます。auto:free にはさらに IP 単位の並行上限があります。個々のモデルにはプラットフォーム側でより厳しい/緩い上限が設定される場合があり、実効値はモデルページの「無料枠」ブロックに表示されます。 無料枠は単純なリクエスト回数ではなく「ユニット」で計算されます。1 回のリクエストで消費されるユニット数はプロンプトのコンテキスト長に応じて増えるため、同じ 1 日の枠でも、長いコンテキストのリクエストは短いプロンプトより実際に使える回数が大幅に少なくなります。

無料枠を使い切った後

無料枠を使い切った後、アカウントに残高があれば超過分はモデルの通常料金で課金されます。超過時に 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リクエストで3つの予算レイヤーが順に確認されます。いずれかのレイヤーを超過するとHTTP 429が返されます:

  1. メンバー月次予算(OrgMember.monthlyBudget)
  2. チーム月次予算(Team.monthlyBudget)
  3. 組織クレジット残高(Organization.credits)

使用量レポート

組織ポータルのレポートページでは、4つのディメンションにわたる月次支出分析を提供:

  • 概要:総支出、マージン率、日次トレンドチャート
  • チーム別:チームごとの支出、シェア%、モデル内訳、予算稼働率
  • モデル別:モデルごとの支出、平均価格($/1Mトークン)
  • メンバー別:メンバーごとの支出 — org_adminのみ

すべてのビューがBOMプレフィックス付きCSVエクスポートをサポートしており、Excel直接互換です。

組織の作成と管理

  1. 設定→組織→新しい組織を作成
  2. 組織名を選択して管理エリアを開く
  3. 組織ポータルでチームを作成(オプション:コストセンターコードと月次予算)
  4. メールでメンバーを招待し、ロールとチームを割り当て
  5. メンバー用のAPIキーを発行 — 使用量は正しいチーム/メンバーに自動タグ付け
  6. レポートページでチーム、モデル、メンバー別の月次支出を確認

メンバーロール

org_adminフルコントロール:メンバー、チーム、請求、設定
billing_viewer財務レポートの読み取り専用アクセス(メンバーごとの詳細は非表示)
team_admin自分のチーム内のメンバーと予算を管理
memberAPIを使用、チームと組織の予算制限に従う

What else can an organization manage?

Beyond members and teams, the organization management area provides:

  • APIキー:組織、チーム、メンバー用のキーを作成し、利用可能なモデルを制限
  • コンテンツフィルタリング:モデルへ送信する前に機密テキストをブロック、編集、または記録
  • 許可モデル:組織、チーム、メンバー、個別APIキーごとにモデルを制限
  • 予算と緊急停止:月間上限と分・時間単位の支出保護を設定
  • レポートと請求:支出、モデル利用、チーム配賦、残高、与信限度、支払いを確認
  • 変更・セキュリティログ:設定変更、コンテンツフィルター検知、セキュリティイベントを追跡

Content filtering

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
Currently limited to text input
Images, audio, video, some structured or multimodal content, and model output are not inspected.

管理API(v1)

/v1/orgs/エンドポイントはBearer管理キー(sk-bl-...)とセッションCookieの両方を受け付け、ブラウザセッションなしでサーバー間の組織管理を可能にします。

認証
すべての/v1/orgs/エンドポイントにはorg_adminロールが必要です。Authorization: Bearer sk-bl-<key>またはセッションCookieを渡してください。管理キーは設定→APIキーから作成できます。

組織

GET/v1/orgs

呼び出し元が所属するすべての組織を、role と joinedAt 付きで一覧する。

GET/v1/orgs/:orgId

team および member 数を含む組織の詳細を取得する。

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

チーム

GET/v1/orgs/:orgId/teams

メンバー数付きでチームを一覧する。name 順。

POST/v1/orgs/:orgId/teams
name必須
string
チームの表示名 (組織内で一意であること)
costCenterCode
string
会計用コストセンターコード
monthlyBudget
number | null
チームの月次支出上限 (USD)
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 情報を含む全メンバーを一覧する。

POST/v1/orgs/:orgId/members
email必須
string
既存の BazaarLink ユーザーの Email
role
string
org_admin | billing_viewer | team_admin | member (default: member)
teamId
string
チームに割り当て (role が team_admin の場合は必須)
monthlyBudget
number | null
メンバー単位の月次支出上限 (USD)

メールアドレスに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総支出、マージン率、日次トレンド
GET /api/orgs/:orgId/reports/by-teamチーム別支出、シェア %、モデル内訳、予算消化率
GET /api/orgs/:orgId/reports/by-modelモデル別支出、平均価格 ($/1M tokens)
GET /api/orgs/:orgId/reports/by-memberメンバー別支出 — 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 ホワイトリストに無いモデル
402月間予算、与信限度額、または利用可能残高が不足しています
429三層予算のいずれか超過、response body に scope (member / team / org) と reset time
503Spend Circuit Breaker トリップ、Retry-After header に復旧時間 (秒)

許可モデル (ホワイトリスト)

組織・チーム・個人メンバーが呼び出せるモデルを制限する。高コストモデルや未検証モデルのブロック、モデル標準の強制、チームを単一プロバイダーに限定する用途に有用。

動作の仕組み

  • 3 つの独立したレイヤー (組織・チーム・メンバー) がそれぞれ独自のリスト (DB 内では String[]) を保持する。
  • 3 レイヤーすべてが空の場合、全モデルが許可される (デフォルト動作)。
  • 1 つ以上のレイヤーが非空の場合、実効リストは非空レイヤーの積集合 — 制限のかかった全レイヤーで許可されたモデルのみ通過する。
  • 変更は数秒以内に反映される (60 秒の in-memory + 5 分の Redis キャッシュ。更新時に両方クリア)。

パターン形式

  • 完全一致 — 例: openai/gpt-4o (この厳密なモデルのみ)。
  • プロバイダーワイルドカード — 例: openai/* (openai/ プレフィックス配下の任意のモデル)。
  • 小文字のみ。1 リスト最大 200 件、1 件あたり最大 100 文字。

管理場所

Org Portal → Allowed Models。org_admin は組織 / チーム / メンバーのリストを編集可能。team_admin は自身のチームとその配下メンバーのみ編集可能。

ブロック時のエラーレスポンス

許可されていないモデルへの呼び出しは HTTP 403 と以下の body を返す:

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

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

管理 API

全エンドポイントは 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 コストが急増した際に後続リクエストをブロックする、デュアルウィンドウ方式の消費上限。暴走スクリプト、無限ループ、漏洩キーの不正利用が実損になる前に封じ込める設計。

動作の仕組み

  • スコープごとに 2 つの固定ウィンドウ (1 分 / 1 時間の upstream コスト USD) を Redis で追跡。
  • いずれかのウィンドウがしきい値に達すると、当該スコープの後続リクエストはウィンドウがリセットされるまで全て拒否される。
  • デフォルト: $5 / 分、$20 / 時間。デフォルトでは無効 — 有効にするにはオプトインが必要です。
  • カウンタは TTL 付きで Redis に保持される — 復旧は自動で、組織 / チーム / メンバーのトリップに手動リセットは不要。

スコープ (member > team > org の順で上書き)

各レイヤーは独自のしきい値を設定できる。解決順序は member → team → org → プラットフォームデフォルト — フィールドごとに最初の non-null 値が採用される (cbEnabled / cbMinuteUsd / cbHourlyUsd)。

  • Org レベル — 組織配下の全キーに適用。Org Portal → Circuit Breaker で設定。
  • Team レベル — そのチームにタグ付けされた全キーに適用。当該キーに対して org を上書きする。
  • Member レベル — そのメンバーにタグ付けされたキーのみに適用。team と org を上書きする。

トリップ時の挙動

トリップ中はリクエストが fail fast (upstream は呼び出されない)。レスポンスは HTTP 429 と以下の body:

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."
  }
}
グローバル vs スコープ別
別途、グローバルなプラットフォーム全体のサーキットブレーカー (オペレーター制御、Org Portal からは不可視) が存在し、Retry-After header 付きの HTTP 503 を返す。マルチテナント不正利用からプラットフォームを守るためにオペレーターが設定するもので、Org 設定からは上書きできない。

監査ログ

全てのトリップイベントと全ての設定変更が記録される:

  • トリップイベント — action は org.cb.tripped / team.cb.tripped / org_member.cb.tripped。スコープ + ウィンドウごとに 1 時間 1 件に重複排除されるため、継続トリップでログが氾濫しない。
  • 設定変更 — action は org.cb.update / team.cb.update / org_member.cb.update。変更前後の値と実行者を記録する。

管理 API

Org admin は API 経由で設定の取得 / 更新が可能。全エンドポイントは Web Session または Bearer Management Key (sk-bl-...) を受け付ける。PATCH の body には任意のサブセットを送ればよく、null を渡すとそのフィールドはクリアされ親レイヤーにフォールバックする。

# 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で照会。

注意
使用量データは米ドルで課金されます。個々のリクエスト記録はログページまたはCSVエクスポートで確認できます。集計統計(期間、モデル、キー別)は`/v1/usage`エンドポイントでBearerトークン認証で利用可能です。

レスポンスフィールドリファレンス

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このリクエストでお客様に請求された米ドル額
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フィールドから)
  • 使用したモデルと送信したパラメータ
  • 期待される動作と実際の動作
  • タイムスタンプと問題の発生頻度
  • エラーメッセージまたはHTTPステータスコード

お問い合わせページにアクセスしてフィードバックを送信してください。

FAQ

BazaarLinkはOpenAIに直接アクセスするのとどう違いますか?
BazaarLinkは米ドル請求と台湾ドル建て価格、統一発票、中国語サポート、主要モデルへの単一APIを提供します。同じコードでOpenAI、Anthropic、Googleなどにアクセスできます。
既存のコードを変更する必要がありますか?
ベースURLとAPIキーを変更するだけです。他のすべての設定(モデルIDを除く)は変更不要です。
BazaarLinkはメッセージを保存しますか?
通常の成功リクエストではメッセージ内容を保存せず、課金と運用に必要な利用記録(モデル、トークン数、時刻、費用など)のみを保持します。失敗したリクエスト、コンテンツ安全機能、動画などのタスク、お客様が有効にした機能は例外であり、プライバシーポリシーに記載しています。ZDRキーモードではより厳格なゼロデータ保持を提供します。
統一発票(統一發票)を取得するには?
統一発票はビジネスプラン以上で月末に自動発行されます。即時発行についてはサポートにお問い合わせください。
対応している支払い方法は?
主要なクレジットカード(Visa、Mastercard、American Express)に対応しています。
どのOpenAI SDK機能がサポートされていますか?
チャットコンプリーション、ストリーミング、ツールコール、構造化出力(response_format)、アシスタントプリフィルがすべて動作します。機能はアップストリームプロバイダーに転送されます。
LangChainやCrewAIなどのエージェントフレームワークでBazaarLinkを使用できますか?
はい!OpenAI APIをサポートするフレームワークはBazaarLinkで動作します。ベースURLを設定し、BazaarLink APIキーを使用するだけです。例についてはエージェント利用セクションをご覧ください。
サポート
サポート
こんにちは。どのようなご用件でしょうか?
メッセージをお送りください。担当者より返信します。