Overview
Quickstart
TokSpan is OpenAI-compatible — change the base URL to access 200+ models instantly. Claude Code / Anthropic-native and the OpenAI Responses API are also supported, and Doubao Seedance video generation runs through the same key, see below.
Create an API Key
Generate your sk- key on the Dashboard's API Keys page.
Change Your Base URL
Point your SDK's base URL at one of the URLs below and call with your key.
Update/Add Model ID
Go to Model Plaza to get the model ID, then update it.
API Base URLs
TokSpan speaks multiple API protocols. Pick the one your SDK already uses — all formats accept the same API key and reach all 200+ models.
https://api.tokspan.com/v1The OpenAI SDK already includes /v1 and appends /chat/completions automatically.
https://api.tokspan.comUse the host root — Claude Code and the Anthropic SDK append /v1/messages themselves.
https://api.tokspan.com/v1/videosPOST /v1/videos creates a task and returns its id; poll until the video is ready, then fetch the content.
https://api.tokspan.com/v1Reuses the OpenAI-compatible base URL and calls /v1/responses.
OpenAI Compatible
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 Native
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")Billing: quota is pre-charged on submit (seconds × resolution) and reconciled against actual usage on completion. 5s at 720p ≈ $1.10, 1080p ≈ $2.48, 4k ≈ $9.90. A token below the pre-charge is rejected before the task is created.
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)Using the TokSpan API
No SDK needed — send requests straight to the OpenAI-compatible endpoint with plain HTTP:
All requests use the same format: POST https://api.tokspan.com/v1/chat/completions with your API key in the Authorization header.
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!"}]
}'Cross-Format Conversion
TokSpan automatically converts between different API formats behind the scenes. You always send requests in the OpenAI Chat Completions format — TokSpan handles translation to the upstream provider's native format:
- OpenAI → Claude Messages API — System prompts, multi-turn conversation, and tool definitions are automatically remapped
- OpenAI → Gemini API — Content parts, safety settings, and generation config are translated transparently
- Claude → OpenAI format — Claude's native responses are normalized to the standard Chat Completions response structure
This means you can use the OpenAI Python/Node SDK, LangChain, or any OpenAI-compatible library to call any model — regardless of its native API format.
Key Scoping & Permissions
Each API key can be scoped to specific permissions:
- Models: Restrict which models the key can access
- Spending cap: Set a hard quota limit — the key is automatically disabled once its quota is exhausted
- IP whitelisting: Only allow requests from specific IP ranges
What's Next?
- Browse the full model catalog — 200+ models across 50+ providers
- Learn about automatic failover for production resilience
- Explore SDK integrations for Python, JavaScript, and more
- Read the Chat Completions API reference for all parameters