Documentation
Start in one prompt.
ScaledThought is headless. There is no dashboard, so everything here is written for you and for the agent doing the work. The API is OpenAI-compatible, so existing SDKs work unchanged.
Quickstart
Easiest: ask your agent
Paste this into Claude Code, Codex, Cursor or any agent that can run commands. It reads these docs and does the rest.
Or run one command
Creates a free account (no card), writes ST_API_KEY and ST_BASE_URL to .env, and lists the models live in your region. Safe to re-run: with a key already present it just reports the account.
npx -y scaledthought@latest init --region us # or --region caMake your first call
curl "$ST_BASE_URL/chat/completions" \
-H "Authorization: Bearer $ST_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [{"role": "user", "content": "Hello"}]
}'Authentication
Send your key as a bearer token. Keys are scoped to one region and can carry their own budget. The base URL is your region's host, saved to .env as ST_BASE_URL: https://api.us.scaledthought.com/v1 or https://api.ca.scaledthought.com/v1.
Authorization: Bearer $ST_API_KEY
Content-Type: application/jsonChat completions
POST /v1/chat/completions accepts the OpenAI request shape. Use a model id from /models or "auto" to let the router choose.
curl "$ST_BASE_URL/chat/completions" \
-H "Authorization: Bearer $ST_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "kimi-k3",
"messages": [{"role": "user", "content": "Hello"}]
}'Streaming
Set stream: true to receive server-sent events in the OpenAI delta format.
stream = client.chat.completions.create(
model="kimi-k3",
messages=[{"role": "user", "content": "Write a haiku about open weights"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")Tool calling
Pass tools in the OpenAI format. Open models each use a different native tool-call syntax. We normalize all of them, so you always get back standard tool_calls.
resp = client.chat.completions.create(
model="kimi-k3",
messages=[{"role": "user", "content": "Weather in Toronto?"}],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
},
}],
)
print(resp.choices[0].message.tool_calls)Structured output
Use response_format with a JSON schema. Output is constrained during decoding, so it always parses.
resp = client.chat.completions.create(
model="kimi-k3",
messages=[{"role": "user", "content": invoice_text}],
response_format={
"type": "json_schema",
"json_schema": {"name": "invoice", "schema": {
"type": "object",
"properties": {"vendor": {"type": "string"}, "total": {"type": "number"}},
"required": ["vendor", "total"],
}},
},
)Router
Set model: "auto" and an optional quality_floor between 0 and 1 (default 0.8). The router picks the cheapest model expected to clear the floor for that request. You're billed at the chosen model's price, with no router fee.
{
"model": "auto",
"quality_floor": 0.85,
"messages": [{ "role": "user", "content": "..." }]
}Read more on the router page.
Models & benchmarks
GET /v1/models lists the model ids live in your region, in OpenAI's format. GET /v1/models/{id} returns one model's pricing, context length, release date, benchmark scores and live status, so an agent can choose without a human reading a web page. To search the whole catalog, use npx -y scaledthought@latest models or the MCP tool models_search.
curl "$ST_BASE_URL/models"
curl "$ST_BASE_URL/models/mimo-v2-6-pro"Regions & retention
Every key is pinned to us or ca. Requests are served, logged and billed only in that country. Prompts and completions are not stored after the response is returned, and are never used for training. See security.
Keys & budgets
Agents can create scoped keys with hard daily spending limits. When a budget is hit, calls return 402 instead of spending more. On the free tier a key's budget can't exceed the $1/day account cap.
npx -y scaledthought@latest keys create --name support-bot --budget-usd 40Billing & approval
Every account starts on the free tier with no card. To go further, the agent asks for an upgrade with a monthly cap and gets back an approval_url. It sends that link to its human, who adds a card and approves the cap. Nothing is ever charged beyond it. Lowering the cap needs no approval.
npx -y scaledthought@latest billing upgrade --monthly-cap-usd 50Batch inference
Upload a JSONL file of requests and get results within 24 hours at 50% of the normal price. The Files and Batches endpoints match OpenAI's, so client.batches.create works unchanged. Every line is validated up front, so a bad file fails in seconds, not hours.
batch_file = client.files.create(file=open("requests.jsonl", "rb"), purpose="batch")
batch = client.batches.create(
input_file_id=batch_file.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
# later
batch = client.batches.retrieve(batch.id)
results = client.files.content(batch.output_file_id).textEmbeddings
POST /v1/embeddings with an embedding model such as qwen3-embedding-8b. Input can be a string or an array of strings.
vecs = client.embeddings.create(model="qwen3-embedding-8b", input=["open weights", "served hot"])Fine-tuning
Train a LoRA adapter on your own examples. The result is a private model id that only your account can call, served on the same replicas as its base model and billed at the base model's per-token price. Training is billed per 1M training tokens (dataset tokens × epochs); the job response includes an estimate before anything runs. Needs a paid plan. See pricing.
f = client.files.create(file=open("examples.jsonl", "rb"), purpose="fine-tune")
job = client.fine_tuning.jobs.create(model="qwen3-8-27b", training_file=f.id, suffix="triage")
# poll
job = client.fine_tuning.jobs.retrieve(job.id)
resp = client.chat.completions.create(model=job.fine_tuned_model, messages=[...])MCP server
Remote MCP on your region's API host: https://api.us.scaledthought.com/mcp or https://api.ca.scaledthought.com/mcp (Streamable HTTP, 2026-07-28 spec). Authenticate with your API key as a bearer token. MCP can't create accounts: sign up with npx -y scaledthought@latest init or POST /v1/accounts first, then npx -y scaledthought@latest mcp prints the exact command and config for your region. The agent gets these tools:
npx -y scaledthought@latest mcp| Tool | What it does |
|---|---|
| account_status | Plan, region, spend today and this month, key count, how to upgrade. Call it first. |
| keys_manage | List, create or revoke keys (action: list | create | revoke). Create returns the full key once. |
| budget_manage | Set or clear a key's hard daily budget (USD) and rate limits. |
| models_search | Models with prices, context, benchmarks and live status in your region (live_only, category, search). |
| benchmarks_get | Our own per-task scores and speed for one model. |
| usage_query | Requests, tokens and cost over the last N days, by model, day or key. |
| billing_upgrade | With monthly_cap_usd: an approval_url for your human. With no arguments: billing status. |
| fine_tuning | List, get, cancel fine-tuning jobs and their events; list your fine-tuned models. |
| docs_search | Where the docs, llms.txt and your base URL are. |
CLI
Run it as npx -y scaledthought@latest <command>. Output is JSON whenever stdout isn't a terminal (or with --json), and errors are one JSON line on stderr with code, message and hint. Nothing prompts. Keys come from ST_API_KEY or ./.env, never from flags.
| Command | What it does |
|---|---|
| init --region us|ca | Free account (no card). Writes ST_API_KEY and ST_BASE_URL to .env. Safe to re-run. |
| models --live | Models serving in your region now, newest first. Filter with --category or --search. |
| models <id> | Pricing, context, benchmarks and live status for one model. |
| chat -m auto "prompt" | Send one message. -m <id> pins a model; auto lets the router pick. |
| account | Plan, region, spend today and this month. |
| keys create --name <name> --budget-usd 5 | New key with a hard daily budget in USD. The key is printed once. |
| keys list | Your keys (prefixes only). |
| keys revoke <id> | Revoke a key. |
| usage --days 7 --by model | Requests, tokens and cost by model, day or key. |
| billing upgrade --monthly-cap-usd 50 | Returns an approval_url for your human. Only needed past the free tier. |
| billing status | Plan, monthly cap and spend. |
| batches create requests.jsonl | Upload a JSONL file and start a batch at 50% off. Paid plans. |
| fine-tune create examples.jsonl --model <base-id> | Upload a dataset and start a LoRA job. Paid plans. |
| mcp | Prints the `claude mcp add` command and JSON config for your region. |
| status | Per-model health in your region over the last hour. |
API reference
| Endpoint | Description |
|---|---|
| POST /v1/accounts | Create a free account in this host's region. Returns api_key (once) and base_url. No auth. |
| POST /v1/chat/completions | Chat, tools, JSON output, streaming. OpenAI-compatible. model: auto routes. |
| POST /v1/completions | Raw text completion. |
| POST /v1/embeddings | Embeddings for embedding models. |
| GET /v1/models | Model ids live in this region (OpenAI list format). No auth. |
| GET /v1/models/{id} | One model: pricing, context, benchmarks and live_in_region. No auth. |
| GET /v1/models/{id}/benchmarks | Our own per-task scores and speed. |
| GET /v1/account | Plan, region, spend and key count. |
| GET /v1/keys | List keys. |
| POST /v1/keys | Create a key with an optional daily_budget_usd. |
| PATCH /v1/keys/{id} | Change a key's name, daily budget or rate limits. |
| DELETE /v1/keys/{id} | Revoke a key. |
| GET /v1/usage | Requests, tokens and cost (days, group_by). |
| GET /v1/billing | Plan, cap and spend. |
| POST /v1/billing/upgrade | Get an approval_url for a monthly cap (or lower an existing cap). |
| POST /v1/files | Upload JSONL (purpose=batch or fine-tune). |
| POST /v1/batches | Start a batch. GET /v1/batches/{id} to poll, POST /v1/batches/{id}/cancel to stop. |
| POST /v1/fine_tuning/jobs | Start a LoRA job from an uploaded purpose=fine-tune file. |
| GET /v1/status | Per-model health in this region, last hour. |
Rate limits
Limits are per key. Over the limit, calls return 429 rate_limit_exceeded with a Retry-After header in seconds. Free keys can lower their limits but not raise them.
| Plan | Requests / min | Tokens / min | Spend |
|---|---|---|---|
| Free | 60 | 200,000 | $1/day per account, no card |
| Pay as you go | 3,000 | 5,000,000 | Monthly cap you approve |
| Scale | Custom | Custom | Talk to us |
Errors
API errors are {"error":{"message","type","code"}}. CLI errors add a hint and exit non-zero.
| Status | Code | What to do |
|---|---|---|
| 400 | invalid_request | Fix the field named in message. Don't retry unchanged. |
| 400 | invalid_body | Fix the field named in message. Don't retry unchanged. |
| 400 | invalid_json | Send valid JSON with `content-type: application/json`. |
| 401 | invalid_api_key | Key missing, mistyped or revoked. Load ST_API_KEY from .env; don't create a new account. |
| 401 | missing_api_key | Send `Authorization: Bearer $ST_API_KEY`. |
| 402 | budget_exceeded | This key's daily budget is spent. Resets 00:00 UTC. Tell your human; don't retry now. |
| 402 | daily_cap_exceeded | Free tier's $1/day account cap is spent. Resets 00:00 UTC, or upgrade (see below). |
| 402 | monthly_cap_exceeded | Monthly cap reached. Ask your human to approve a higher one: `billing upgrade --monthly-cap-usd <higher>`. |
| 402 | free_tier_key_limit | Free accounts have 5 active keys. Revoke one (`keys revoke <id>`) or upgrade. |
| 402 | free_tier_limit | Free keys can't raise budgets or rate limits. Upgrade first. |
| 402 | batches_require_paid | Batches need a paid plan. Upgrade, then retry. |
| 402 | fine_tuning_requires_paid | Fine-tuning needs a paid plan. Upgrade, then retry. |
| 403 | insufficient_scope | This key lacks the scope. Use the default key from init. |
| 403 | account_suspended | Stop. Tell your human to email hello@scaledthought.com. |
| 404 | model_not_found | Not live here. Pick an id from `models --live` or `GET $ST_BASE_URL/models`, or use auto. |
| 404 | not_found | Wrong path. ST_BASE_URL already ends in /v1; append /chat/completions. |
| 421 | wrong_region | The key belongs to the other region. Use the `base_url` in the error body; remove any hard-coded host. |
| 429 | rate_limit_exceeded | Wait `Retry-After` seconds, then retry. |
| 502 | upstream_error | Transient. Retry with backoff, or use model auto. |
| 503 | service_unavailable | Transient. Retry in a few seconds. |
| exit 1 | no_key | No ST_API_KEY in the environment or ./.env. Run init in the project directory. |
| exit 1 | region_mismatch | A key from the other region already exists here. Use it, or ask your human before creating a second account elsewhere. |
| exit 1 | wrong_region_endpoint | ST_BASE_URL / ST_API_URL points at the other region. Unset it. Nothing was sent. |
| exit 1 | network_error | Couldn't reach the API. Check the network, then retry. |
| exit 1 | bad_region | Use `--region us` or `--region ca`. |
| exit 2 | usage_error | Unknown command, flag or missing argument. Run the command with --help. |