概要
クイックスタート
TokSpan は OpenAI 互換です — ベース URL を変更するだけで 200 以上のモデルにすぐアクセスできます。Claude Code / Anthropic ネイティブ、OpenAI Responses API もサポートされ、Doubao Seedance による動画生成も同じキーで利用できます。詳細は下記をご覧ください。
API キーを作成
ダッシュボードの API Keys ページで sk- キーを生成します。
ベース URL を変更
SDK のベース URL を下のいずれかの URL に向け、キーで呼び出します。
Model ID を更新/追加
Model Plaza に移動して Model ID を取得し、更新してください。
API ベース URL
TokSpan は複数の API プロトコルに対応しています。使用中の SDK に合う形式を選んでください — どの形式も同じ API キーを受け入れ、200 以上のモデルすべてにアクセスできます。
https://api.tokspan.com/v1OpenAI SDK は /v1 を含み、/chat/completions を自動的に追加します。
https://api.tokspan.comホストのルートを使用します — Claude Code と Anthropic SDK が /v1/messages を自動的に追加します。
https://api.tokspan.com/v1/videosPOST /v1/videos がタスクを作成して id を返します。動画の準備が整うまでポーリングし、その後コンテンツを取得します。
https://api.tokspan.com/v1OpenAI 互換のベース URL を再利用し、/v1/responses を呼び出します。
OpenAI 互換
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.tokspan.com/v1", # ← OpenAI-compatible base URL
)
response = client.chat.completions.create(
model="MODEL_NAME", # Replace MODEL_NAME with any model from the catalog
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)Anthropic ネイティブ
from anthropic import Anthropic
client = Anthropic(
api_key="sk-your-api-key",
base_url="https://api.tokspan.com", # ← Native Anthropic base URL (host root; SDK appends /v1/messages)
)
response = client.messages.create(
model="MODEL_NAME", # Replace MODEL_NAME with any Claude model from the catalog
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
print(response.content[0].text)Video Generation API
"""
Doubao Seedance video generation - Python example.
Video generation is asynchronous: submit a task, poll it, then download the
result. Requires `pip install requests`.
"""
import time
from typing import Any, Dict, Optional
import requests
# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
# Site origin only - no trailing slash and no "/v1/videos" (the paths below are
# appended by the code, e.g. f"{BASE_URL}/v1/videos").
BASE_URL = "https://api.tokspan.com"
API_KEY = "YOUR_API_KEY" # user token from Console -> Tokens
MODEL = "volcengine/doubao-seedance-2-5-v2"
PROMPT = "A ginger cat walking through a sunlit garden, cinematic, shallow depth of field"
SECONDS = 5 # 1-3600; upstream default is about 10s
RESOLUTION = "1080p" # 480p / 720p / 1080p / 4k; upstream default is 720p
IMAGE_URL = None # reference image URL for image-to-video; None = text-to-video
POLL_INTERVAL = 10 # seconds between status checks
POLL_TIMEOUT = 15 * 60 # give up after this many seconds
# A trailing slash would produce "https://host//v1/videos", which the gateway
# answers with its HTML front page (HTTP 200), so normalize it away.
BASE_URL = BASE_URL.rstrip("/")
# Available models, with list price per 1M tokens (billed on actual usage):
# volcengine/doubao-seedance-2-5-v2 $10.19 best quality
# volcengine/doubao-seedance-2-0-260128 $6.00
# volcengine/doubao-seedance-2-0-fast-260128 $4.35 fastest, cheapest
def _headers() -> Dict[str, str]:
"""Auth header. `requests` sets Content-Type automatically for json= bodies."""
return {"Authorization": f"Bearer {API_KEY}"}
def _check(resp: requests.Response, action: str) -> None:
"""Raise a readable error for any non-2xx response.
Error codes you may hit:
pre_consume_token_quota_failed token balance below the pre-charge
model_not_found no channel serves this model
get_channel_failed channel selection failed
fail_to_fetch_task upstream error (details inside `message`)
"""
if resp.ok:
return
try:
body = resp.json()
except ValueError:
body = {"message": resp.text[:200]}
err = body.get("error", body) if isinstance(body, dict) else {"message": str(body)}
raise RuntimeError(
f"{action} failed: HTTP {resp.status_code} "
f"[{err.get('code', '')}] {err.get('message', '')}"
)
def create_video(
prompt: str,
model: str = MODEL,
seconds: Optional[int] = None,
resolution: Optional[str] = None,
image_url: Optional[str] = None,
) -> str:
"""Submit a generation task and return its task id."""
payload: Dict[str, Any] = {"model": model, "prompt": prompt}
if seconds is not None:
payload["seconds"] = seconds
if resolution is not None:
payload["resolution"] = resolution
if image_url:
payload["input_reference"] = image_url # "image" is an accepted alias
resp = requests.post(f"{BASE_URL}/v1/videos", headers=_headers(), json=payload, timeout=60)
_check(resp, "Submit")
task_id = resp.json()["id"]
print(f"Submitted task: {task_id}")
return task_id
def wait_for_video(task_id: str) -> Dict[str, Any]:
"""Poll until the task finishes: queued -> in_progress -> completed / failed."""
deadline = time.time() + POLL_TIMEOUT
while time.time() < deadline:
resp = requests.get(f"{BASE_URL}/v1/videos/{task_id}", headers=_headers(), timeout=60)
_check(resp, "Poll")
data = resp.json()
status = str(data.get("status", "")).lower()
print(f" status={status} progress={data.get('progress', 0)}%")
if status == "completed":
return data
if status in {"failed", "cancelled", "expired"}:
reason = (data.get("error") or {}).get("message", "unknown reason")
raise RuntimeError(f"Generation failed: {reason}")
time.sleep(POLL_INTERVAL)
raise TimeoutError(f"Timed out after {POLL_TIMEOUT}s, task {task_id} still running")
def download_video(task_id: str, save_path: str) -> str:
"""Download the finished video to `save_path`."""
resp = requests.get(
f"{BASE_URL}/v1/videos/{task_id}/content",
headers=_headers(),
stream=True,
timeout=300,
)
_check(resp, "Download")
with open(save_path, "wb") as fh:
for chunk in resp.iter_content(chunk_size=1 << 16):
fh.write(chunk)
print(f"Saved video: {save_path}")
return save_path
if __name__ == "__main__":
tid = create_video(PROMPT, seconds=SECONDS, resolution=RESOLUTION, image_url=IMAGE_URL)
wait_for_video(tid)
download_video(tid, f"{tid}.mp4")課金: クォータは送信時に事前消費され(seconds × resolution)、完了時に実際の使用量と突合されます。5秒・720p ≈ $1.10、1080p ≈ $2.48、4k ≈ $9.90。事前消費額を下回る残高のトークンは、タスク作成前に拒否されます。
Responses API
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.tokspan.com/v1", # ← Same base URL as OpenAI-compatible
)
response = client.responses.create(
model="MODEL_NAME", # Replace MODEL_NAME with any model from the catalog
input="Hello!",
)
print(response.output_text)TokSpan APIの使用
SDK 不要 — プレーンな HTTP で OpenAI 互換エンドポイントに直接リクエストを送信できます:
すべてのリクエストは同じ形式です:POST https://api.tokspan.com/v1/chat/completions、APIキーをAuthorizationヘッダーに含めます。
import requests
def chat(prompt: str, model: str = "MODEL_NAME"): # Replace MODEL_NAME with any model from the catalog
response = requests.post(
"https://api.tokspan.com/v1/chat/completions",
headers={
"Authorization": "Bearer sk-your-api-key",
"Content-Type": "application/json",
},
json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
},
)
return response.json()["choices"][0]["message"]["content"]
print(chat("Hello! What models are available?"))const chat = async (prompt: string, model = 'MODEL_NAME') => { // Replace MODEL_NAME with any model from the catalog
const res = await fetch('https://api.tokspan.com/v1/chat/completions', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk-your-api-key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
model,
messages: [{ role: 'user', content: prompt }],
}),
});
const data = await res.json();
return data.choices[0].message.content;
};curl -X POST "https://api.tokspan.com/v1/chat/completions" \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "MODEL_NAME",
"messages": [{"role": "user", "content": "Hello!"}]
}'クロスフォーマット変換
TokSpanはバックグラウンドで異なるAPIフォーマット間の変換を自動的に行います。常にOpenAI Chat Completions形式でリクエストを送信するだけで、TokSpanが上流プロバイダーのネイティブ形式への変換を処理します:
- OpenAI → Claude Messages API — システムプロンプト、マルチターン会話、ツール定義が自動的に再マッピングされます
- OpenAI → Gemini API — コンテンツパーツ、安全設定、生成設定が透過的に変換されます
- Claude → OpenAI形式 — Claudeのネイティブレスポンスが標準のChat Completionsレスポンス構造に正規化されます
つまり、OpenAI Python/Node SDK、LangChain、または任意のOpenAI互換ライブラリを使用して、ネイティブAPI形式に関係なくすべてのモデルを呼び出せるということです。
キーの制限と権限
各APIキーは特定の権限に制限できます:
- モデル:キーがアクセスできるモデルを制限します
- 利用上限:ハードなクォータを設定します — クォータを使い切るとキーは自動的に無効化されます
- IPホワイトリスト:特定のIP範囲からのリクエストのみを許可します
次は何を?
- 完全なモデルカタログを閲覧する — 50以上のプロバイダーにわたる200以上のモデル
- 本番環境の回復力のための自動フェイルオーバーについて学ぶ
- Python、JavaScriptなどのSDK統合を探索する
- すべてのパラメータについてChat Completions APIリファレンスを読む