Create a caller key
Part of Keys, 6 operations. The overview covers keys, scopes and errors.
POST /v1/keys
Mint a key. The plaintext is returned once. A caller key can only mint keys within its own reach: no scope, route, cap or model it does not hold. With person the key is minted for someone else and billed to you: the row carries person_id, person_name and the rest, and name defaults to the person's name. A bad person answers 400 invalid_person. Only the account owner (a signed-in session, a device or the account key) mints a key for a person: a caller key that sends person answers 403 caller_key_forbidden, and so does a person key minting any key. A person key minted with no scopes or preset holds gateway:invoke alone. A paused caller key answers 403 key_paused.
A caller key holding keys:write (Authorization: Bearer sbc_… or x-api-key: sbc_…), or a signed-in session.
Request body
namestringWhat the tool calls itself, 1-64 chars. Required unless
personis given, then it defaults to the person's name.personKeyPersonThe person a key is minted for. Without
idit makes a new person (namerequired); withidit adds a key to that person. A person key stamps no device (the minting device's logout never revokes it), takes noorg_idand is billed to the owner.4 fields
namestringThe person's display name, 1-64 printable characters (no
<,>,"or'). Required for a new person; withidit must equal the stored name or be left out.emailstringThe person's email address. With
idit must equal the stored one or be left out.groupstringA free-text grouping, 1-64 characters. With
idit must equal the stored one or be left out.idstringThe
person_idof a person already on this account: adds another key for them, which inherits the stored name, email, group, prompt_history and paused_at (a paused person's new key is born paused). Rotating a key is a mint with the sameid, then a revoke of the old key.
routestringOne of
byo,credits,auto.modestringOne of
model,agent.daily_limit_tokensnumberDaily spend cap in whole credits.
monthly_limit_tokensnumberMonthly spend cap in whole credits.
allowed_modelsarray of stringGlob allow-list over model names; with models_listed, the exact canonical ids (no globs).
models_listedbooleantrue = the listed reading: the key dials exactly its allowed_models, listed as the per-app picker names; empty = none. A PATCH that omits it leaves it as it was.
model_pinsobject | nullCanonical model id to the stable account id it is pinned to (non-empty strings). A PATCH replaces the whole map; null clears it.
model_aliasesobject | nullCanonical model id (a member of allowed_models) to the custom name its picker shows (1-64 characters: letters, numbers, dots, dashes, colons). A PATCH replaces the whole map; null clears it. A refused name stores nothing and answers the reason. Removing a model from allowed_models drops its custom name.
default_modelstring | nullThe model a call that names the bare house agent
superbot(the default model of Zapier and n8n), or names no model, is answered by instead:superbot-fast,superbot-omni, or a model of one of your own accounts (claude-sonnet-5-5,gpt-5.5,custom/<endpoint>/<id>). A call that names any other model is dialled as named.nullorsuperbotclears it. A model of your own account needs a key on routeautoorbyoin modemodelwhoseallowed_modelsadmits it; a key on routecreditstakes a house model only, and a key withmodels_listedtakes none. The write is judged on the key as it will be stored, so a PATCH that would leave the default unusable (route credits, mode agent, a narrower list) answers 400invalid_default_model: senddefault_model: nullwith it. A PATCH that omits it leaves it as it was.incognitobooleanscopesarray of ScopeExplicit scopes; wins over
preset. One ofgateway:invoke,usage:read,billing:read,keys:read,keys:write,endpoints:read,endpoints:write,teams:read,teams:write,devices:read,devices:write,runs:read,runs:write,mcp:invoke,turns:read.appstringForwarding app this listed key's model names are spelled for: cursor, copilot-cli, cline, roo, qwen-code, hermes, openclaw, zazen, default. Set at creation, cannot be changed. Absent = cursor.
presetstringA named scope set. One of
gateway,read_only,full.
Response 201
The new key.
keystring requiredThe plaintext
sbc_…key, shown once.rowCallerKey required29 fields
idstring requireduser_idstring requirednamestring requiredWhat the tool calls itself, 1-64 chars.
maskstring requiredThe only form shown after mint.
created_atstring (date-time) requiredlast_used_atstring (date-time)revoked_atstring (date-time)daily_limit_tokensnumberDaily spend cap in whole credits.
monthly_limit_tokensnumberMonthly spend cap in whole credits.
caps_unitstringOne of
credit.allowed_modelsarray of stringGlob allow-list over model names; absent = every model. With models_listed: the exact canonical ids the key may dial, and empty = none.
models_listedbooleantrue = the listed reading: allowed_models are literal canonical ids (no globs), the key lists exactly those as its per-app picker names, and an empty list allows nothing.
model_pinsobjectCanonical model id to the stable account id it is pinned to: a pinned model dials only that account, and one id pinned to two accounts gets two picker names.
model_aliasesobjectCanonical model id (a member of allowed_models) to the custom name its picker shows: 1-64 characters of letters, numbers, dots, dashes or colons; no Cursor routing word (claude, gemini, anthropic, sonnet-, opus-, haiku-, grok, composer); not a house id (superbot, superbot-fast, superbot-omni); unique among this key's forwards; not another model's id. A refused name stores nothing. A custom name replaces the default name for that model.
appstringForwarding app this listed key's model names are spelled for: cursor, copilot-cli, cline, roo, qwen-code, hermes, openclaw, zazen, default. Set at creation, cannot be changed. Absent = cursor.
default_modelstringThe model a call that names the bare house agent
superbot(the default model of Zapier and n8n), or names no model, is answered by instead:superbot-fast,superbot-omnior a model of one of your own accounts. A call that names any other model is dialled as named. Absent = a call namingsuperbotgetssuperbot.routestring requiredOne of
byo,credits,auto.modestring requiredOne of
model,agent.incognitoboolean requireddevice_idstringorg_idstringSet on a team key.
person_idstringSet on a key minted for a person:
per_+ 16 hex. Every key minted for the same person carries the same id. A person key has no device_id and no org_id, and is billed to the owner.person_namestringThe person's display name, 1-64 characters. Present on every person key.
person_emailstringThe person's email address, when the owner gave one.
person_groupstringA free-text grouping the owner sorts people by (a team, a class), 1-64 characters.
prompt_historyPromptHistoryWhat the owner told a person about their prompts, and how long they are kept. Absent on a key until the owner sets it: the person's prompts are then not visible to the owner and follow the account's own retention.
3 fields
visible_to_ownerboolean requiredThe owner may read this person's prompts.
retention_daysinteger requiredWhole days the prompts are kept, 1-3650.
attested_atstring (date-time) requiredISO 8601 time the owner attested the person was told. The owner's own claim, stored as given and not verified; the answer normalises it to UTC.
paused_atstring (date-time)Set while the owner holds this person: until a PATCH clears it the key answers 403
key_pausedat the model gateway, the/v1/keysroutes, the relay door and the Cosmos door; every other route does not recognise a held key and answers 401unauthorized. Held is not revoked. It is written to every live key of the person.person_limit_usdnumberThe owner's monthly spend limit for this person, in US dollars to the cent. Set by the owner's
PUT /v1/keys/person/{person_id}/limit(the Helper), written to every live key of the person, and absent while no limit is set.scopesarray of Scope requiredThe EFFECTIVE scopes: stored list or the legacy set, team keys capped. One of
gateway:invoke,usage:read,billing:read,keys:read,keys:write,endpoints:read,endpoints:write,teams:read,teams:write,devices:read,devices:write,runs:read,runs:write,mcp:invoke,turns:read.
Errors
| Status | Code | What to change |
|---|---|---|
| 400 | invalid_request | A parameter or body field is invalid; |
| 401 | unauthorized | Send a live caller key or session as |
| 403 | insufficient_scope | The key lacks the scope in |
curl
curl -sS -X POST "https://superbot.gg/v1/keys" \
-H "Authorization: Bearer $SUPERBOT_API_KEY" \
-H "content-type: application/json" \
-d '{"name":"your-name","person":{"name":"your-name","email":"[email protected]","group":"your-group"},"route":"byo"}'JavaScript
const res = await fetch(`https://superbot.gg/v1/keys`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
'content-type': 'application/json',
},
body: JSON.stringify({"name":"your-name","person":{"name":"your-name","email":"[email protected]","group":"your-group"},"route":"byo"}),
});
console.log(res.status, await res.json());Python
import os
import requests
res = requests.request(
"POST",
"https://superbot.gg/v1/keys",
headers={
"Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
"content-type": "application/json",
},
json={"name":"your-name","person":{"name":"your-name","email":"[email protected]","group":"your-group"},"route":"byo"},
)
print(res.status_code, res.json())201 The new key.
{
"key": "your-key",
"row": {
"id": "ck_9f2c41d0",
"user_id": "your-user-id",
"name": "your-name",
"mask": "sbc_ab12…cd34",
"created_at": "2026-09-01T00:00:00Z",
"last_used_at": "2026-09-01T00:00:00Z",
"revoked_at": "2026-09-01T00:00:00Z",
"daily_limit_tokens": 0,
"monthly_limit_tokens": 0,
"caps_unit": "credit",
"allowed_models": [
"your-allowed-models"
],
"models_listed": true,
"model_pins": {},
"model_aliases": {},
"app": "your-app",
"default_model": "your-default-model",
"route": "byo",
"mode": "model",
"incognito": true,
"device_id": "your-device-id",
"org_id": "your-org-id",
"person_id": "per_9f2c41d0a7b35e68",
"person_name": "your-person-name",
"person_email": "[email protected]",
"person_group": "your-person-group",
"prompt_history": {
"visible_to_owner": true,
"retention_days": 0,
"attested_at": "2026-09-01T00:00:00Z"
},
"paused_at": "2026-09-01T00:00:00Z",
"person_limit_usd": 0,
"scopes": [
"gateway:invoke"
]
}
}400 The request is malformed or a parameter is invalid; `param` names the field.
{
"error": "invalid_request",
"message": "A parameter or body field is invalid; param names it and issues lists every problem.",
"doc_url": "https://superbot.gg/developers#errors-invalid_request",
"request_id": "req_5f1c0a9e2b7d4c3a1e0f9b8d"
}401 The bearer is missing, malformed or unknown.
{
"error": "unauthorized",
"message": "Send a live caller key or session as Authorization: Bearer … or x-api-key. No key yet: create one at /account/api, or sign a user in at /auth.md.",
"doc_url": "https://superbot.gg/developers#errors-unauthorized",
"request_id": "req_5f1c0a9e2b7d4c3a1e0f9b8d"
}403 The key lacks a scope (insufficient_scope), is revoked, or may not call this route.
{
"error": "insufficient_scope",
"message": "The key lacks the scope in required_scopes; mint a key that holds it.",
"doc_url": "https://superbot.gg/developers#errors-insufficient_scope",
"request_id": "req_5f1c0a9e2b7d4c3a1e0f9b8d"
}No operation matches this filter.