ScaledThought

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

1

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.

2

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 ca
3

Make 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/json

Chat 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 40

Billing & 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 50

Batch 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).text

Embeddings

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
ToolWhat it does
account_statusPlan, region, spend today and this month, key count, how to upgrade. Call it first.
keys_manageList, create or revoke keys (action: list | create | revoke). Create returns the full key once.
budget_manageSet or clear a key's hard daily budget (USD) and rate limits.
models_searchModels with prices, context, benchmarks and live status in your region (live_only, category, search).
benchmarks_getOur own per-task scores and speed for one model.
usage_queryRequests, tokens and cost over the last N days, by model, day or key.
billing_upgradeWith monthly_cap_usd: an approval_url for your human. With no arguments: billing status.
fine_tuningList, get, cancel fine-tuning jobs and their events; list your fine-tuned models.
docs_searchWhere 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.

CommandWhat it does
init --region us|caFree account (no card). Writes ST_API_KEY and ST_BASE_URL to .env. Safe to re-run.
models --liveModels 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.
accountPlan, region, spend today and this month.
keys create --name <name> --budget-usd 5New key with a hard daily budget in USD. The key is printed once.
keys listYour keys (prefixes only).
keys revoke <id>Revoke a key.
usage --days 7 --by modelRequests, tokens and cost by model, day or key.
billing upgrade --monthly-cap-usd 50Returns an approval_url for your human. Only needed past the free tier.
billing statusPlan, monthly cap and spend.
batches create requests.jsonlUpload 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.
mcpPrints the `claude mcp add` command and JSON config for your region.
statusPer-model health in your region over the last hour.

API reference

EndpointDescription
POST /v1/accountsCreate a free account in this host's region. Returns api_key (once) and base_url. No auth.
POST /v1/chat/completionsChat, tools, JSON output, streaming. OpenAI-compatible. model: auto routes.
POST /v1/completionsRaw text completion.
POST /v1/embeddingsEmbeddings for embedding models.
GET /v1/modelsModel 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}/benchmarksOur own per-task scores and speed.
GET /v1/accountPlan, region, spend and key count.
GET /v1/keysList keys.
POST /v1/keysCreate 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/usageRequests, tokens and cost (days, group_by).
GET /v1/billingPlan, cap and spend.
POST /v1/billing/upgradeGet an approval_url for a monthly cap (or lower an existing cap).
POST /v1/filesUpload JSONL (purpose=batch or fine-tune).
POST /v1/batchesStart a batch. GET /v1/batches/{id} to poll, POST /v1/batches/{id}/cancel to stop.
POST /v1/fine_tuning/jobsStart a LoRA job from an uploaded purpose=fine-tune file.
GET /v1/statusPer-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.

PlanRequests / minTokens / minSpend
Free60200,000$1/day per account, no card
Pay as you go3,0005,000,000Monthly cap you approve
ScaleCustomCustomTalk to us

Errors

API errors are {"error":{"message","type","code"}}. CLI errors add a hint and exit non-zero.

StatusCodeWhat to do
400invalid_requestFix the field named in message. Don't retry unchanged.
400invalid_bodyFix the field named in message. Don't retry unchanged.
400invalid_jsonSend valid JSON with `content-type: application/json`.
401invalid_api_keyKey missing, mistyped or revoked. Load ST_API_KEY from .env; don't create a new account.
401missing_api_keySend `Authorization: Bearer $ST_API_KEY`.
402budget_exceededThis key's daily budget is spent. Resets 00:00 UTC. Tell your human; don't retry now.
402daily_cap_exceededFree tier's $1/day account cap is spent. Resets 00:00 UTC, or upgrade (see below).
402monthly_cap_exceededMonthly cap reached. Ask your human to approve a higher one: `billing upgrade --monthly-cap-usd <higher>`.
402free_tier_key_limitFree accounts have 5 active keys. Revoke one (`keys revoke <id>`) or upgrade.
402free_tier_limitFree keys can't raise budgets or rate limits. Upgrade first.
402batches_require_paidBatches need a paid plan. Upgrade, then retry.
402fine_tuning_requires_paidFine-tuning needs a paid plan. Upgrade, then retry.
403insufficient_scopeThis key lacks the scope. Use the default key from init.
403account_suspendedStop. Tell your human to email hello@scaledthought.com.
404model_not_foundNot live here. Pick an id from `models --live` or `GET $ST_BASE_URL/models`, or use auto.
404not_foundWrong path. ST_BASE_URL already ends in /v1; append /chat/completions.
421wrong_regionThe key belongs to the other region. Use the `base_url` in the error body; remove any hard-coded host.
429rate_limit_exceededWait `Retry-After` seconds, then retry.
502upstream_errorTransient. Retry with backoff, or use model auto.
503service_unavailableTransient. Retry in a few seconds.
exit 1no_keyNo ST_API_KEY in the environment or ./.env. Run init in the project directory.
exit 1region_mismatchA key from the other region already exists here. Use it, or ask your human before creating a second account elsewhere.
exit 1wrong_region_endpointST_BASE_URL / ST_API_URL points at the other region. Unset it. Nothing was sent.
exit 1network_errorCouldn't reach the API. Check the network, then retry.
exit 1bad_regionUse `--region us` or `--region ca`.
exit 2usage_errorUnknown command, flag or missing argument. Run the command with --help.

Opens your agent with the prompt typed. You press Enter.