Documentation
Commencez en un seul prompt.
ScaledThought est pensé d’abord pour les agents : votre agent s’inscrit et fait le travail, et vous disposez d’un tableau de bord pour la facturation, les clés et vos collègues quand vous le souhaitez. Tout ce qui est ici est écrit pour vous et pour l’agent. L’API est OpenAI-compatible (compatible avec OpenAI) : la plupart du code utilisant le SDK OpenAI fonctionne en changeant l’URL de base et la clé.
Démarrage rapide
Le plus simple : demandez à votre agent
Collez ceci dans Claude Code, Codex, Cursor ou tout agent capable d’exécuter des commandes. Il lit /llms.txt et exécute les étapes de configuration.
Liens profonds vers des applications que vous avez installées. Claude et Claude Code sont des marques d’Anthropic ; Codex est une marque d’OpenAI. ScaledThought n’est ni affilié à l’une ou l’autre ni approuvé par elles.
Non affilié à Anthropic, OpenAI, Cursor ni à aucun éditeur de modèles, et non approuvé par eux. Claude, Claude Code, Codex, Cursor, OpenAI et les noms de modèles sont des marques de leurs propriétaires.
Ou exécutez une seule commande
Crée un compte dans la région des États-Unis, écrit ST_API_KEY et ST_BASE_URL dans .env, et liste les modèles en ligne dans cette région. Peut être relancée sans risque : si une clé est déjà présente, elle indique simplement le compte. La région du Canada arrive bientôt ; d’ici son ouverture, son API ne répond pas et --region ca échoue avec network_error.
npx -y scaledthought@0.3 init --region usAchetez des crédits
Chaque appel est payé avec des crédits prépayés, de $20 à $2,000 par recharge, au plus $2,000 par 24 heures et 2 liens d’approbation ouverts à la fois. L’agent demande une recharge et envoie l’approval_url qu’il reçoit à la personne pour qui il travaille, et celle-ci paie par carte. Tant que les crédits ne sont pas arrivés, les appels renvoient 402 insufficient_credits. Plus de détails dans Crédits et approbation.
npx -y scaledthought@0.3 billing topup --amount-usd 20Faites votre premier appel
curl "$ST_BASE_URL/chat/completions" \
-H "Authorization: Bearer $ST_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "deepseek-v4-1-flash",
"messages": [{"role": "user", "content": "Hello"}]
}'Authentification
Envoyez votre clé comme jeton bearer. Les clés sont limitées à une seule région et peuvent avoir leur propre budget. L’URL de base est l’hôte de votre région, enregistré dans .env sous ST_BASE_URL : https://api.us.scaledthought.com/v1 (celui du Canada, https://api.ca.scaledthought.com/v1, arrive bientôt).
Authorization: Bearer $ST_API_KEY
Content-Type: application/jsonComplétions de chat
POST /v1/chat/completions accepte le format de requête d’OpenAI. Utilisez un identifiant de modèle tiré de npx -y scaledthought@0.3 models --live ou de /pricing.
curl "$ST_BASE_URL/chat/completions" \
-H "Authorization: Bearer $ST_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "deepseek-v4-1-flash",
"messages": [{"role": "user", "content": "Hello"}]
}'Streaming
Définissez stream: true pour recevoir des événements envoyés par le serveur (server-sent events) au format delta d’OpenAI.
stream = client.chat.completions.create(
model="deepseek-v4-1-flash",
messages=[{"role": "user", "content": "Write a haiku about open weights"}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")Appel d’outils
Passez tools au format d’OpenAI. Les modèles qui prennent en charge l’appel d’outils renvoient des tool_calls standard. La prise en charge et la qualité varient selon le modèle : consultez la fiche d’un modèle avant de vous y fier.
resp = client.chat.completions.create(
model="deepseek-v4-1-flash",
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)Sortie structurée
Utilisez response_format avec un schéma JSON. Sur les modèles qui le prennent en charge, la sortie est contrainte au schéma pendant le décodage. Validez le résultat avant de vous y fier.
resp = client.chat.completions.create(
model="deepseek-v4-1-flash",
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"],
}},
},
)API Responses et Codex
POST $ST_BASE_URL/responses parle l’API Responses d’OpenAI, donc les clients qui n’utilisent que ce protocole, comme Codex, peuvent utiliser ScaledThought comme fournisseur de modèles. Elle accepte input (une chaîne, ou des messages et des éléments function_call et function_call_output), instructions, des outils de type fonction et personnalisés (forme libre), tool_choice, max_output_tokens, text.format pour une sortie JSON et stream: true (des événements Responses, se terminant par response.completed ou response.incomplete avec son usage, ou response.failed avec une error).
Elle est sans état. Nous ne stockons aucune réponse : envoyez donc toute la conversation dans input à chaque tour (Codex le fait) et omettez previous_response_id, qui renvoie 400 invalid_request ; store vaut toujours false. Les outils hébergés comme la recherche de fichiers renvoient 400 ; un outil de recherche web est ignoré. Les requêtes sans max_output_tokens reçoivent un plafond égal à ce que le contexte du modèle laisse après votre prompt, au plus 32 768 tokens.
La facturation est la même que pour les complétions de chat : par token, d’après l’utilisation que rapporte le serveur du modèle, payée avec vos crédits.
# ~/.codex/config.toml
model = "deepseek-v4-1-flash" # or a model id from `npx -y scaledthought@0.3 models --live`
model_provider = "scaledthought"
[model_providers.scaledthought]
name = "ScaledThought"
base_url = "https://api.us.scaledthought.com/v1" # your ST_BASE_URL
env_key = "ST_API_KEY"
wire_api = "responses"
model_catalog_url = "https://api.us.scaledthought.com/v1/codex/models" # same host (and region) as base_urlCodex lit ST_API_KEY dans l’environnement : chargez donc d’abord ./.env dans le shell. wire_api = "responses" est obligatoire : ScaledThought sert Codex via l’API Responses.
model_catalog_url indique à Codex les fenêtres de contexte des modèles en ligne dans votre région, pour qu’il compacte les longues sessions à temps, et lui donne son outil d’édition apply_patch. Ce catalogue est construit à partir des modèles en ligne à chaque requête ; Codex l’appelle avec votre clé, gardez-le donc sur le même hôte que base_url (celui de votre région).
Modèles et benchmarks
GET /v1/models liste les identifiants des modèles en ligne dans votre région, au format d’OpenAI. Cette liste fait foi sur ce que vous pouvez appeler. GET /v1/models/{id} renvoie le prix d’un modèle, sa longueur de contexte, sa date de sortie, ses résultats de benchmarks et son état, pour qu’un agent puisse choisir sans qu’un humain lise une page web. Pour chercher et filtrer, utilisez npx -y scaledthought@0.3 models --live ou l’outil MCP models_search. Pour les personnes, /pricing liste chaque modèle en ligne aux États-Unis avec son prix, depuis la même API.
curl "$ST_BASE_URL/models"
curl "$ST_BASE_URL/models/deepseek-v4-1-flash"Régions et conservation
Chaque clé est liée à sa région. La région des États-Unis est ouverte maintenant ; le Canada (ca) arrive bientôt ; son API ne répond pas avant son ouverture. Les requêtes sont servies et journalisées, et les données de compte et d’utilisation stockées, uniquement dans ce pays. Les paiements par carte de toutes les régions sont traités par Stripe aux États-Unis. Les prompts et les complétions ne sont pas stockés une fois la réponse renvoyée, et ne sont jamais utilisés pour l’entraînement. Les fichiers de lots et de fine-tuning sont effacés après 30 jours, ou plus tôt avec DELETE /v1/files/{id}. Chaque réponse porte x-st-region et x-st-data-retention: none. Voir sécurité (ou /security.json) et la Politique de confidentialité (en anglais).
Clés et budgets
Les agents peuvent créer des clés à portée limitée avec des plafonds de dépense quotidiens stricts. Quand un budget est atteint, les appels renvoient 402 au lieu de dépenser davantage. Une clé révoquée cesse de fonctionner en environ 30 secondes.
npx -y scaledthought@0.3 keys create --name support-bot --budget-usd 40Les portées sont inference, read, keys, billing. Une clé ne peut donner à une nouvelle clé que des portées qu’elle possède elle-même (sinon 403 scope_not_allowed). Expiration : envoyez expires_in (comme "30d") ou expires_at, jusqu’à 365 jours ; ensuite, la clé reçoit 401 key_expired. Une clé ne survit jamais à la clé qui l’a créée.
Clés de sous-agent : avec child: true, la nouvelle clé enregistre la clé appelante comme parente. Son budget quotidien tient dans ce qu’il reste aujourd’hui à la parente, ses limites de débit et son expiration ne dépassent pas celles de la parente, et elle ne peut gérer que ses propres sous-clés. Révoquer une clé révoque toutes les clés situées sous elle.
Rotation : POST /v1/keys/{id}/rotate crée une clé de remplacement avec le même nom, les mêmes portées, le même budget et les mêmes limites, renvoyée une seule fois. L’ancienne clé continue de fonctionner pendant grace (par défaut 24h, de "0" à "7d"). Auto-révocation : DELETE /v1/keys/self révoque la clé appelante et ses clés de sous-agent, sans portée requise, pour qu’un agent qui soupçonne une fuite puisse agir immédiatement.
npx -y scaledthought@0.3 keys create --name sub-agent --child --scopes inference --budget-usd 2 --expires-in 12h
npx -y scaledthought@0.3 keys rotate key_… --grace 24h
npx -y scaledthought@0.3 keys revoke-selfPlus de détails sur la protection des clés et des données : sécurité.
Crédits et approbation
L’utilisation est payée avec des crédits prépayés, de $20 à $2,000 par recharge, au plus $2,000 par 24 heures et 2 liens d’approbation ouverts à la fois. L’agent demande une recharge (20 $ par défaut) et reçoit une approval_url : une page de financement où la personne pour qui il travaille confirme ou modifie le montant, peut activer la recharge automatique, et paie par carte. Les crédits arrivent une fois le paiement confirmé, et nous envoyons un reçu par courriel. Rien n’est jamais facturé sans cette approbation. Les crédits n’expirent pas. Quand ils sont épuisés, les requêtes renvoient 402 insufficient_credits avec le solde et le montant nécessaire.
npx -y scaledthought@0.3 billing topup --amount-usd 20La recharge automatique est facultative et recommandée : quand le solde passe sous un seuil (5 $ par défaut), la carte enregistrée ajoute un montant fixe (20 $ par défaut), pour que l’agent ne soit jamais bloqué. La personne pour qui l’agent travaille l’active sur la page de financement de n’importe quelle recharge, ou sans rien acheter via un lien de configuration de la recharge automatique (billing auto-reload setup), où elle enregistre une carte. Les recharges sont limitées à 2 000 $ par 24 heures. L’activer ou relever une limite exige une nouvelle approbation ; la désactiver ou la réduire, non. Si une recharge est refusée, la recharge automatique se désactive d’elle-même et la prochaine erreur 402 indique à l’agent d’obtenir un nouveau lien. billing status affiche le solde et les recharges en attente ; billing transactions liste chaque achat, recharge et débit.
npx -y scaledthought@0.3 billing topup --amount-usd 20 --auto-reload-below 5 --auto-reload-amount 20
npx -y scaledthought@0.3 billing auto-reload setup --below 5 --amount 20 # no purchase: they save a card
npx -y scaledthought@0.3 billing auto-reload offAvis et webhooks
Les réponses peuvent porter x-st-notice avec des codes séparés par des virgules : low_balance (un compte dont le solde est inférieur à $5). Un agent qui en voit un doit dire à la personne pour qui il travaille ce qu’il faut approuver. GET /v1/account, l’outil MCP account_status, status et doctor affichent les mêmes codes avec le texte à transmettre.
Les webhooks poussent plutôt les mêmes signaux : balance.low, key.expiring et budget.exhausted. Les points de terminaison doivent être des URL https publiques sur le port 443. Chaque POST porte x-st-signature: t=…,v1=…, un HMAC-SHA256 de <t>.<raw body> calculé avec le secret de signature du point de terminaison, affiché une seule fois quand vous l’ajoutez. Les envois vont à votre URL où qu’elle soit hébergée, même hors de la région de votre compte, et ne portent que id, type, created_at, region, account_id et data : des identifiants, des montants entiers en micro-dollars, des nombres de jours et des horodatages, jamais de prompts, de noms ni d’adresses courriel. data par événement : balance.low {balance_micros, threshold_micros}, key.expiring {key_id, expires_at}, budget.exhausted {scope, key_id, budget_micros, spent_today_micros, resets_at}. Les envois qui échouent sont relancés avec un délai croissant pendant environ deux jours.
npx -y scaledthought@0.3 webhooks add https://hooks.example.com/st --events balance.low,budget.exhaustedEn-têtes de requête facultatifs : x-st-app nomme votre application dans les données d’utilisation (non publié), et x-st-session garde une conversation sur la même réplique pour que son préfixe en cache soit réutilisé (en mémoire seulement, jamais stocké). Au Canada, les requêtes ne débordent jamais vers un autre pays : quand toutes les répliques d’un modèle sont occupées, une requête attend brièvement, puis reçoit 429 capacity_exhausted avec Retry-After.
Inférence par lots
Téléversez un fichier JSONL de requêtes et obtenez les résultats à 50 % du prix normal. Les lots s’exécutent dans une fenêtre de traitement de 24 heures et se terminent généralement dans ce délai, mais ce n’est pas garanti. Les points de terminaison Files et Batches suivent ceux d’OpenAI, donc client.batches.create fonctionne. Chaque ligne est validée dès le départ : un fichier invalide échoue en quelques secondes.
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 avec un modèle d’embeddings (trouvez-en un avec models --live --modality embedding). L’entrée peut être une chaîne ou un tableau de chaînes.
vecs = client.embeddings.create(model="<embedding-model-id>", input=["open weights", "served hot"])Fine-tuning
Entraînez un adaptateur LoRA sur vos propres exemples. Le résultat est un identifiant de modèle privé que seul votre compte peut appeler, servi sur les mêmes répliques que son modèle de base et facturé au prix par token du modèle de base. Seuls les modèles de base exécutés sur nos propres GPU dans votre région peuvent être entraînés, et les adaptateurs ne peuvent pas être téléchargés. L’entraînement est facturé par 1 M de tokens d’entraînement (tokens du jeu de données × époques) ; la réponse de la tâche inclut une estimation avant tout lancement. Payé avec des crédits prépayés. Voir les tarifs.
f = client.files.create(file=open("examples.jsonl", "rb"), purpose="fine-tune")
job = client.fine_tuning.jobs.create(model="<base-id>", 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=[...])Serveur MCP
MCP distant sur l’hôte d’API de votre région : https://api.us.scaledthought.com/mcp (celui du Canada, https://api.ca.scaledthought.com/mcp, arrive bientôt ; Streamable HTTP, spécification 2026-07-28). Authentifiez-vous avec votre clé d’API comme jeton bearer. MCP ne peut pas créer de compte : inscrivez-vous d’abord avec npx -y scaledthought@0.3 init ou POST /v1/accounts, puis npx -y scaledthought@0.3 mcp affiche la commande et la configuration exactes pour votre région. L’agent dispose de ces outils :
npx -y scaledthought@0.3 mcp- account_status
- Region, spend, credit balance, auto-reload, key count and notices (tell your human about each). Call it first.
- account_settings
- Read or change account settings. ad_measurement: false opts the account out of ad measurement; any key can do it.
- keys_manage
- List, create, rotate or revoke keys (action: list | create | rotate | revoke | revoke_self). create and rotate return the full key once; create takes scopes, expires_in, child (a sub-agent key) and lives_in (where it will be stored); rotate takes grace. revoke_self revokes the key in use.
- budget_manage
- Set or clear a key's hard daily budget (USD) and rate limits.
- webhooks
- Signed HTTPS callbacks for balance.low, key.expiring and budget.exhausted (action: add | list | remove). add returns signing_secret once.
- 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_topup
- With amount_usd (and optional auto_reload): an approval_url for your human to buy credits. action: status | transactions | auto_reload_off.
- 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.
| Outil | Ce qu’il fait |
|---|---|
| account_status | Region, spend, credit balance, auto-reload, key count and notices (tell your human about each). Call it first. |
| account_settings | Read or change account settings. ad_measurement: false opts the account out of ad measurement; any key can do it. |
| keys_manage | List, create, rotate or revoke keys (action: list | create | rotate | revoke | revoke_self). create and rotate return the full key once; create takes scopes, expires_in, child (a sub-agent key) and lives_in (where it will be stored); rotate takes grace. revoke_self revokes the key in use. |
| budget_manage | Set or clear a key's hard daily budget (USD) and rate limits. |
| webhooks | Signed HTTPS callbacks for balance.low, key.expiring and budget.exhausted (action: add | list | remove). add returns signing_secret once. |
| 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_topup | With amount_usd (and optional auto_reload): an approval_url for your human to buy credits. action: status | transactions | auto_reload_off. |
| 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
Exécutez-la sous la forme npx -y scaledthought@0.3 <command>. La sortie est en JSON chaque fois que stdout n’est pas un terminal (ou avec --json), et les erreurs sont une ligne JSON sur stderr avec code, message et hint. Rien n’est demandé de façon interactive. Les clés viennent de ST_API_KEY ou de ./.env, jamais d’options de ligne de commande.
- init --region us
- Account and key in the US. Writes ST_API_KEY and ST_BASE_URL to .env. Safe to re-run. Canada (ca) is coming soon.
- init --account Acme
- In a new folder on a machine with saved accounts: use that account with a new project key (init asks which when there are several). --new-account makes a separate account; --no-save keeps the key out of this machine's credential store.
- login --region us
- Connect to an existing account: prints a code your human types on the dashboard's connect page (opened in their browser). Then run login --wait.
- login --wait
- Waits about 90 s for your human to approve the code, then writes a new key to .env (never printed). Re-run on authorization_pending.
- login --code -
- Use a connect line made on the dashboard (its stl_ code on stdin, out of shell history): already approved, works once for 15 minutes.
- use "Side project"
- Point this folder at another account saved on this machine: a new project key in .env; the folder's old project key is revoked.
- init --region us --source a-rd
- The same, recording the campaign code of the scaledthought.com/go/<code> link that brought you (optional). An invalid code is dropped with a warning.
- models --live
- Models serving in your region now, newest first, with prices. Filter with --category or --search. The US list is also on /pricing.
- models <id>
- Pricing, context, benchmarks and live status for one model.
- chat -m <id> "prompt"
- Send one message to a model id from models --live.
- account
- Region, spend and credit balance.
- account ad-measurement off
- Opt out of ad measurement: nothing about the account is ever sent to an ad platform. on turns it back on.
- keys create --name <name> --budget-usd 5
- New key with a hard daily budget in USD. The key is printed once.
- keys create --name <name> --expires-in 30d --scopes inference,read
- A key that expires (at most 365d) with a subset of your key's scopes.
- keys create --name <name> --child --budget-usd 2
- A sub-agent key: scopes, budget, rate limits and expiry within your key's; revoked when your key is.
- keys list
- Your keys (prefixes only).
- keys rotate <id> --grace 24h
- Replace a key: the new key is printed once; the old one keeps working for the grace period (0 to 7d).
- keys revoke <id>
- Revoke a key and its sub-agent keys. They stop working within about 30 seconds.
- keys revoke-self
- Revoke the key you are using now (and its sub-agent keys), e.g. if it may have leaked. Irreversible.
- keys put github --repo <owner/repo> --budget-usd 2
- Put a new sub-agent key straight into a platform's secret store as ST_API_KEY, through its own CLI with the key on stdin (never printed). Destinations: github, vercel, fly, cloudflare, gcp, aws, k8s, doppler. The key is named after the place and records where it lives (lives_in). If storing fails, the new key is revoked.
- keys rotate --all --push --grace 1h
- Rotate every key that keys put stored somewhere and put each replacement in the same place; the old keys stop after the grace period. Prints no keys. One key: keys rotate <id> --push.
- connect opencode
- Point an OpenAI-compatible tool at ScaledThought: opencode and aider get the base URL and their own sub-agent key in their config (files 0600, key never printed); cursor and continue get steps for your human.
- usage --days 7 --by model
- Requests, tokens and cost by model, day or key.
- billing status
- Credit balance, auto-reload, pending top-ups.
- billing topup --amount-usd 20
- Buy prepaid credits ($20 to $2,000 per top-up, at most $2,000 per 24 hours and 2 open approval links at a time; default 20): opens the funding page in your human's browser, where they confirm the amount, can turn on auto-reload and pay.
- billing wait
- Returns as soon as your human pays the open top-up, with the new balance. Polls about 90 seconds a run; run it again on topup_pending.
- billing topup --amount-usd 20 --auto-reload-below 5 --auto-reload-amount 20
- Top up with auto-reload pre-selected on the funding page (your human can untick it).
- billing auto-reload setup --below 5 --amount 20
- Turn auto-reload on without buying anything: opens a page where your human saves a card. Then billing wait.
- billing auto-reload off
- Turn auto-reload off. No approval needed.
- billing transactions
- The credit ledger: purchases, auto-reloads, usage, batches, fine-tuning, refunds.
- batches create requests.jsonl
- Upload a JSONL file and start a batch at 50% off. Needs prepaid credits.
- fine-tune create examples.jsonl --model <base-id>
- Upload a dataset and start a LoRA job. Needs prepaid credits.
- webhooks add https://hooks.example.com/st --events balance.low,budget.exhausted
- Get a signed POST when the balance is low, a key is about to expire or a budget is spent (default: every event). Prints signing_secret once.
- webhooks list
- Your webhook endpoints.
- webhooks remove <id>
- Delete a webhook endpoint.
- doctor
- Checks the key in .env, its region, the account and its credit, and lists notices to tell your human.
- mcp
- Prints the `claude mcp add` command and JSON config for your region.
- dashboard --page billing
- Opens your human's dashboard (overview, billing, keys, members, connect) in their browser. If they aren't signed in, one click emails them a link.
- members
- Who can sign in to the account's dashboard: email, role (owner or member), status.
- status
- Per-model health in your region over the last hour, plus your account's notices when a key is set.
| Commande | Ce qu’il fait |
|---|---|
| init --region us | Account and key in the US. Writes ST_API_KEY and ST_BASE_URL to .env. Safe to re-run. Canada (ca) is coming soon. |
| init --account Acme | In a new folder on a machine with saved accounts: use that account with a new project key (init asks which when there are several). --new-account makes a separate account; --no-save keeps the key out of this machine's credential store. |
| login --region us | Connect to an existing account: prints a code your human types on the dashboard's connect page (opened in their browser). Then run login --wait. |
| login --wait | Waits about 90 s for your human to approve the code, then writes a new key to .env (never printed). Re-run on authorization_pending. |
| login --code - | Use a connect line made on the dashboard (its stl_ code on stdin, out of shell history): already approved, works once for 15 minutes. |
| use "Side project" | Point this folder at another account saved on this machine: a new project key in .env; the folder's old project key is revoked. |
| init --region us --source a-rd | The same, recording the campaign code of the scaledthought.com/go/<code> link that brought you (optional). An invalid code is dropped with a warning. |
| models --live | Models serving in your region now, newest first, with prices. Filter with --category or --search. The US list is also on /pricing. |
| models <id> | Pricing, context, benchmarks and live status for one model. |
| chat -m <id> "prompt" | Send one message to a model id from models --live. |
| account | Region, spend and credit balance. |
| account ad-measurement off | Opt out of ad measurement: nothing about the account is ever sent to an ad platform. on turns it back on. |
| keys create --name <name> --budget-usd 5 | New key with a hard daily budget in USD. The key is printed once. |
| keys create --name <name> --expires-in 30d --scopes inference,read | A key that expires (at most 365d) with a subset of your key's scopes. |
| keys create --name <name> --child --budget-usd 2 | A sub-agent key: scopes, budget, rate limits and expiry within your key's; revoked when your key is. |
| keys list | Your keys (prefixes only). |
| keys rotate <id> --grace 24h | Replace a key: the new key is printed once; the old one keeps working for the grace period (0 to 7d). |
| keys revoke <id> | Revoke a key and its sub-agent keys. They stop working within about 30 seconds. |
| keys revoke-self | Revoke the key you are using now (and its sub-agent keys), e.g. if it may have leaked. Irreversible. |
| keys put github --repo <owner/repo> --budget-usd 2 | Put a new sub-agent key straight into a platform's secret store as ST_API_KEY, through its own CLI with the key on stdin (never printed). Destinations: github, vercel, fly, cloudflare, gcp, aws, k8s, doppler. The key is named after the place and records where it lives (lives_in). If storing fails, the new key is revoked. |
| keys rotate --all --push --grace 1h | Rotate every key that keys put stored somewhere and put each replacement in the same place; the old keys stop after the grace period. Prints no keys. One key: keys rotate <id> --push. |
| connect opencode | Point an OpenAI-compatible tool at ScaledThought: opencode and aider get the base URL and their own sub-agent key in their config (files 0600, key never printed); cursor and continue get steps for your human. |
| usage --days 7 --by model | Requests, tokens and cost by model, day or key. |
| billing status | Credit balance, auto-reload, pending top-ups. |
| billing topup --amount-usd 20 | Buy prepaid credits ($20 to $2,000 per top-up, at most $2,000 per 24 hours and 2 open approval links at a time; default 20): opens the funding page in your human's browser, where they confirm the amount, can turn on auto-reload and pay. |
| billing wait | Returns as soon as your human pays the open top-up, with the new balance. Polls about 90 seconds a run; run it again on topup_pending. |
| billing topup --amount-usd 20 --auto-reload-below 5 --auto-reload-amount 20 | Top up with auto-reload pre-selected on the funding page (your human can untick it). |
| billing auto-reload setup --below 5 --amount 20 | Turn auto-reload on without buying anything: opens a page where your human saves a card. Then billing wait. |
| billing auto-reload off | Turn auto-reload off. No approval needed. |
| billing transactions | The credit ledger: purchases, auto-reloads, usage, batches, fine-tuning, refunds. |
| batches create requests.jsonl | Upload a JSONL file and start a batch at 50% off. Needs prepaid credits. |
| fine-tune create examples.jsonl --model <base-id> | Upload a dataset and start a LoRA job. Needs prepaid credits. |
| webhooks add https://hooks.example.com/st --events balance.low,budget.exhausted | Get a signed POST when the balance is low, a key is about to expire or a budget is spent (default: every event). Prints signing_secret once. |
| webhooks list | Your webhook endpoints. |
| webhooks remove <id> | Delete a webhook endpoint. |
| doctor | Checks the key in .env, its region, the account and its credit, and lists notices to tell your human. |
| mcp | Prints the `claude mcp add` command and JSON config for your region. |
| dashboard --page billing | Opens your human's dashboard (overview, billing, keys, members, connect) in their browser. If they aren't signed in, one click emails them a link. |
| members | Who can sign in to the account's dashboard: email, role (owner or member), status. |
| status | Per-model health in your region over the last hour, plus your account's notices when a key is set. |
Référence de l’API
- POST /v1/accounts
- Create an account in this host's region. Returns api_key (once) and base_url. No auth. Optional source: the campaign code from a /go/<code> link.
- POST /v1/chat/completions
- Chat, tools, JSON output, streaming. OpenAI-compatible.
- POST /v1/responses
- The OpenAI Responses API (Codex): function and custom tools, streaming. Stateless: send the whole conversation each turn; previous_response_id isn't supported.
- 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, balance, spend, key count and notices (low_balance) with notice_text to relay to your human.
- PATCH /v1/account
- Account settings: {"ad_measurement": false} opts out of ad measurement (any key); true needs the keys or billing scope.
- GET /v1/keys
- List keys.
- POST /v1/keys
- Create a key: scopes (a subset of yours), daily_budget_usd, rate limits, expires_in or expires_at (max 365d), child: true for a sub-agent key, lives_in (where it will be stored, display only).
- POST /v1/keys/{id}/rotate
- Replace a key. The new key is returned once; the old one works for grace (default 24h, 0 to 7d).
- PATCH /v1/keys/{id}
- Change a key's name, daily budget, rate limits or lives_in (null clears it).
- DELETE /v1/keys/{id}
- Revoke a key and its sub-agent keys.
- DELETE /v1/keys/self
- The calling key revokes itself and its sub-agent keys. No scope needed.
- GET /v1/usage
- Requests, tokens and cost (days, group_by).
- GET /v1/billing
- Credit balance, auto-reload, pending top-ups and recent transactions.
- POST /v1/billing/topup
- Buy credits: {amount_usd, auto_reload?} returns an approval_url for your human.
- GET /v1/billing/topups/{id}
- One top-up's status (open, paid, expired, failed).
- PATCH /v1/billing/auto-reload
- Disable or lower auto-reload. Raising it needs a new top-up approval.
- GET /v1/billing/transactions
- The credit ledger, newest first (cursor).
- POST /v1/webhooks
- Add a webhook: {url (public https, port 443), events}. Returns signing_secret once. Billing scope; at most 5.
- GET /v1/webhooks
- Your webhook endpoints (status, last success and failure).
- DELETE /v1/webhooks/{id}
- Delete a webhook endpoint.
- 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.
- POST /v1/dashboard/link
- A URL for your human's dashboard (optional page), the owners, and a message to relay. billing or keys scope.
- POST /v1/device/codes
- Ask to connect to an existing account. No key. Returns device_code (secret), user_code for your human to type at verification_url, expires_in, interval.
- POST /v1/device/token
- Collect the key once approved: {device_code}, or {connect_code} (stl_…) for a dashboard connect line. 428 authorization_pending until then; one key per code, with the approver's scopes.
- GET /v1/members
- Who can sign in to the dashboard (email, role, status). read scope.
| Point de terminaison | Description |
|---|---|
| POST /v1/accounts | Create an account in this host's region. Returns api_key (once) and base_url. No auth. Optional source: the campaign code from a /go/<code> link. |
| POST /v1/chat/completions | Chat, tools, JSON output, streaming. OpenAI-compatible. |
| POST /v1/responses | The OpenAI Responses API (Codex): function and custom tools, streaming. Stateless: send the whole conversation each turn; previous_response_id isn't supported. |
| 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, balance, spend, key count and notices (low_balance) with notice_text to relay to your human. |
| PATCH /v1/account | Account settings: {"ad_measurement": false} opts out of ad measurement (any key); true needs the keys or billing scope. |
| GET /v1/keys | List keys. |
| POST /v1/keys | Create a key: scopes (a subset of yours), daily_budget_usd, rate limits, expires_in or expires_at (max 365d), child: true for a sub-agent key, lives_in (where it will be stored, display only). |
| POST /v1/keys/{id}/rotate | Replace a key. The new key is returned once; the old one works for grace (default 24h, 0 to 7d). |
| PATCH /v1/keys/{id} | Change a key's name, daily budget, rate limits or lives_in (null clears it). |
| DELETE /v1/keys/{id} | Revoke a key and its sub-agent keys. |
| DELETE /v1/keys/self | The calling key revokes itself and its sub-agent keys. No scope needed. |
| GET /v1/usage | Requests, tokens and cost (days, group_by). |
| GET /v1/billing | Credit balance, auto-reload, pending top-ups and recent transactions. |
| POST /v1/billing/topup | Buy credits: {amount_usd, auto_reload?} returns an approval_url for your human. |
| GET /v1/billing/topups/{id} | One top-up's status (open, paid, expired, failed). |
| PATCH /v1/billing/auto-reload | Disable or lower auto-reload. Raising it needs a new top-up approval. |
| GET /v1/billing/transactions | The credit ledger, newest first (cursor). |
| POST /v1/webhooks | Add a webhook: {url (public https, port 443), events}. Returns signing_secret once. Billing scope; at most 5. |
| GET /v1/webhooks | Your webhook endpoints (status, last success and failure). |
| DELETE /v1/webhooks/{id} | Delete a webhook endpoint. |
| 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. |
| POST /v1/dashboard/link | A URL for your human's dashboard (optional page), the owners, and a message to relay. billing or keys scope. |
| POST /v1/device/codes | Ask to connect to an existing account. No key. Returns device_code (secret), user_code for your human to type at verification_url, expires_in, interval. |
| POST /v1/device/token | Collect the key once approved: {device_code}, or {connect_code} (stl_…) for a dashboard connect line. 428 authorization_pending until then; one key per code, with the approver's scopes. |
| GET /v1/members | Who can sign in to the dashboard (email, role, status). read scope. |
Limites de débit
Les limites s’appliquent par clé. Au-delà de la limite, les appels renvoient 429 rate_limit_exceeded avec un en-tête Retry-After en secondes. Jusqu’au premier achat de crédits du compte, les clés peuvent abaisser leurs limites mais pas les relever.
- Nouveau compte
- Requêtes / min: 60
- Tokens / min: 200,000
- Dépense: Jusqu’au premier achat de crédits : jusqu’à 5 clés
- Crédits prépayés
- Requêtes / min: 3,000
- Tokens / min: 5,000,000
- Dépense: Crédits achetés par la personne pour qui votre agent travaille, de $20 à $2,000 par recharge, $2,000 par 24 h
- Volume
- Requêtes / min: Sur mesure
- Tokens / min: Sur mesure
- Dépense: Parlez-nous
| Formule | Requêtes / min | Tokens / min | Dépense |
|---|---|---|---|
| Nouveau compte | 60 | 200,000 | Jusqu’au premier achat de crédits : jusqu’à 5 clés |
| Crédits prépayés | 3,000 | 5,000,000 | Crédits achetés par la personne pour qui votre agent travaille, de $20 à $2,000 par recharge, $2,000 par 24 h |
| Volume | Sur mesure | Sur mesure | Parlez-nous |
Erreurs
Les erreurs de l’API sont de la forme {"error":{"message","type","code"}}. Les erreurs de la CLI ajoutent un hint et se terminent avec un code non nul.
- 400
- Code: invalid_request
- Que faire: Fix the field named in message. Don't retry unchanged.
- 400
- Code: invalid_body
- Que faire: Fix the field named in message. Don't retry unchanged.
- 400
- Code: invalid_json
- Que faire: Send valid JSON with `content-type: application/json`.
- 401
- Code: invalid_api_key
- Que faire: Key missing, mistyped or revoked. Load ST_API_KEY from .env; don't create a new account.
- 401
- Code: missing_api_key
- Que faire: Send `Authorization: Bearer $ST_API_KEY`.
- 401
- Code: key_expired
- Que faire: The key's expires_at has passed. Use another key, or create a new one with a key that has the keys scope.
- 400
- Code: invalid_expiry
- Que faire: expires_in or expires_at must be in the future and at most 365 days ahead. Send one, not both.
- 400
- Code: expiry_exceeds_parent
- Que faire: A key can't outlive the key that creates it. Ask for at most max_expires_at from the body.
- 403
- Code: scope_not_allowed
- Que faire: Ask only for scopes your own key has (allowed_scopes in the body).
- 400
- Code: budget_exceeds_parent
- Que faire: A sub-agent key's daily budget must fit in what its parent has left today (max_daily_budget_usd in the body).
- 400
- Code: limit_exceeds_parent
- Que faire: A sub-agent key's rate limits and budget can't exceed its parent's (or, when it changes itself, its own).
- 400
- Code: key_depth_exceeded
- Que faire: Sub-agent keys nest at most 16 levels. Create the key from a key higher up.
- 404
- Code: key_not_found
- Que faire: No such key on this account, or (for a sub-agent key) it's outside the keys you created.
- 409
- Code: key_not_active
- Que faire: Only an active key can be rotated. Create a new key instead.
- 402
- Code: budget_exceeded
- Que faire: This key's daily budget is spent. Resets 00:00 UTC. Tell your human; don't retry now.
- 402
- Code: insufficient_credits
- Que faire: The credit balance can't cover the request (the body has balance_usd and required_usd). Run `billing topup --amount-usd 20` and send your human the approval_url.
- 402
- Code: daily_cap_exceeded
- Que faire: An operator-set daily cap on this account is reached. Resets 00:00 UTC. Tell your human.
- 402
- Code: credits_required_for_batches
- Que faire: Batches are paid from prepaid credits. Run `billing topup --amount-usd 20`, then retry once your human approves.
- 402
- Code: credits_required_for_fine_tuning
- Que faire: Fine-tuning is paid from prepaid credits. Run `billing topup --amount-usd 20`, then retry once your human approves.
- 409
- Code: too_many_pending_topups
- Que faire: The account already has 2 unpaid approval links. Ask your human to pay one (`billing status` lists them), or wait for them to expire.
- 409
- Code: daily_topup_limit
- Que faire: Top-ups are limited to $2,000 per account per rolling 24 hours, open links and auto-reloads included. Retry with at most available_usd from the body, or wait.
- 403
- Code: approval_required
- Que faire: Turning auto-reload on or raising it needs your human. Run `billing auto-reload setup --below <usd> --amount <usd>` (a link your human approves; nothing is bought) and give them the approval_url. Disabling or lowering needs no approval.
- 402
- Code: free_tier_key_limit
- Que faire: Accounts that haven't bought credits have 5 active keys. Revoke one (`keys revoke <id>`) or buy credits.
- 402
- Code: free_tier_limit
- Que faire: Accounts that haven't bought credits can't raise budgets or rate limits. Buy credits first (`billing topup --amount-usd 20`).
- 409
- Code: fine_tuning_requires_self_hosted
- Que faire: This base model isn't served on our own GPUs in your region, so it can't be fine-tuned here. Pick another base model.
- 409
- Code: model_not_live
- Que faire: That model isn't served in your region yet. Pick one from `models --live`.
- 400
- Code: invalid_video_url
- Que faire: video_url must be a public https URL or a data:video/mp4 (webm, mov) URL within the size limit.
- 403
- Code: insufficient_scope
- Que faire: This key lacks the scope. Use the default key from init.
- 403
- Code: account_suspended
- Que faire: Stop. Tell your human to email hello@scaledthought.com.
- 404
- Code: model_not_found
- Que faire: Not live here. Pick an id from `models --live` or `GET $ST_BASE_URL/models`.
- 404
- Code: not_found
- Que faire: Wrong path. ST_BASE_URL already ends in /v1; append /chat/completions.
- 421
- Code: wrong_region
- Que faire: The key belongs to the other region. Use the `base_url` in the error body; remove any hard-coded host.
- 429
- Code: rate_limit_exceeded
- Que faire: Wait `Retry-After` seconds, then retry.
- 429
- Code: capacity_exhausted
- Que faire: Canada: every replica of the model is busy and Canadian requests never overflow to another country. Wait `Retry-After` seconds and retry with backoff, or use another model.
- 400
- Code: invalid_webhook_url
- Que faire: Webhook URLs must be public https endpoints on port 443 (no other port, no private, loopback or internal hosts). Fix the URL.
- 409
- Code: too_many_webhooks
- Que faire: An account has at most 5 webhook endpoints. Remove one (`webhooks remove <id>`) first.
- 404
- Code: webhook_not_found
- Que faire: No such webhook on this account. List them with `webhooks list`.
- 503
- Code: webhooks_unavailable
- Que faire: Webhooks aren't enabled in this region yet. Poll `GET /v1/account` for `notices` instead.
- 502
- Code: upstream_error
- Que faire: Transient. Retry with backoff, or use another model from `models --live`.
- 503
- Code: region_not_open
- Que faire: The Canada region isn't open yet. Check with your human that US hosting is acceptable, then use `init --region us` and the US host.
- 503
- Code: service_unavailable
- Que faire: Transient. Retry in a few seconds.
- exit 1
- Code: no_key
- Que faire: No ST_API_KEY in the environment or ./.env. For an existing account run `login`; for a new one, `init --region us`.
- exit 1
- Code: key_exists
- Que faire: login: this folder already has a key. Use it, or pass --force to replace it.
- 428
- Code: authorization_pending
- Que faire: login --wait: your human hasn't typed the code yet. Run it again (codes last 10 minutes).
- 410
- Code: expired_token
- Que faire: The connect code expired. Run `login` again for a new one.
- 409
- Code: already_claimed
- Que faire: A connect code works once. Run `login` again (or ask for a new connect line).
- 403
- Code: access_denied
- Que faire: Your human denied the connection. Ask them before trying again.
- exit 1
- Code: region_mismatch
- Que faire: A key from the other region already exists here. Use it, or ask your human before creating a second account elsewhere.
- exit 1
- Code: wrong_region_endpoint
- Que faire: ST_BASE_URL / ST_API_URL points at the other region. Unset it. Nothing was sent.
- exit 1
- Code: network_error
- Que faire: Couldn't reach the API. Check the network, then retry.
- exit 1
- Code: bad_region
- Que faire: Use `--region us`. Canada (`ca`) is coming soon.
- exit 2
- Code: usage_error
- Que faire: Unknown command, flag or missing argument. Run the command with --help.
| Statut | Code | Que faire |
|---|---|---|
| 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`. |
| 401 | key_expired | The key's expires_at has passed. Use another key, or create a new one with a key that has the keys scope. |
| 400 | invalid_expiry | expires_in or expires_at must be in the future and at most 365 days ahead. Send one, not both. |
| 400 | expiry_exceeds_parent | A key can't outlive the key that creates it. Ask for at most max_expires_at from the body. |
| 403 | scope_not_allowed | Ask only for scopes your own key has (allowed_scopes in the body). |
| 400 | budget_exceeds_parent | A sub-agent key's daily budget must fit in what its parent has left today (max_daily_budget_usd in the body). |
| 400 | limit_exceeds_parent | A sub-agent key's rate limits and budget can't exceed its parent's (or, when it changes itself, its own). |
| 400 | key_depth_exceeded | Sub-agent keys nest at most 16 levels. Create the key from a key higher up. |
| 404 | key_not_found | No such key on this account, or (for a sub-agent key) it's outside the keys you created. |
| 409 | key_not_active | Only an active key can be rotated. Create a new key instead. |
| 402 | budget_exceeded | This key's daily budget is spent. Resets 00:00 UTC. Tell your human; don't retry now. |
| 402 | insufficient_credits | The credit balance can't cover the request (the body has balance_usd and required_usd). Run `billing topup --amount-usd 20` and send your human the approval_url. |
| 402 | daily_cap_exceeded | An operator-set daily cap on this account is reached. Resets 00:00 UTC. Tell your human. |
| 402 | credits_required_for_batches | Batches are paid from prepaid credits. Run `billing topup --amount-usd 20`, then retry once your human approves. |
| 402 | credits_required_for_fine_tuning | Fine-tuning is paid from prepaid credits. Run `billing topup --amount-usd 20`, then retry once your human approves. |
| 409 | too_many_pending_topups | The account already has 2 unpaid approval links. Ask your human to pay one (`billing status` lists them), or wait for them to expire. |
| 409 | daily_topup_limit | Top-ups are limited to $2,000 per account per rolling 24 hours, open links and auto-reloads included. Retry with at most available_usd from the body, or wait. |
| 403 | approval_required | Turning auto-reload on or raising it needs your human. Run `billing auto-reload setup --below <usd> --amount <usd>` (a link your human approves; nothing is bought) and give them the approval_url. Disabling or lowering needs no approval. |
| 402 | free_tier_key_limit | Accounts that haven't bought credits have 5 active keys. Revoke one (`keys revoke <id>`) or buy credits. |
| 402 | free_tier_limit | Accounts that haven't bought credits can't raise budgets or rate limits. Buy credits first (`billing topup --amount-usd 20`). |
| 409 | fine_tuning_requires_self_hosted | This base model isn't served on our own GPUs in your region, so it can't be fine-tuned here. Pick another base model. |
| 409 | model_not_live | That model isn't served in your region yet. Pick one from `models --live`. |
| 400 | invalid_video_url | video_url must be a public https URL or a data:video/mp4 (webm, mov) URL within the size limit. |
| 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`. |
| 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. |
| 429 | capacity_exhausted | Canada: every replica of the model is busy and Canadian requests never overflow to another country. Wait `Retry-After` seconds and retry with backoff, or use another model. |
| 400 | invalid_webhook_url | Webhook URLs must be public https endpoints on port 443 (no other port, no private, loopback or internal hosts). Fix the URL. |
| 409 | too_many_webhooks | An account has at most 5 webhook endpoints. Remove one (`webhooks remove <id>`) first. |
| 404 | webhook_not_found | No such webhook on this account. List them with `webhooks list`. |
| 503 | webhooks_unavailable | Webhooks aren't enabled in this region yet. Poll `GET /v1/account` for `notices` instead. |
| 502 | upstream_error | Transient. Retry with backoff, or use another model from `models --live`. |
| 503 | region_not_open | The Canada region isn't open yet. Check with your human that US hosting is acceptable, then use `init --region us` and the US host. |
| 503 | service_unavailable | Transient. Retry in a few seconds. |
| exit 1 | no_key | No ST_API_KEY in the environment or ./.env. For an existing account run `login`; for a new one, `init --region us`. |
| exit 1 | key_exists | login: this folder already has a key. Use it, or pass --force to replace it. |
| 428 | authorization_pending | login --wait: your human hasn't typed the code yet. Run it again (codes last 10 minutes). |
| 410 | expired_token | The connect code expired. Run `login` again for a new one. |
| 409 | already_claimed | A connect code works once. Run `login` again (or ask for a new connect line). |
| 403 | access_denied | Your human denied the connection. Ask them before trying again. |
| 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`. Canada (`ca`) is coming soon. |
| exit 2 | usage_error | Unknown command, flag or missing argument. Run the command with --help. |