Rotate a caller key
Part of Keys, 6 operations. The overview covers keys, scopes and errors.
POST /v1/keys/{id}/rotate
Replace a key with a new one of the same shape (name, scopes, route, mode, caps, models, pins, aliases, default model, incognito, the person it is for, the device that minted it) and revoke the old one. The new key is minted first and the old one revoked after, so a failure never leaves the account without a working key. The reply carries the new key in plaintext once (key), its row, and revoked, the id of the key revoked (null if that revoke failed after the mint: the new key is live, so revoke the old one with DELETE /v1/keys/{id}). No body. A key that is revoked already answers 409 revoked; an id this account does not hold answers 404 not_found; a team key answers 400 team_key (rotate it on the team pane). A person key is rotated by the account owner only; a caller key that tries answers 403 caller_key_forbidden. The new key has made no calls yet, so it lists under Zapier or n8n again with its first call.
A caller key holding keys:write (Authorization: Bearer sbc_… or x-api-key: sbc_…), or a signed-in session.
Path parameters
idstring required
Response 201
The new key, once.
keystring requiredThe new key in plaintext. 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.
revokedstring | null requiredThe id of the key that was revoked, or null if that revoke failed after the mint.
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 |
| 404 | not_found | No such resource on this account; check the id. |
| 409 | conflict | The resource is not in a state that allows this change. |
curl
curl -sS -X POST "https://superbot.gg/v1/keys/$ID/rotate" \
-H "Authorization: Bearer $SUPERBOT_API_KEY"JavaScript
const id = 'ID';
const res = await fetch(`https://superbot.gg/v1/keys/${id}/rotate`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`,
},
});
console.log(res.status, await res.json());Python
import os
import requests
id = "ID"
res = requests.request(
"POST",
f"https://superbot.gg/v1/keys/{id}/rotate",
headers={
"Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}",
},
)
print(res.status_code, res.json())201 The new key, once.
{
"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"
]
},
"revoked": "your-revoked"
}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"
}404 No such resource on this account.
{
"error": "not_found",
"message": "No such resource on this account; check the id.",
"doc_url": "https://superbot.gg/developers#errors-not_found",
"request_id": "req_5f1c0a9e2b7d4c3a1e0f9b8d"
}409 The resource is not in a state that allows this change.
{
"error": "conflict",
"message": "The resource is not in a state that allows this change.",
"doc_url": "https://superbot.gg/developers#errors-conflict",
"request_id": "req_5f1c0a9e2b7d4c3a1e0f9b8d"
}No operation matches this filter.