Documentation
TDSPRO developer docs
One OpenAI-compatible endpoint for 20+ models. Point your client at the base URL below, send your key, and call any model — no SDK changes.
https://api.tdspro.lol/v1Overview
TDSPRO is a single, OpenAI-compatible gateway. You get one API key and one base URL that route every request to the right model — with smart routing, automatic fallback, a token-saving cache, per-key budgets, and full usage analytics. Because the API matches the OpenAI spec exactly, any existing client, SDK, or tool works without code changes.
Drop-in compatible
Identical request & response shapes to the OpenAI API. Change the base URL and key — that is it.
Smart routing
Call an alias like fast or smart and we pick the best engine by speed, cost, and uptime.
Honest by design
Every response carries the real model name in the "model" field — never a silent swap.
More than an API
The same key powers a whole platform, not just the endpoint below. Build your own assistants in Agents, work in the chat-plus-canvas workspace, generate visuals in the Studio, compare models in the Arena, embed a support widget, or take it offline with the CLI and desktop app.
Quickstart
Three steps and you are live. The snippets below are complete and runnable — paste your key and go.
- 1Create a free API key in your dashboard. It starts with sk-hub-.
- 2Set your client base URL to https://api.tdspro.lol/v1.
- 3Call any model by alias (smart, fast, code…) or by full name (gpt-4.1).
Pick your language. All three do the same thing.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.tdspro.lol/v1",
apiKey: process.env.AIHUB_API_KEY, // sk-hub-...
});
const res = await client.chat.completions.create({
model: "smart", // alias → best model for the job
messages: [{ role: "user", content: "Hello from TDSPRO!" }],
});
console.log(res.choices[0]?.message.content);from openai import OpenAI
import os
client = OpenAI(
base_url="https://api.tdspro.lol/v1",
api_key=os.environ["AIHUB_API_KEY"], # sk-hub-...
)
res = client.chat.completions.create(
model="smart", # alias → best model for the job
messages=[{"role": "user", "content": "Hello from TDSPRO!"}],
)
print(res.choices[0].message.content)curl https://api.tdspro.lol/v1/chat/completions \
-H "Authorization: Bearer $AIHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "smart",
"messages": [{"role": "user", "content": "Hello from TDSPRO!"}]
}'Authentication
Authenticate every request with a Bearer token — your TDSPRO key, which starts with sk-hub-. The OpenAI SDKs set this header for you when you pass apiKey.
Authorization: Bearer sk-hub-...# Keep keys in environment variables — never in source control.
export AIHUB_API_KEY="sk-hub-..." # macOS / Linux
$env:AIHUB_API_KEY = "sk-hub-..." # Windows PowerShellKey security
- ✓Store keys in environment variables or a secret manager — never in source control or client-side code.
- ✓Create a separate key per project or environment, and set a spend cap and rate limit on each from the dashboard.
- ✓Rotate or revoke a key instantly in the dashboard if it leaks. Old keys stop working immediately.
- ✓Every request runs over HTTPS (TLS), so your key and payloads are encrypted in transit.
Models & aliases
Call a friendly alias and let smart routing choose the best available model, or pass an exact model name. List everything your key can reach from the /models endpoint.
Capability aliases
These route automatically to the best model for the task — and fall back if one is busy.
fastLowest latency — autocomplete, quick replies, classification.smartBalanced flagship default for hard, general problems.codeTuned for writing, fixing, and reviewing code.visionUnderstands images and screenshots alongside text.reasoningStep-by-step thinking, planning, and math.creativeLong-form writing, brainstorming, and ideas.chatFriendly, balanced everyday conversation.Named models
Prefer an exact flagship? Call it by name. Flagship-class models — including GPT-4.1 and GPT-4o-class — are available directly.
gpt-4.1Flagship general model.gpt-4oFast multimodal flagship.List available models
Returns an OpenAI-style list. Each id can be passed straight into the "model" field.
curl https://api.tdspro.lol/v1/models \
-H "Authorization: Bearer sk-hub-..."{
"object": "list",
"data": [
{ "id": "smart", "object": "model", "owned_by": "ai-hub" },
{ "id": "fast", "object": "model", "owned_by": "ai-hub" },
{ "id": "code", "object": "model", "owned_by": "ai-hub" },
{ "id": "vision", "object": "model", "owned_by": "ai-hub" }
// ...and every named model your key can reach
]
}How to verify the model is real
Every response carries the real model name in the "model" field — we NEVER swap it for a cheaper one. Want to be sure? Compare the answer or behavior with the same model on its official API; the model name in the response will match. In Chat and Arena we surface that exact name on every reply, with a "Verify" button that shows the raw response so you can read the field yourself.
- 1Send any request and read the "model" field in the JSON response — that is the engine that actually answered.
- 2Aliases (smart, fast…) resolve to a concrete model name; that resolved name is what you see in "model".
- 3Run the same prompt against that model on its official API and compare — same name, same family of behavior.
Endpoints
The core OpenAI surface is supported. All paths are relative to the base URL and require the Authorization header.
/chat/completionsChat & tool calling. Streaming supported via "stream": true./embeddingsVector embeddings for search, clustering & RAG./images/generationsGenerate images from a text prompt./modelsList the models and aliases your key can call./meYour key’s plan, usage, and remaining quota.Chat completions
Request
curl https://api.tdspro.lol/v1/chat/completions \
-H "Authorization: Bearer sk-hub-..." \
-H "Content-Type: application/json" \
-d '{
"model": "smart",
"messages": [
{ "role": "system", "content": "You are concise." },
{ "role": "user", "content": "Explain HTTP in one sentence." }
],
"temperature": 0.7,
"max_tokens": 256
}'Response
{
"id": "chatcmpl-...",
"object": "chat.completion",
"model": "gpt-4o", // the real model that answered
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": { "prompt_tokens": 23, "completion_tokens": 14, "total_tokens": 37 }
}The "model" field in the response is the real engine that answered — useful for logging and cost attribution.
Embeddings
curl https://api.tdspro.lol/v1/embeddings \
-H "Authorization: Bearer sk-hub-..." \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-embedding-001",
"input": "The quick brown fox"
}'Returns an OpenAI-style data array of float vectors. Use them for semantic search and RAG.
Streaming
Set "stream": true to receive tokens as they are generated over Server-Sent Events (SSE), exactly like the OpenAI API. The stream ends with a [DONE] sentinel. The OpenAI SDKs handle this for you — just iterate the response.
With the SDK
from openai import OpenAI
client = OpenAI(base_url="https://api.tdspro.lol/v1", api_key="sk-hub-...")
stream = client.chat.completions.create(
model="smart",
messages=[{"role": "user", "content": "Write a haiku about caching."}],
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ""
print(delta, end="", flush=True)Raw SSE wire format
data: {"choices":[{"delta":{"content":"Hello"}}]}
data: {"choices":[{"delta":{"content":" world"}}]}
data: {"choices":[{"delta":{},"finish_reason":"stop"}]}
data: [DONE]Each event is a data: line with a JSON delta. Concatenate the delta.content fields to rebuild the message.
Errors & status codes
Errors use standard HTTP status codes and a consistent JSON shape, so OpenAI-style error handling works unchanged.
Error shape
{
"error": {
"type": "rate_limit_exceeded",
"message": "You hit your per-key rate limit. Retry shortly.",
"code": 429
}
}Status codes
Retry on 429 & 5xx
On a 429 or transient 5xx, retry with exponential backoff. Automatic fallback often resolves it before you even see the error.
async function withRetry(fn, tries = 4) {
for (let i = 0; i < tries; i++) {
try {
return await fn();
} catch (e) {
// Retry only on 429 and transient 5xx.
const status = e?.status ?? e?.response?.status;
if (![429, 500, 502, 503].includes(status) || i === tries - 1) throw e;
await new Promise((r) => setTimeout(r, 2 ** i * 500)); // 0.5s, 1s, 2s, 4s
}
}
}Rate limits & quotas
Rate limits and budgets are set per key in your dashboard, not hard-coded globally — so you control them. Limits scale with your plan.
Per-key rate limit
A requests-per-minute ceiling you set per key. Exceeding it returns 429; just retry shortly.
Spend cap & quota
Set a hard monthly budget or request quota per key. Hitting it returns 402 until you raise it or the period resets.
Plan limits
Free keys are capped at ~50 requests/day; paid plans raise both rate and volume. See pricing for exact numbers.
Live usage
Track remaining quota any time via GET /me or the dashboard — no surprises at the end of the month.
Caching & token savings
Identical requests are served from a token-saving cache, so repeat traffic costs less and returns instantly. It is the same model and the same answer — you simply pay for fewer of them.
Instant repeats
A cache hit skips inference entirely and returns in milliseconds.
Lower bill
Cached responses do not re-bill tokens — your repeat traffic gets cheaper automatically.
Same model, honestly
The cached response carries the same real model name as the original — no swaps.
Caching keys on the exact request (model + messages + parameters). Change any field — temperature, a message — and you get a fresh generation.
Examples
Copy-paste starters for the most common tools. Replace sk-hub-... with your key.
from openai import OpenAI
import os
client = OpenAI(
base_url="https://api.tdspro.lol/v1",
api_key=os.environ["AIHUB_API_KEY"], # sk-hub-...
)
res = client.chat.completions.create(
model="smart", # alias → best model for the job
messages=[{"role": "user", "content": "Hello from TDSPRO!"}],
)
print(res.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.tdspro.lol/v1",
apiKey: process.env.AIHUB_API_KEY,
});
const r = await client.chat.completions.create({
model: "code", // tuned for programming
messages: [{ role: "user", content: "Write a debounce() in TypeScript." }],
});
console.log(r.choices[0].message.content);curl https://api.tdspro.lol/v1/chat/completions \
-H "Authorization: Bearer $AIHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "smart",
"messages": [{"role": "user", "content": "Hello from TDSPRO!"}]
}'{
"$schema": "https://opencode.ai/config.json",
"provider": {
"aihub": {
"npm": "@ai-sdk/openai-compatible",
"name": "TDSPRO",
"options": {
"baseURL": "https://api.tdspro.lol/v1",
"apiKey": "sk-hub-..."
},
"models": {
"smart": { "name": "TDSPRO — Flagship" },
"fast": { "name": "TDSPRO — Fast" },
"code": { "name": "TDSPRO — Code" }
}
}
},
"model": "aihub/smart"
}Drop this into opencode.json. Only the baseURL, key, and model ids are ours.
Settings → Models → OpenAI API Key
Override OpenAI Base URL: https://api.tdspro.lol/v1
OpenAI API Key: sk-hub-...
Custom model name: smart (also add: fast, code, vision)Cursor → Settings → Models. Turn on “Override OpenAI Base URL”, paste the base URL and your key, then add a model named smart.
FAQ
Is the API really OpenAI-compatible?+
Yes. The request and response shapes match the OpenAI spec, so the official OpenAI SDKs and any compatible tool work by changing only the base URL and key.
Do you ever swap my model for a cheaper one?+
Never. Every response carries the real model name in the "model" field. We save you money only through caching identical requests — which return the same model.
What is an alias vs a model name?+
An alias (like smart or fast) is a capability that smart-routes to the best available model and falls back if one is busy. A model name (like gpt-4.1) pins one specific model.
How do I stream responses?+
Set "stream": true. Tokens arrive as Server-Sent Events ending in [DONE]. The OpenAI SDKs iterate this for you automatically.
Where do I find my rate limit and quota?+
Both are per-key and visible in your dashboard, or via GET /me. You set the spend cap and rate limit yourself.
Can I self-host?+
The public endpoint is the simplest path. If you run your own instance, point your client at your local base URL instead — everything else stays the same.
Troubleshooting
401 UnauthorizedYour key is missing, mistyped, or revoked. Confirm the header is exactly “Authorization: Bearer sk-hub-...” and copy a fresh key from the dashboard.
404 model not foundThe model id is unknown. Use an alias (smart, fast, code) or a listed name from GET /models.
429 rate limitedYou exceeded your per-key rate limit. Back off and retry with exponential delay, or raise the limit on the dashboard.
402 out of quotaYour key hit its spend cap or quota. Top up, raise the cap, or wait for the period to reset.
Empty or cut-off responseRaise max_tokens, or stream the response so long outputs arrive incrementally.
SDK ignores the base URLMake sure baseURL/base_url ends in /v1 and you restarted the process after setting the env var.
Get help
Stuck or have a question? We respond fast — usually within a few hours.
Connect a client→
Per-tool quickstart & installers.
Service status→
Live component health.
Contact support→
Telegram & [email protected].
Or reach us directly — Telegram is fastest: Telegram @tdspro_admin · [email protected]