Tổng Quan
Bắt Đầu Nhanh
TokSpan tương thích với OpenAI — chỉ cần thay đổi base URL để truy cập hơn 200 mô hình ngay lập tức. Claude Code / Anthropic gốc và OpenAI Responses API cũng được hỗ trợ, và tính năng tạo video Doubao Seedance dùng chung một khóa, xem bên dưới.
Tạo khóa API
Tạo khóa sk- trên trang API Keys trong Bảng điều khiển.
Thay đổi Base URL
Trỏ base URL của SDK đến một trong các URL bên dưới và gọi bằng khóa của bạn.
Cập nhật / Thêm Model ID
Đi tới Model Plaza để lấy ID của mô hình, sau đó cập nhật nó.
URL Cơ Sở API
TokSpan hỗ trợ nhiều giao thức API. Chọn giao thức SDK của bạn đã dùng — mọi định dạng đều chấp nhận cùng một khóa và truy cập hơn 200 mô hình.
https://api.tokspan.com/v1SDK OpenAI đã bao gồm /v1 và tự động thêm /chat/completions.
https://api.tokspan.comDùng đường dẫn gốc của máy chủ — Claude Code và SDK Anthropic tự thêm /v1/messages.
https://api.tokspan.com/v1/videosPOST /v1/videos tạo một tác vụ và trả về id của tác vụ; hãy thăm dò trạng thái cho đến khi video sẵn sàng, rồi tải nội dung về.
https://api.tokspan.com/v1Dùng lại base URL tương thích OpenAI và gọi /v1/responses.
Tương thích 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 Gốc
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")Thanh toán: hạn mức được trừ trước khi gửi (seconds × resolution) và đối soát theo mức sử dụng thực tế khi hoàn tất. 5 giây ở 720p ≈ $1.10, 1080p ≈ $2.48, 4k ≈ $9.90. Token có số dư thấp hơn khoản trừ trước sẽ bị từ chối trước khi tác vụ được tạo.
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)Sử dụng TokSpan API
Không cần SDK — gửi yêu cầu trực tiếp đến endpoint tương thích OpenAI bằng HTTP thuần:
Tất cả yêu cầu sử dụng cùng định dạng: POST https://api.tokspan.com/v1/chat/completions với khóa API của bạn trong header 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!"}]
}'Chuyển Đổi Định Dạng Chéo
TokSpan tự động chuyển đổi giữa các định dạng API khác nhau ở phía sau. Bạn luôn gửi yêu cầu theo định dạng OpenAI Chat Completions — TokSpan xử lý việc chuyển đổi sang định dạng gốc của nhà cung cấp ngược dòng:
- OpenAI → Claude Messages API — System prompt, hội thoại nhiều lượt và định nghĩa công cụ được ánh xạ lại tự động
- OpenAI → Gemini API — Phần nội dung, cài đặt an toàn và cấu hình tạo được chuyển đổi minh bạch
- Claude → định dạng OpenAI — Phản hồi gốc của Claude được chuẩn hóa về cấu trúc phản hồi Chat Completions tiêu chuẩn
Điều này có nghĩa là bạn có thể sử dụng OpenAI Python/Node SDK, LangChain hoặc bất kỳ thư viện tương thích OpenAI nào để gọi bất kỳ mô hình nào — bất kể định dạng API gốc của nó.
Phạm Vi & Quyền Của Khóa
Mỗi khóa API có thể được giới hạn phạm vi với các quyền cụ thể:
- Mô Hình: Giới hạn những mô hình mà khóa có thể truy cập
- Giới hạn chi tiêu: Đặt hạn mức cứng — khóa tự động bị vô hiệu hóa khi hết hạn mức
- Giới hạn IP: Chỉ cho phép yêu cầu từ các dải IP cụ thể
Tiếp Theo Là Gì?
- Duyệt danh mục mô hình đầy đủ — hơn 200 mô hình trên 50+ nhà cung cấp
- Tìm hiểu về tự động chuyển đổi dự phòng cho độ bền production
- Khám phá tích hợp SDK cho Python, JavaScript và hơn thế nữa
- Đọc tham khảo Chat Completions API cho tất cả tham số