skip to content
superbot.gg

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.

Operation id rotateKey in Keys.

Path parameters

  • id string required

Response 201

The new key, once.

application/json: RotatedKey.

  • key string required

    The new key in plaintext. Shown once.

  • row CallerKey required
    29 fields
    • id string required
    • user_id string required
    • name string required

      What the tool calls itself, 1-64 chars.

    • mask string required

      The only form shown after mint.

    • created_at string (date-time) required
    • last_used_at string (date-time)
    • revoked_at string (date-time)
    • daily_limit_tokens number

      Daily spend cap in whole credits.

    • monthly_limit_tokens number

      Monthly spend cap in whole credits.

    • caps_unit string

      One of credit.

    • allowed_models array of string

      Glob allow-list over model names; absent = every model. With models_listed: the exact canonical ids the key may dial, and empty = none.

    • models_listed boolean

      true = 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_pins object

      Canonical 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_aliases object

      Canonical 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.

    • app string

      Forwarding 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_model string

      The 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. A call that names any other model is dialled as named. Absent = a call naming superbot gets superbot.

    • route string required

      One of byo, credits, auto.

    • mode string required

      One of model, agent.

    • incognito boolean required
    • device_id string
    • org_id string

      Set on a team key.

    • person_id string

      Set 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_name string

      The person's display name, 1-64 characters. Present on every person key.

    • person_email string

      The person's email address, when the owner gave one.

    • person_group string

      A free-text grouping the owner sorts people by (a team, a class), 1-64 characters.

    • prompt_history PromptHistory

      What 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_owner boolean required

        The owner may read this person's prompts.

      • retention_days integer required

        Whole days the prompts are kept, 1-3650.

      • attested_at string (date-time) required

        ISO 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_at string (date-time)

      Set while the owner holds this person: until a PATCH clears it the key answers 403 key_paused at the model gateway, the /v1/keys routes, the relay door and the Cosmos door; every other route does not recognise a held key and answers 401 unauthorized. Held is not revoked. It is written to every live key of the person.

    • person_limit_usd number

      The 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.

    • scopes array of Scope required

      The 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.

  • revoked string | null required

    The id of the key that was revoked, or null if that revoke failed after the mint.

Errors

StatusCodeWhat to change
400invalid_request

A parameter or body field is invalid; param names it and issues lists every problem.

401unauthorized

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.

403insufficient_scope

The key lacks the scope in required_scopes; mint a key that holds it.

404not_found

No such resource on this account; check the id.

409conflict

The resource is not in a state that allows this change.

view .mdopenapi
Request

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())
Response

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"
}