# Superbot API: full reference > Every operation of the Superbot API as markdown, generated from https://superbot.gg/docs/openapi.json (version 2026-09-23). Base URL: `https://api.superbot.gg/v1` for OpenAI- and Anthropic-compatible clients alike; set OPENAI_BASE_URL and ANTHROPIC_BASE_URL to it. The dialect is read from each request, and answers come back in the dialect you dialed. Set `model: "superbot"` to run your agent; `superbot-omni`: Superbot agent, run on your computer. A request that declares its own tools, the way Codex, Claude Code and Cursor do, is answered by the superbot model driving those tools: its tool calls come back in your dialect for your client to run. So is a call that caps its reply at 512 tokens or fewer, and a call that asks for structured output (a JSON object or a JSON schema), whose reply is the model’s output alone. Any other request is answered by your agent, and outside superbot’s own apps a card it draws comes back as plain markdown: a choice as a list, sources as a Sources: list. Send `x-superbot-mode: agent` to have your agent answer whatever the request carries; its cards then arrive as cards, not converted to plain markdown. Auth: a caller key (`sbc_…`) goes in `Authorization: Bearer sbc_…` or `x-api-key: sbc_…`. Each key holds scopes; an operation lists the scopes it needs, and a key without one answers 403 `insufficient_scope`. Account routes also take a signed-in session. Headers: x-superbot-route (byo, credits or auto), x-superbot-mode (model or agent), x-superbot-engine (omni, the only engine a caller key may pin), x-superbot-session (names the conversation; 1-59 word chars). Conversations: When your agent answers a call, superbot keeps its memory of the chat on the server, one thread per conversation. A call answered by the model alone, such as one that declares its own tools, keeps no such thread: the messages your client sends are the conversation. Name a conversation with the `x-superbot-session: ` header: letters, digits, `_` and `-`, at most 59 characters. Every call that sends the same id continues the same thread, even when your client does not resend the earlier messages. With no header, superbot reads the conversation id your client already sends: `prompt_cache_key`, `metadata.session_id`, `metadata.conversation_id`, a Responses `conversation` or an Anthropic `metadata.user_id`. Codex and Claude Code send these themselves, so the agent keeps each of their chats apart. With none of them, superbot keys the conversation on its first message, the first one the user wrote and not the reminder blocks a client wraps around it, so two chats that open with the same words share a thread. Name a session when that matters. The OpenAI `user` field is not a conversation id, and neither is a Responses `previous_response_id`. A call that sends `x-superbot-mode: agent` is treated as one of superbot’s own apps: it reads only the header, and without one it shares a single thread per key. Errors: every account-route refusal is `{"error", "message", "doc_url", "request_id"}` plus `param` when one field is at fault. Gateway refusals come in your dialect. Status: 400 invalid request; 401 unknown key; 402 budget or credits spent (`byo_url` on the body; a credit refusal’s `error.message` names the billing page to add credits); 403 revoked key, insufficient_scope, model_not_allowed, no_vendor_credential, no_custom_upstream; 404 unknown resource; 409 conflicting state; 429 per-key bucket; 499 caller gone; 5xx the upstream’s own status, passed through in your dialect. When that status is your OWN vendor credential’s answer (a BYO or custom-endpoint dial), the response also carries `x-superbot-error-origin: vendor` and `error.origin: "vendor"` with `error.vendor_status` (the vendor’s status); a refusal without them is the gateway’s own. Every gateway error object also carries `error.source`, where the problem is: `request` (your request or conversation, e.g. too long for the model: shorten or compact it), `client` (your client’s key or setup), `account` (credits, plan or limits), `superbot` or `model_server` (ours: retry), `provider` (an account you connected). Match on `code`, `type` and `source`, not on `message`. Lists: `limit` (1-100, default 20) with `after_id` or `before_id`; the page is `{"object": "list", "data", "has_more", "first_id", "last_id"}`, and `Link: rel="next"` names the next page. ## Tools One MCP tool, `superbot`, at `https://superbot.gg/mcp`. It is the only tool you call, and it does every job below. ### Connect Point an MCP client at `https://superbot.gg/mcp` (Streamable HTTP); [clients](https://superbot.gg/clients.md) has the setup for each client. Sign in with OAuth, or send an `sbk_…` account token as `Authorization: Bearer`. With no account yet, [auth.md](https://superbot.gg/auth.md) signs a user in with one emailed code and hands you that token. The token works on `/mcp` and `/answer`, not on the `/v1` model routes, which take an `sbc_…` caller key; the same guide shows the one request that mints it. To try superbot before you connect anything, open [https://superbot.gg/chat](https://superbot.gg/chat) in a browser: no account needed. `npx skills add https://superbot.gg` adds the superbot skill with the skills CLI, and when your user says `use superbot`, call this tool with the rest of what they asked. ### Call it - `{"intent": ""}`: superbot picks the adapter, or answers directly. `intent` alone is enough. - `{"adapter": "", "args": {…}}`: run one adapter from the table below. The fields go inside `args`; a `*` marks a required one. - `{"slug": ""}` reads one adapter's full input schema and runs nothing. `{"use_case": ""}` searches the catalog. - A reply with status=processing carries a `request_id`. Call again with that `request_id` to get the finished answer. - `GET https://superbot.gg/answer?intent=` runs the same request with the same Bearer, with no MCP client. ### Capability groups | Group | Adapters, with their main `args` | | --- | --- | | Web search and news | `web-search` (`query*`, `limit`); `scraper-search` (`query*`, `limit`); `news-headlines` (`query`, `limit`, `lang`) | | Read pages and sites | `read-url` (`url*`, `max_chars`); `scraper-fetch` (`url*`, `as`, `links`); `scraper-scrape` (`url*`, `links`, `screenshot`, `depth`, `pages`); `scraper-map` (`url*`, `search`, `limit`); `scraper-crawl` (`url*`, `limit`, `max_depth`, `prefix`); `scraper-archive` (`url*`, `timestamp`); `scraper-cdx` (`url*`, `match_type`, `from`, `to`, `limit`); `scraper-catalog` (`host`, `url`, `path`); `scraper-catalog-call` (`host`, `path`, `method`, `query`, `body`); `scraper-catalog-discover` (`host`, `depth`, `limit`) | | Research | `scraper-papers` (`query`, `source`, `sort`, `limit`); `scraper-repos` (`query*`, `limit`); `scientist` (`question*`, `context`, `deep`) | | Quick facts | `fx-convert` (`from*`, `to*`, `amount`); `market-price` (`symbol*`, `currency`, `kind`): keyless crypto and one-line equity price path; `market-quote` (`symbol*`): cache-backed equity quote with vendor provenance; `market-bars` (`symbol*`, `interval*`, `range`, `limit`); `market-options` (`symbol*`, `expiry`, `right`, `strike_min`, `strike_max`); `market-macro` (`series_id*`, `start`, `end`, `as_of`, `limit`); `market-fundamentals` (`symbol*`, `tag*`, `form`, `period`, `limit`); `weather` (`place*`, `days`, `units`); `world-time` (`place*`, `time`, `to`); `clock`; `calc` (`expression`, `value`, `from`, `to`); `define-word` (`word*`); `wiki-summary` (`topic*`, `lang`) | | Browser sessions | `scraper-browser-open`; `scraper-browser-navigate` (`session_id*`, `url*`); `scraper-browser-snapshot` (`session_id*`, `filter`); `scraper-browser-click` (`session_id*`, `ref`, `at`); `scraper-browser-type` (`session_id*`, `ref`, `text*`, `submit`): no ref types into the focused element (click at a point first on a canvas editor); `scraper-browser-press` (`session_id*`, `key*`): a key or chord on the focused element: Enter, Tab, Escape, Control+End, Meta+ArrowDown; `scraper-browser-fill-form` (`session_id*`, `fields*`); `scraper-browser-evaluate` (`session_id*`, `js*`); `scraper-browser-screenshot` (`session_id*`); `scraper-browser-wait-for` (`session_id*`, `text`, `selector`, `timeout_ms`); `scraper-browser-close` (`session_id*`); `scraper-browser-close-all` | | Images | `image-gen` (`prompt*`, `size`, `aspect_ratio`, `quality`); `image-search` (`queries*`, `count`, `orientation`, `min_width`) | | Video, audio and 3D | `video-gen` (`prompt*`, `seconds`, `size`, `model`, `image`); `audio-gen` (`prompt*`, `mode*`, `voice`, `seconds`); `model3d-gen` (`prompt*`, `format`, `formats`, `image`) | | Documents | `docs-generate` (`spec*`); `docs-extract` (`artifact_id*`); `docs-convert` (`artifact_id*`, `to`); `file-convert` (`artifact_id`, `to`, `from`, `list`); `docs-pdf-to-spec` (`artifact_id*`, `pages`); `docs-edit` (`op*`, `artifact_id`, `artifact_ids`, `params`) | | Automations | `routine-create` (`prompt*`, `cron_expr`, `tz`, `label`); `routine-list` (`all`); `routine-control` (`op*`, `hint`, `cron_expr`) | | Find tools | `capability-acquire` (`need*`, `context`, `target`); `mcp-search` (`query*`, `limit`) | | Design references | `design-guide` (`surface*`, `topic`, `genre`); `reference-search` (`queries*`, `kind`, `per_query`); `component-registry` (`op`, `registry`, `query`, `name`); `icon-search` (`op*`, `query`, `prefix`, `icon`, `icons`) | | Phone calls, texts and faxes | `phone-status` (`call_id`); `phone-call` (`request`, `to`, `objective`, `questions`, `max_minutes`); `phone-poll` (`call_id*`); `sms-send` (`to*`, `body*`); `fax-send` (`to*`, `media_url*`, `kind`, `consent_basis`) | | Chat apps | `slack-post` (`channel*`, `text*`); `slack-dm` (`user*`, `text*`); `discord-post` (`channel*`, `text*`, `server`) | | Work apps | `notion-pages` (`op`, `query`, `page_id`, `data_source_id`, `properties`, `limit`); `github-me` (`op`, `limit`); `trello-attach` (`card*`, `artifact_id`, `url`, `name`, `set_cover`); `jira-attach` (`issue*`, `artifact_id`, `url`, `name`); `confluence-attach` (`page*`, `artifact_id`, `url`, `comment`, `replace`) | | Zapier and n8n | `account` (`op`): op keys lists the caller keys a Zap or an n8n node dials with | Each integration has its own page and its live status: [integrations](https://superbot.gg/integrations.md) ([Slack](https://superbot.gg/integrations/slack.md), [Discord](https://superbot.gg/integrations/discord.md), [Trello](https://superbot.gg/integrations/trello.md), [Confluence](https://superbot.gg/integrations/confluence.md), [Jira](https://superbot.gg/integrations/jira.md), [GitHub](https://superbot.gg/integrations/github.md), [Zapier](https://superbot.gg/integrations/zapier.md), [n8n](https://superbot.gg/integrations/n8n.md)). ### Refusals | Code | When | What to do | | --- | --- | --- | | `page_refused` | The site answered a read with 401, 402, 403 or 451: a sign-in wall, a paywall, a bot or region wall, or a legal block. | The site chose this. Read the same facts from another source, or open the page in a browser session. | | `page_not_found` | The site answered 404 or 410. | Check the URL, find the page with a search, or ask for an archived copy. | | `page_rate_limited` | The site answered 429 to a read. `retry_after` carries the site's own wait when it sent one. | Read the same facts from another source, or read the page again later. | | `no_credits` | The account behind a media lane (image, video, audio, 3D) is out of credits or over its key limit. | superbot walks on to the next lane. When none is left the answer names the step: add credits to that account. | | `rate_limited` | A media lane answered 429. | superbot waits out `Retry-After` and retries that lane once, then walks on. Ask again a little later if every lane was busy. | ## Gateway OpenAI- and Anthropic-shaped model calls, answered in the dialect you dialed. ### Read a turn `GET /v1/turns/{session}` Where a turn of one of your conversations stands: `running` with the text so far, `done` with the reply (and `assets`, the files it made, for a caller key that draws no cards), `error`, `cancelled`. `?request=` names one turn (the `request_id` of an async call’s 202, from either form: `x-superbot-callback-url` or `Prefer: respond-async`); without it the conversation’s newest turn. A turn the gateway admitted reads `running` (empty `text`) from the moment of its 202, before the agent has produced a frame, so a poll that starts at once never sees a gap; one an earlier process lost after admitting it reads `error` with reason `interrupted`. Turns are stored for 24 hours. Needs the `turns:read` scope; the read bills nothing. A missing or unknown bearer is `401`, a key without the scope `403 insufficient_scope`, a request id this account never admitted `404 no_turn` and a deleted conversation `410 chat_deleted`. - Operation id: `getTurn` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: A caller key holding `turns:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `turns:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `session` | string | required | The conversation id (what `x-superbot-session` named, or the `session` of an async call’s 202). | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `request` | string | optional | A turn’s request id. | #### Response 200 The turn. `application/json`: TurnRecord. - `state` (string, required): Where the turn stands. One of `running`, `done`, `error`, `cancelled`, `parked`. - `request_id` (string, required) - `text` (string): The reply so far (`running`) or the whole reply (`done`). - `assets` (array of TurnAsset): Only on a `done` turn, only when it made files, and only when the read is by a caller key that draws no cards (an automation step, a script): the files the reply names, one entry per file, in order. `text` is unchanged beside it. - `name` (string, required): A file name with its extension where one is known, ready to hand to a Gmail attachment or a Drive upload. - `mime` (string, required): The file’s media type. - `size` (integer, required): The size in bytes. - `url` (string, required): Where to fetch the bytes. A generated picture, sound or clip is at `/gen/`; an artifact is published at an unguessable, immutable public link (`/shared/` or `/gen/`) for a `zapier/` or `n8n/` caller, and answered by its signed artifact link (valid 24 hours) for any other. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/turns/$SESSION" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const session = 'SESSION'; const res = await fetch(`https://superbot.gg/v1/turns/${session}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests session = "SESSION" res = requests.request( "GET", f"https://superbot.gg/v1/turns/{session}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Re-attach to a turn’s stream `GET /v1/turns/{session}/stream` Server-sent events: every journaled frame of the turn after `after` (or `Last-Event-ID`), then the live frames until its `answer` or `error`. A cursor past the journal gets one `resync` with the text so far. Needs the `turns:read` scope. - Operation id: `streamTurn` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: A caller key holding `turns:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `turns:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `session` | string | required | The conversation id (what `x-superbot-session` named, or the `session` of an async call’s 202). | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `request` | string | required | The turn’s request id (required). | | `after` | string | optional | The last frame id already seen. | #### Response 200 The turn’s frames as server-sent events. `text/event-stream`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/turns/$SESSION/stream?request=string" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const session = 'SESSION'; const res = await fetch(`https://superbot.gg/v1/turns/${session}/stream?request=string`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests session = "SESSION" res = requests.request( "GET", f"https://superbot.gg/v1/turns/{session}/stream?request=string", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Create a chat completion `POST /v1/chat/completions` OpenAI Chat Completions: passed through to your own vendor key, transcoded, or answered by your agent (`model: "superbot"`). A request that declares its own tools, the way Codex, Claude Code and Cursor do, is answered by the superbot model driving those tools: its tool calls come back in your dialect for your client to run. So is a call that caps its reply at 512 tokens or fewer, and a call that asks for structured output (a JSON object or a JSON schema), whose reply is the model’s output alone. Any other request is answered by your agent, and outside superbot’s own apps a card it draws comes back as plain markdown: a choice as a list, sources as a Sources: list. When the agent answers with files (a generated picture, sound or clip, a document), the reply carries them beside the text as a top-level `superbot_assets` array of `{name, mime, size, url}` (a streamed reply sends it on its last chunk before `[DONE]`), only for a caller that draws no cards and only when there are files; the text is unchanged. The `url` is a durable public link for a `zapier/` or `n8n/` client (`x-superbot-client`) and the artifact’s signed link (valid 24 hours) for any other caller. When your agent answers, its server-side memory is kept per conversation: name one with the `x-superbot-session` header, or superbot reads the id your client sends (`prompt_cache_key`, `metadata.session_id`, `metadata.conversation_id`, a Responses `conversation` or an Anthropic `metadata.user_id`), else it keys the conversation on its first message. - Operation id: `createChatCompletion` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: A caller key holding `gateway:invoke` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: `gateway:invoke` - Body reference: [OpenAI Chat Completions reference](https://platform.openai.com/docs/api-reference/chat/create) #### Header parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `x-superbot-route` | string | optional | Override the key’s route for this request. One of `byo`, `credits`, `auto`. | | `x-superbot-mode` | string | optional | Override the key’s mode for this request. One of `model`, `agent`. | | `x-superbot-engine` | string | optional | Run the agent lane on your computer (omni). One of `omni`. | | `x-superbot-session` | string | optional | Names the server-side conversation your agent continues: letters, digits, `_` and `-`, at most 59 characters. | | `x-superbot-callback-url` | string | optional | An https URL (a Zapier catch hook, an n8n webhook node). The call is accepted at once with `202 {session, request_id}`, the turn runs, and when it settles Superbot POSTs `{session, request_id, status, text}` to this URL (`status` is `done` or `error`; an error also carries `error: {code, message}`; a turn that made files also carries `assets`, the same list as the reply’s `superbot_assets`). The URL is a secret: it is stored sealed, never logged, and forgotten once delivered. A 2xx from your URL ends the delivery; a network error, 408, 429 or 5xx is retried (1 s, 5 s, 30 s, 2 min, 10 min). Each delivery carries `x-superbot-event: turn.settled` and a stable `x-superbot-delivery` id. Every refusal a plain call gets (401, 402, 403, 429, a bad body) is still answered synchronously and starts no turn. The reply is the non-streamed one whatever `stream` says. Name the thread with `x-superbot-session` to continue it; a key holding `turns:read` reads the same turn back at `GET /v1/turns/{session}?request={request_id}`. | | `Prefer` | string | optional | `respond-async` (RFC 7240) starts the turn and answers `202 {session, request_id}` with `Preference-Applied: respond-async` as soon as it is accepted; nothing is delivered, so read the result by polling `GET /v1/turns/{session}?request={request_id}` (or re-attach at `/stream`) with `turns:read`. The turn runs on whether or not you stay connected. It applies to the agent (the default for `model: superbot`); on a call that dials a model directly the preference is ignored, the call is answered as usual and the response carries no `Preference-Applied`. With `x-superbot-callback-url` too, the callback form is used. Every refusal a plain call gets is still answered synchronously and starts no turn. The reply is the non-streamed one whatever `stream` says. | #### Request body `application/json`, required. An OpenAI Chat Completions request body. - `model` (string, required) #### Response 200 The answer in the dialect you dialed; streamed as server-sent events when the body asks for `stream: true`. `application/json`: object. `text/event-stream`: string. #### Response 202 Only with `x-superbot-callback-url` or `Prefer: respond-async`: the call was accepted and the turn is running. With the callback header the result is POSTed to that URL when it settles; with `Prefer: respond-async` alone nothing is delivered and the caller polls. `session` and `request_id` read it back with `turns:read`. `Preference-Applied: respond-async` names the preference whenever the call asked for it. `application/json`: TurnCallbackAccepted. - `session` (string, required): The conversation the turn runs in: what `x-superbot-session` named, else the id the gateway derived. - `request_id` (string, required): The turn’s id (also the response’s `x-request-id`): the `request` of `GET /v1/turns/{session}`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The body is not JSON or the dialect refused it. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | Missing, malformed or unknown key. A 401 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 402 | `byo_url` | The key’s budget or your credits are spent (`byo_url` on the body). | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope), `model_not_allowed`, `no_vendor_credential`, `no_custom_upstream` | Revoked · insufficient_scope · model_not_allowed · no_vendor_credential · no_custom_upstream. A 403 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket. A 429 that carries `x-superbot-error-origin: vendor` is your vendor’s rate limit, not the gateway’s. | | 499 | — | The caller hung up; the agent turn keeps running. | | 5XX | — | The upstream’s own status, rendered in your dialect. When a status is your own vendor credential’s answer (a BYO or custom-endpoint dial) the response carries `x-superbot-error-origin: vendor` and `error.origin: "vendor"` with `error.vendor_status`; a refusal without them is the gateway’s own. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/chat/completions" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"model":"superbot"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/chat/completions`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"model":"superbot"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"model":"superbot"}, ) print(res.status_code, res.json()) ``` ### Create a response `POST /v1/responses` OpenAI Responses: `model: "superbot"` (or `superbot-omni`) runs your agent; a linked Codex login passes through. A request that declares its own tools, the way Codex, Claude Code and Cursor do, is answered by the superbot model driving those tools: its tool calls come back in your dialect for your client to run. So is a call that caps its reply at 512 tokens or fewer, and a call that asks for structured output (a JSON object or a JSON schema), whose reply is the model’s output alone. Any other request is answered by your agent, and outside superbot’s own apps a card it draws comes back as plain markdown: a choice as a list, sources as a Sources: list. When your agent answers, its server-side memory is kept per conversation: name one with the `x-superbot-session` header, or superbot reads the id your client sends (`prompt_cache_key`, `metadata.session_id`, `metadata.conversation_id`, a Responses `conversation` or an Anthropic `metadata.user_id`), else it keys the conversation on its first message. - Operation id: `createResponse` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: A caller key holding `gateway:invoke` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: `gateway:invoke` - Body reference: [OpenAI Responses reference](https://platform.openai.com/docs/api-reference/responses/create) #### Header parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `x-superbot-route` | string | optional | Override the key’s route for this request. One of `byo`, `credits`, `auto`. | | `x-superbot-mode` | string | optional | Override the key’s mode for this request. One of `model`, `agent`. | | `x-superbot-engine` | string | optional | Run the agent lane on your computer (omni). One of `omni`. | | `x-superbot-session` | string | optional | Names the server-side conversation your agent continues: letters, digits, `_` and `-`, at most 59 characters. | #### Request body `application/json`, required. An OpenAI Responses request body. - `model` (string, required) #### Response 200 The answer in the dialect you dialed; streamed as server-sent events when the body asks for `stream: true`. `application/json`: object. `text/event-stream`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The body is not JSON or the dialect refused it. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | Missing, malformed or unknown key. A 401 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 402 | `byo_url` | The key’s budget or your credits are spent (`byo_url` on the body). | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope), `model_not_allowed`, `no_vendor_credential`, `no_custom_upstream` | Revoked · insufficient_scope · model_not_allowed · no_vendor_credential · no_custom_upstream. A 403 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket. A 429 that carries `x-superbot-error-origin: vendor` is your vendor’s rate limit, not the gateway’s. | | 499 | — | The caller hung up; the agent turn keeps running. | | 5XX | — | The upstream’s own status, rendered in your dialect. When a status is your own vendor credential’s answer (a BYO or custom-endpoint dial) the response carries `x-superbot-error-origin: vendor` and `error.origin: "vendor"` with `error.vendor_status`; a refusal without them is the gateway’s own. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/responses" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"model":"superbot"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/responses`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"model":"superbot"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/responses", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"model":"superbot"}, ) print(res.status_code, res.json()) ``` ### Create a message `POST /v1/messages` Anthropic Messages, transcoded to the upstream the key routes to, or answered by your agent (`model: "superbot"`). A request that declares its own tools, the way Codex, Claude Code and Cursor do, is answered by the superbot model driving those tools: its tool calls come back in your dialect for your client to run. So is a call that caps its reply at 512 tokens or fewer, and a call that asks for structured output (a JSON object or a JSON schema), whose reply is the model’s output alone. Any other request is answered by your agent, and outside superbot’s own apps a card it draws comes back as plain markdown: a choice as a list, sources as a Sources: list. When your agent answers, its server-side memory is kept per conversation: name one with the `x-superbot-session` header, or superbot reads the id your client sends (`prompt_cache_key`, `metadata.session_id`, `metadata.conversation_id`, a Responses `conversation` or an Anthropic `metadata.user_id`), else it keys the conversation on its first message. - Operation id: `createMessage` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: A caller key holding `gateway:invoke` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: `gateway:invoke` - Body reference: [Anthropic Messages reference](https://docs.anthropic.com/en/api/messages) #### Header parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `x-superbot-route` | string | optional | Override the key’s route for this request. One of `byo`, `credits`, `auto`. | | `x-superbot-mode` | string | optional | Override the key’s mode for this request. One of `model`, `agent`. | | `x-superbot-engine` | string | optional | Run the agent lane on your computer (omni). One of `omni`. | | `x-superbot-session` | string | optional | Names the server-side conversation your agent continues: letters, digits, `_` and `-`, at most 59 characters. | #### Request body `application/json`, required. An Anthropic Messages request body. - `model` (string, required) #### Response 200 The answer in the dialect you dialed; streamed as server-sent events when the body asks for `stream: true`. `application/json`: object. `text/event-stream`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The body is not JSON or the dialect refused it. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | Missing, malformed or unknown key. A 401 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 402 | `byo_url` | The key’s budget or your credits are spent (`byo_url` on the body). | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope), `model_not_allowed`, `no_vendor_credential`, `no_custom_upstream` | Revoked · insufficient_scope · model_not_allowed · no_vendor_credential · no_custom_upstream. A 403 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket. A 429 that carries `x-superbot-error-origin: vendor` is your vendor’s rate limit, not the gateway’s. | | 499 | — | The caller hung up; the agent turn keeps running. | | 5XX | — | The upstream’s own status, rendered in your dialect. When a status is your own vendor credential’s answer (a BYO or custom-endpoint dial) the response carries `x-superbot-error-origin: vendor` and `error.origin: "vendor"` with `error.vendor_status`; a refusal without them is the gateway’s own. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/messages" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"model":"superbot"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/messages`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"model":"superbot"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/messages", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"model":"superbot"}, ) print(res.status_code, res.json()) ``` ### Estimate input tokens `POST /v1/messages/count_tokens` A local estimate (characters / 4). No upstream call and no charge. - Operation id: `countMessageTokens` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: none - Body reference: [Anthropic count tokens reference](https://docs.anthropic.com/en/api/messages-count-tokens) #### Request body `application/json`, required. An Anthropic Messages body; only `messages` is read. - `model` (string, required) #### Response 200 The estimate. `application/json`: TokenCount. - `input_tokens` (integer, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The body is not JSON. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | Missing, malformed or unknown key. A 401 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key is revoked. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/messages/count_tokens" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"model":"superbot"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/messages/count_tokens`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"model":"superbot"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/messages/count_tokens", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"model":"superbot"}, ) print(res.status_code, res.json()) ``` ### List models `GET /v1/models` The agent models first (`superbot`, `superbot-omni`, `superbot-fast`), then your linked vendors’ models, your custom endpoints’ ids as `custom//`, then the credits catalog. - Operation id: `listModels` - Group: [Gateway](https://superbot.gg/developers/gateway.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: none #### Response 200 Every model this key can name. `application/json`: ModelList. - `object` (string, required): One of `list`. - `data` (array of Model, required) - `id` (string, required) - `object` (string, required): One of `model`. - `created` (integer, required) - `owned_by` (string, required) - `lane` (string) - `tier` (string) - `available` (boolean) - `reason` (string) - `min_plan` (string) - `auto` (boolean) - `context_window` (integer) - `context_length` (integer) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | Missing, malformed or unknown key. A 401 that carries `x-superbot-error-origin: vendor` is your vendor credential’s refusal, not the gateway’s. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key is revoked. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/models" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/models`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/models", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ## Usage & spend What your keys and account spent: per request, per day, bucketed and across apps. ### Get usage over a window `GET /v1/usage` With a caller key (or `key=` from a session): that key’s burn over `window`, OpenRouter generation shape. From a session without `key`: paid-versus-list spend over `period`. - Operation id: `getUsage` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `window` | string | optional | Key usage window; default day. One of `day`, `week`, `month`. | | `key` | string | optional | Key id to read (sessions only; a caller key reads itself). | | `period` | string | optional | Account spend period (session without `key`); default week. One of `week`, `month`, `all`. | #### Response 200 The key aggregate, or the account period projection. `application/json`: UsageAggregate | UsagePeriod. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### List usage per request `GET /v1/usage/requests` One generation per request, newest first. - Operation id: `listUsageRequests` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `key` | string | optional | Key id to read (sessions only). | | `limit` | integer | optional | Rows to return, 1-100; default 20. | #### Response 200 The generations. `application/json`: UsageGenerationList. - `object` (string, required): One of `list`. - `data` (array of UsageGeneration, required) - `request_id` (string) - `native_tokens_prompt` (number, required) - `native_tokens_completion` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `total_cost` (number, required): USD at vendor list price. - `cache_discount` (number, required) - `is_byok` (boolean, required) - `model` (string) - `key_label` (string) - `session_id` (string) - `latency_ms` (number) - `ttft_ms` (number) - `status` (integer, required) - `ts` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage/requests" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage/requests`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage/requests", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get usage per UTC day `GET /v1/usage/daily` The account’s usage per UTC day across every key, with totals. A person key (one minted for a person) reads its own person’s usage here, never the account’s. - Operation id: `getUsageDaily` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `from` | string (date) | optional | YYYY-MM-DD; default 30 days before `to`. | | `to` | string (date) | optional | YYYY-MM-DD; default today (UTC). | #### Response 200 One row per day. `application/json`: UsageDaily. - `from` (string, required) - `to` (string, required) - `days` (array of UsageDay, required) - `day` (string, required) - `tokens` (number, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `turns` (integer, required) - `cost_usd` (number, required) - `charged_usd` (number, required) - `totals` (object, required) - `tokens` (number, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `turns` (integer, required) - `cost_usd` (number, required) - `charged_usd` (number, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage/daily" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage/daily`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage/daily", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get usage bucketed and grouped `GET /v1/usage/breakdown` Usage bucketed by hour or day, grouped by key, lane, role, session or model, narrowed by any filter. A person key reads its own person’s usage here, never the account’s. - Operation id: `getUsageBreakdown` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `from` | string (date) | optional | YYYY-MM-DD; default 30 days before `to`. | | `to` | string (date) | optional | YYYY-MM-DD; default today (UTC). | | `tz` | string | optional | IANA zone the days and buckets are read in; default UTC. | | `bucket` | string | optional | Bucket width; default day. One of `day`, `hour`. | | `group` | string | optional | Split dimension; default none. One of `none`, `key`, `lane`, `role`, `session`, `model`. | | `key` | string | optional | Only rows from this key id. | | `lane` | string | optional | Only rows on this lane. | | `role` | string | optional | Only rows with this agent role. | | `session` | string | optional | Only rows in this session. | #### Response 200 Buckets, groups and totals. `application/json`: UsageBreakdown. - `from` (string, required) - `to` (string, required) - `tz` (string, required) - `bucket` (string, required): One of `day`, `hour`. - `group` (string, required) - `totals` (UsageMetrics, required) - `requests` (integer, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `tokens` (number, required): Billed credits. - `usd` (number, required) - `list_usd` (number, required) - `groups` (array of UsageMetrics & object, required) - `requests` (integer, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `tokens` (number, required): Billed credits. - `usd` (number, required) - `list_usd` (number, required) - `id` (string, required) - `label` (string, required) - `buckets` (array of UsageMetrics & object, required) - `requests` (integer, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `tokens` (number, required): Billed credits. - `usd` (number, required) - `list_usd` (number, required) - `key` (string, required) - `start` (string, required) - `by` (object, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage/breakdown" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage/breakdown`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage/breakdown", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Export usage rows `GET /v1/usage/export` The usage rows as a CSV (default), JSON or newline-delimited JSON attachment. - Operation id: `exportUsage` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `from` | string (date) | optional | YYYY-MM-DD; default 30 days before `to`. | | `to` | string (date) | optional | YYYY-MM-DD; default today (UTC). | | `format` | string | optional | Attachment format; default csv. One of `csv`, `json`, `ndjson`. | | `tz` | string | optional | IANA zone the days and buckets are read in; default UTC. | | `key` | string | optional | Only rows from this key id. | | `lane` | string | optional | Only rows on this lane. | | `role` | string | optional | Only rows with this agent role. | | `session` | string | optional | Only rows in this session. | #### Response 200 The rows, as an attachment. `text/csv`: string. `application/json`: array of object. `application/x-ndjson`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage/export" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage/export`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage/export", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get the credit balance `GET /v1/credits` The credit balance, the period meter and the plan. - Operation id: `getCredits` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `billing:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `billing:read` #### Response 200 The balance. `application/json`: Credits. - `credits` (object, required): The pot view: beta, plan and permanent credits with a total. - `balance_credits` (number, required) - `balance_tokens` (number, required) - `total_usage_tokens` (number, required) - `period_usage_tokens` (number, required) - `capacity_tokens` (number, required) - `keys_count` (integer, required) - `paid_usd_week` (number, required) - `list_usd_week` (number, required) - `saved_usd_week` (number, required) - `plan` (string, required) - `renews_at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/credits" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/credits`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/credits", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get AI spend across apps `GET /v1/spend` AI spend across every app on the account over a window, by provider and day. - Operation id: `getSpend` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `range` | string | optional | Window; default 30d. One of `30d`, `90d`, `month`, `custom`. | | `from` | string (date) | optional | YYYY-MM-DD, with range=custom. | | `to` | string (date) | optional | YYYY-MM-DD, with range=custom. | #### Response 200 The spend report. `application/json`: Spend. - `from` (string, required) - `to` (string, required) - `currency` (string, required): One of `USD`. - `total_usd` (number, required) - `tied_usd` (number, required) - `estimated_usd` (number, required) - `unpriced_models` (array of string, required) - `providers` (array of object, required) - `provider` (string, required) - `label` (string, required) - `total_usd` (number, required) - `usage_usd` (number, required) - `purchase_usd` (number, required) - `measured_usd` (number, required) - `estimated_usd` (number, required) - `plan_usd` (number, required) - `residual_usd` (number | null, required) - `status` (string, required): One of `caught_up`, `residual`, `estimate_only`. - `services` (array of object, required) - `service` (string, required) - `total_usd` (number, required) - `unpriced_usage` (array of object, required) - `service` (string, required) - `sku` (string, required) - `quantity` (number, required) - `unit` (string, required): One of `tokens`, `requests`, `acu`, `seat-month`. - `period_start` (string, required) - `period_end` (string, required) - `fresh_at` (string, required) - `sources` (array of object, required) - `source` (string, required) - `fresh_at` (string | null, required) - `status` (string, required): One of `ok`, `stale`, `missing`. - `series` (array of object, required) - `day` (string, required) - `providers` (object, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/spend" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/spend`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/spend", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get a usage report `GET /v1/usage/report` The account’s usage across every key in hourly or daily UTC buckets, grouped by any mix of key, model, lane, role, session and team, and narrowed by any filter. A person key reads its own person’s usage here, never the account’s. - Operation id: `getUsageReport` - Group: [Usage & spend](https://superbot.gg/developers/usage.md) - Auth: A caller key holding `usage:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `usage:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `starting_at` | string (date-time) | optional | RFC 3339 start, floored to the bucket width. Default: 7 days before `ending_at`. | | `ending_at` | string (date-time) | optional | RFC 3339 end (exclusive), ceiled to the bucket width. Default: the end of the current bucket. At most 92 days after `starting_at`. | | `bucket_width` | string | optional | Bucket width; default 1d. One of `1h`, `1d`. | | `group_by` | string \| array of string | optional | Split each bucket by these dimensions: api_key_id, model, lane, role, session_id, team_id. Repeat the parameter or pass a comma list. | | `api_key_ids` | string \| array of string | optional | Only usage from these caller key ids. Repeat the parameter or pass a comma list. | | `models` | string \| array of string | optional | Only usage on these model ids. Repeat the parameter or pass a comma list. | | `lanes` | string \| array of string | optional | Only usage on these lanes: credits, caller_key, byo. Repeat the parameter or pass a comma list. | | `roles` | string \| array of string | optional | Only usage with these agent roles (chat for a plain turn). Repeat the parameter or pass a comma list. | | `session_ids` | string \| array of string | optional | Only usage inside these agent runs. Repeat the parameter or pass a comma list. | | `team_ids` | string \| array of string | optional | Only usage from keys scoped to these teams. Repeat the parameter or pass a comma list. | | `limit` | integer | optional | Buckets per page. 1h: default 24, max 168. 1d: default 7, max 31. | | `page` | string | optional | The previous response’s `next_page`. Repeat group_by and the filters with it. | #### Response 200 One page of buckets. `application/json`: UsageReport. - `object` (string, required): One of `list`. - `data` (array of UsageBucket, required) - `object` (string, required): One of `bucket`. - `starting_at` (string (date-time), required) - `ending_at` (string (date-time), required) - `results` (array of UsageResult, required) - `requests` (integer, required) - `tokens_in` (number, required) - `tokens_out` (number, required) - `cache_read` (number, required) - `cache_write` (number, required) - `tokens` (number, required): Billed credits. - `usd` (number, required) - `list_usd` (number, required) - `api_key_id` (string | null) - `model` (string | null) - `lane` (string | null) - `role` (string | null) - `session_id` (string | null) - `team_id` (string | null) - `has_more` (boolean, required) - `next_page` (string | null, required): Pass as `page` for the next buckets; null on the last page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 503 | — | The account store is not ready; retry later. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/usage/report" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/usage/report`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/usage/report", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ## Keys Mint, list, edit and revoke scoped caller keys. ### List caller keys `GET /v1/keys` Every caller key on the account, revoked ones included. Never the hash. A caller key reads the list without `person_email`, `prompt_history` and `person_limit_usd`, which are the account owner's; a person key lists only its own person's keys. - Operation id: `listKeys` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: A caller key holding `keys:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `keys:read` #### Response 200 The keys. `application/json`: CallerKeyList. - `object` (string, required): One of `list`. - `data` (array of CallerKey, required) - `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. - `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. - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. - `keys` (array of CallerKey, required): Legacy: the same rows as `data`. - `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. - `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. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/keys" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/keys`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/keys", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Create a caller key `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`. - Operation id: `createKey` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: A caller key holding `keys:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `keys:write` #### Request body `application/json`, required. - `name` (string): What the tool calls itself, 1-64 chars. Required unless `person` is given, then it defaults to the person's name. - `person` (KeyPerson): The person a key is minted for. Without `id` it makes a new person (`name` required); with `id` it adds a key to that person. A person key stamps no device (the minting device's logout never revokes it), takes no `org_id` and is billed to the owner. - `name` (string): The person's display name, 1-64 printable characters (no `<`, `>`, `"` or `'`). Required for a new person; with `id` it must equal the stored name or be left out. - `email` (string): The person's email address. With `id` it must equal the stored one or be left out. - `group` (string): A free-text grouping, 1-64 characters. With `id` it must equal the stored one or be left out. - `id` (string): The `person_id` of 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 same `id`, then a revoke of the old key. - `route` (string): One of `byo`, `credits`, `auto`. - `mode` (string): One of `model`, `agent`. - `daily_limit_tokens` (number): Daily spend cap in whole credits. - `monthly_limit_tokens` (number): Monthly spend cap in whole credits. - `allowed_models` (array of string): Glob allow-list over model names; with models_listed, the exact canonical ids (no globs). - `models_listed` (boolean): true = 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_pins` (object | null): Canonical model id to the stable account id it is pinned to (non-empty strings). A PATCH replaces the whole map; null clears it. - `model_aliases` (object | null): Canonical 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_model` (string | null): 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 (`claude-sonnet-5-5`, `gpt-5.5`, `custom//`). A call that names any other model is dialled as named. `null` or `superbot` clears it. A model of your own account needs a key on route `auto` or `byo` in mode `model` whose `allowed_models` admits it; a key on route `credits` takes a house model only, and a key with `models_listed` takes 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 400 `invalid_default_model`: send `default_model: null` with it. A PATCH that omits it leaves it as it was. - `incognito` (boolean) - `scopes` (array of Scope): Explicit scopes; wins over `preset`. - `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. - `preset` (string): A named scope set. One of `gateway`, `read_only`, `full`. #### Response 201 The new key. `application/json`: CreatedKey. - `key` (string, required): The plaintext `sbc_…` key, shown once. - `row` (CallerKey, required) - `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. - `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. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh 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":"user@example.com","group":"your-group"},"route":"byo"}' ``` ```js 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":"user@example.com","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":"user@example.com","group":"your-group"},"route":"byo"}, ) print(res.status_code, res.json()) ``` ### Get the calling key `GET /v1/keys/whoami` The calling caller key’s own row and effective scopes, and its own metered usage in three windows (`usage`). A person key’s fields ride on `row`. Caller keys only; a session gets 403 caller_key_required. A revoked key gets 403 revoked_key, a paused one 403 key_paused. - Operation id: `getCurrentKey` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`). - Scopes: none #### Response 200 The key. `application/json`: CurrentKey. - `row` (CallerKey, required) - `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. - `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. - `scopes` (array of Scope, required) - `usage` (KeyUsage, required): This key's own metered usage in three windows: `day` is the trailing 24 hours (the daily cap's window), `week` the trailing 7 days, `month` the current UTC calendar month (the monthly cap's window). Each window reports `requests` (every metered request), `prompts` (the requests that were the person's own text), `tokens` and `billed_usd`. - `day` (KeyUsageWindow, required) - `requests` (integer, required): Distinct metered requests (a request that dialed several times counts once). Every request the key made is one, an agent's tool legs, a title helper and a probe included: the call volume, not what the person asked. - `prompts` (integer, required): Distinct answered prompts: requests whose last message was the person's own text and that were answered (the gateway marks the request's row only then), counted once per request id. A tool leg, a title helper, a probe and a refused or failed call are requests but not prompts. Only the dials the gateway wrote a row for are read, so the relay door's turns are not counted here. - `tokens` (number, required): Every metered leg: fresh input, output and both cache legs. - `billed_usd` (number, required): What the window's calls are worth to the caps and the usage pages, USD: the router's settle once read back, else the metered list value. - `clients` (object): Distinct requests of the window made by Zapier or n8n, counted from the `x-superbot-client` tag (`zapier/`, `n8n/`) the request carried. A platform with no request in the window is absent, and the member is absent when neither made one. - `zapier` (integer) - `n8n` (integer) - `week` (KeyUsageWindow, required) - `requests` (integer, required): Distinct metered requests (a request that dialed several times counts once). Every request the key made is one, an agent's tool legs, a title helper and a probe included: the call volume, not what the person asked. - `prompts` (integer, required): Distinct answered prompts: requests whose last message was the person's own text and that were answered (the gateway marks the request's row only then), counted once per request id. A tool leg, a title helper, a probe and a refused or failed call are requests but not prompts. Only the dials the gateway wrote a row for are read, so the relay door's turns are not counted here. - `tokens` (number, required): Every metered leg: fresh input, output and both cache legs. - `billed_usd` (number, required): What the window's calls are worth to the caps and the usage pages, USD: the router's settle once read back, else the metered list value. - `clients` (object): Distinct requests of the window made by Zapier or n8n, counted from the `x-superbot-client` tag (`zapier/`, `n8n/`) the request carried. A platform with no request in the window is absent, and the member is absent when neither made one. - `zapier` (integer) - `n8n` (integer) - `month` (KeyUsageWindow, required) - `requests` (integer, required): Distinct metered requests (a request that dialed several times counts once). Every request the key made is one, an agent's tool legs, a title helper and a probe included: the call volume, not what the person asked. - `prompts` (integer, required): Distinct answered prompts: requests whose last message was the person's own text and that were answered (the gateway marks the request's row only then), counted once per request id. A tool leg, a title helper, a probe and a refused or failed call are requests but not prompts. Only the dials the gateway wrote a row for are read, so the relay door's turns are not counted here. - `tokens` (number, required): Every metered leg: fresh input, output and both cache legs. - `billed_usd` (number, required): What the window's calls are worth to the caps and the usage pages, USD: the router's settle once read back, else the metered list value. - `clients` (object): Distinct requests of the window made by Zapier or n8n, counted from the `x-superbot-client` tag (`zapier/`, `n8n/`) the request carried. A platform with no request in the window is absent, and the member is absent when neither made one. - `zapier` (integer) - `n8n` (integer) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/keys/whoami" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/keys/whoami`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/keys/whoami", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Update a caller key `PATCH /v1/keys/{id}` Edit a key’s name, route, mode, caps, models, default model or scopes. A bad `default_model` answers 400 `invalid_default_model`. On a person key, `person_name`, `person_email`, `person_group`, `prompt_history` and `paused_at` edit the person and are written to every live key of that person; on any other key they answer 400 `not_a_person_key`, and an invalid value answers 400 `invalid_person`. A person key is edited by the account owner only, and a person field is changed by the account owner only: a caller key that tries either answers 403 `caller_key_forbidden`. A person key cannot be renamed `account`. A paused caller key answers 403 `key_paused`. - Operation id: `updateKey` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: A caller key holding `keys:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `keys:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | required | | #### Request body `application/json`, required. - `name` (string) - `route` (string): One of `byo`, `credits`, `auto`. - `mode` (string): One of `model`, `agent`. - `daily_limit_tokens` (number): Daily spend cap in whole credits. - `monthly_limit_tokens` (number): Monthly spend cap in whole credits. - `allowed_models` (array of string): Glob allow-list over model names; with models_listed, the exact canonical ids (no globs). - `models_listed` (boolean): true = 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_pins` (object | null): Canonical model id to the stable account id it is pinned to (non-empty strings). A PATCH replaces the whole map; null clears it. - `model_aliases` (object | null): Canonical 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_model` (string | null): 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 (`claude-sonnet-5-5`, `gpt-5.5`, `custom//`). A call that names any other model is dialled as named. `null` or `superbot` clears it. A model of your own account needs a key on route `auto` or `byo` in mode `model` whose `allowed_models` admits it; a key on route `credits` takes a house model only, and a key with `models_listed` takes 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 400 `invalid_default_model`: send `default_model: null` with it. A PATCH that omits it leaves it as it was. - `incognito` (boolean) - `scopes` (array of Scope): Explicit scopes; wins over `preset`. - `person_name` (string): Rename the person (1-64 printable characters). Cannot be cleared. Does not rename the key (`name`). - `person_email` (string | null): Set the person's email address; null clears it. - `person_group` (string | null): Set the person's group; null clears it. - `prompt_history` (PromptHistory & object | null) - `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` (boolean | string | null): `true` pauses the person now (the edge stamps the time), an ISO 8601 time pauses from then (not in the future), `false` or null resumes. A paused person's keys answer 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`. #### Response 200 The edited key. `application/json`: UpdatedKey. - `row` (CallerKey, required) - `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. - `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. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X PATCH "https://superbot.gg/v1/keys/$ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"name":"your-name","route":"byo","mode":"model"}' ``` ```js const id = 'ID'; const res = await fetch(`https://superbot.gg/v1/keys/${id}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"name":"your-name","route":"byo","mode":"model"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests id = "ID" res = requests.request( "PATCH", f"https://superbot.gg/v1/keys/{id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"name":"your-name","route":"byo","mode":"model"}, ) print(res.status_code, res.json()) ``` ### Revoke a caller key `DELETE /v1/keys/{id}` Revoke a key. Revoking an already-revoked key is a no-op (`already: true`). A person key is revoked by the account owner only; a caller key that tries answers 403 `caller_key_forbidden`. - Operation id: `revokeKey` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: A caller key holding `keys:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `keys:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | required | | #### Response 200 Revoked. `application/json`: RevokedKey. - `ok` (boolean, required): One of `true`. - `already` (boolean) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/keys/$ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const id = 'ID'; const res = await fetch(`https://superbot.gg/v1/keys/${id}`, { method: 'DELETE', 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( "DELETE", f"https://superbot.gg/v1/keys/{id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Rotate a caller key `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. - Operation id: `rotateKey` - Group: [Keys](https://superbot.gg/developers/keys.md) - Auth: A caller key holding `keys:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `keys:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `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) - `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. - `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. - `revoked` (string | null, required): The id of the key that was revoked, or null if that revoke failed after the mint. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/keys/$ID/rotate" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js 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()) ``` ## Endpoints Custom OpenAI- or Anthropic-compatible endpoints and @mention aliases. ### List custom endpoints `GET /v1/upstreams` Every custom endpoint on the account. Never the API key; header values are redacted for caller keys. - Operation id: `listUpstreams` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:read` #### Response 200 The endpoints. `application/json`: UpstreamList. - `object` (string, required): One of `list`. - `data` (array of Upstream, required) - `slug` (string, required): The endpoint id; `custom` for the legacy singleton. - `label` (string, required) - `base_url` (string, required) - `dialect` (string, required): One of `openai`, `anthropic`. - `headers` (object): Extra header names; values are redacted for caller keys. - `models` (array of string) - `model_names` (object) - `model_meta` (object) - `probe` (UpstreamProbe) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) - `updated_at` (string) - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. - `upstreams` (array of Upstream, required): Legacy: the same rows as `data`. - `slug` (string, required): The endpoint id; `custom` for the legacy singleton. - `label` (string, required) - `base_url` (string, required) - `dialect` (string, required): One of `openai`, `anthropic`. - `headers` (object): Extra header names; values are redacted for caller keys. - `models` (array of string) - `model_names` (object) - `model_meta` (object) - `probe` (UpstreamProbe) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) - `updated_at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/upstreams" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/upstreams`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/upstreams", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Add a custom endpoint `POST /v1/upstreams` Add an OpenAI- or Anthropic-compatible endpoint and probe it. A failed probe still saves. - Operation id: `createUpstream` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Request body `application/json`, required. - `label` (string, required) - `base_url` (string, required) - `api_key` (string, required) - `dialect` (string): One of `openai`, `anthropic`, `auto`. - `headers` (object) - `models` (array of string) #### Response 201 The saved endpoint and its probe. `application/json`: UpstreamWithProbe. - `upstream` (Upstream, required) - `slug` (string, required): The endpoint id; `custom` for the legacy singleton. - `label` (string, required) - `base_url` (string, required) - `dialect` (string, required): One of `openai`, `anthropic`. - `headers` (object): Extra header names; values are redacted for caller keys. - `models` (array of string) - `model_names` (object) - `model_meta` (object) - `probe` (UpstreamProbe) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) - `updated_at` (string) - `probe` (UpstreamProbe, required) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/upstreams" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"label":"your-label","base_url":"https://example.com","api_key":"your-api-key"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/upstreams`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"label":"your-label","base_url":"https://example.com","api_key":"your-api-key"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/upstreams", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"label":"your-label","base_url":"https://example.com","api_key":"your-api-key"}, ) print(res.status_code, res.json()) ``` ### Update a custom endpoint `PATCH /v1/upstreams/{slug}` Edit label, dialect, key, models or model names; re-probes when the dial changed. - Operation id: `updateUpstream` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `slug` | string | required | | #### Request body `application/json`, required. - `label` (string) - `dialect` (string): One of `openai`, `anthropic`. - `api_key` (string) - `models` (array of string) - `model_names` (object) #### Response 200 The edited endpoint and its last probe. `application/json`: UpstreamWithProbe. - `upstream` (Upstream, required) - `slug` (string, required): The endpoint id; `custom` for the legacy singleton. - `label` (string, required) - `base_url` (string, required) - `dialect` (string, required): One of `openai`, `anthropic`. - `headers` (object): Extra header names; values are redacted for caller keys. - `models` (array of string) - `model_names` (object) - `model_meta` (object) - `probe` (UpstreamProbe) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) - `updated_at` (string) - `probe` (UpstreamProbe, required) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X PATCH "https://superbot.gg/v1/upstreams/$SLUG" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"label":"your-label","dialect":"openai","api_key":"your-api-key"}' ``` ```js const slug = 'SLUG'; const res = await fetch(`https://superbot.gg/v1/upstreams/${slug}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"label":"your-label","dialect":"openai","api_key":"your-api-key"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests slug = "SLUG" res = requests.request( "PATCH", f"https://superbot.gg/v1/upstreams/{slug}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"label":"your-label","dialect":"openai","api_key":"your-api-key"}, ) print(res.status_code, res.json()) ``` ### Remove a custom endpoint `DELETE /v1/upstreams/{slug}` Remove the endpoint and its stored key. - Operation id: `deleteUpstream` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `slug` | string | required | | #### Response 204 Removed. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/upstreams/$SLUG" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const slug = 'SLUG'; const res = await fetch(`https://superbot.gg/v1/upstreams/${slug}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests slug = "SLUG" res = requests.request( "DELETE", f"https://superbot.gg/v1/upstreams/{slug}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Re-probe a custom endpoint `POST /v1/upstreams/{slug}/probe` Dial the stored endpoint and fold what it lists into the row. A failed probe is a 200 whose report says so. - Operation id: `probeUpstream` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `slug` | string | required | | #### Response 200 The endpoint and the probe. `application/json`: UpstreamWithProbe. - `upstream` (Upstream, required) - `slug` (string, required): The endpoint id; `custom` for the legacy singleton. - `label` (string, required) - `base_url` (string, required) - `dialect` (string, required): One of `openai`, `anthropic`. - `headers` (object): Extra header names; values are redacted for caller keys. - `models` (array of string) - `model_names` (object) - `model_meta` (object) - `probe` (UpstreamProbe) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) - `updated_at` (string) - `probe` (UpstreamProbe, required) - `ok` (boolean, required) - `models_found` (integer) - `error` (string) - `at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/upstreams/$SLUG/probe" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const slug = 'SLUG'; const res = await fetch(`https://superbot.gg/v1/upstreams/${slug}/probe`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests slug = "SLUG" res = requests.request( "POST", f"https://superbot.gg/v1/upstreams/{slug}/probe", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### List @mention aliases `GET /v1/aliases` Your own aliases, the built-in ones, then the catalog; `available` says whether the vendor is linked. - Operation id: `listAliases` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:read` #### Response 200 The aliases. `application/json`: array of Alias. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/aliases" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/aliases`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/aliases", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Set an @mention alias `PUT /v1/aliases/{token}` Create or overwrite one personal alias; every paired device picks it up. - Operation id: `setAlias` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `token` | string | required | | #### Request body `application/json`, required. - `vendor` (string, required) - `model_id` (string) - `label` (string) - `custody` (string): One of `envelope`, `device-held`. #### Response 200 Saved. `application/json`: AliasWrite. - `ok` (boolean, required): One of `true`. - `token` (string, required) - `rev` (integer, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X PUT "https://superbot.gg/v1/aliases/$TOKEN" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"vendor":"your-vendor"}' ``` ```js const token = 'TOKEN'; const res = await fetch(`https://superbot.gg/v1/aliases/${token}`, { method: 'PUT', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"vendor":"your-vendor"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests token = "TOKEN" res = requests.request( "PUT", f"https://superbot.gg/v1/aliases/{token}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"vendor":"your-vendor"}, ) print(res.status_code, res.json()) ``` ### Delete an @mention alias `DELETE /v1/aliases/{token}` Delete one personal alias on every device. - Operation id: `deleteAlias` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: A caller key holding `endpoints:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `endpoints:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `token` | string | required | | #### Response 200 Deleted. `application/json`: AliasWrite. - `ok` (boolean, required): One of `true`. - `token` (string, required) - `rev` (integer, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/aliases/$TOKEN" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const token = 'TOKEN'; const res = await fetch(`https://superbot.gg/v1/aliases/${token}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests token = "TOKEN" res = requests.request( "DELETE", f"https://superbot.gg/v1/aliases/{token}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get a service’s OpenAPI document `GET /docs/services/{service_id}.json` One shipped service’s learned endpoints as an OpenAPI 3.1 document (`x-path-templates`, `x-superbot-replay`): endpoint shapes, header rule names and provenance, never an example value or a credential. - Operation id: `getServiceDocument` - Group: [Endpoints](https://superbot.gg/developers/endpoints.md) - Auth: No credential needed; any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session is also accepted. - Scopes: none #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `service_id` | string | required | The service id, e.g. `doordash`. | #### Response 200 The service as OpenAPI 3.1. `application/json`: object. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/docs/services/$SERVICE_ID.json" ``` ```js const serviceId = 'SERVICE_ID'; const res = await fetch(`https://superbot.gg/docs/services/${serviceId}.json`, { method: 'GET', }); console.log(res.status, await res.json()); ``` ```python import os import requests service_id = "SERVICE_ID" res = requests.request( "GET", f"https://superbot.gg/docs/services/{service_id}.json", ) print(res.status_code, res.json()) ``` ## Teams Teams, their members and their invites. ### Export a team’s audit log `GET /v1/org/{id}/audit` The team’s audit log, oldest first, as NDJSON (default) or CSV: who, on which device and through which agent, used which credential class for what, and the outcome. Rows are kept for a year. Owners and admins only; a member gets 403 and a caller outside the team 404. At most `limit` rows per request; when more remain, the `x-next-cursor` header carries the cursor for the next page. Columns, in CSV order: ts, org_id, actor_user_id, actor_email, device_id, agent, credential_class, credential_ref, action, target, outcome, request_id, ip, ua. - Operation id: `exportTeamAuditLog` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `id` | string | required | The team id (`org_…`). | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `format` | string | optional | Attachment format; default ndjson. One of `ndjson`, `csv`. | | `since` | string (date-time) | optional | Rows at or after this time; default a year ago. | | `until` | string (date-time) | optional | Rows before this time; default now. | | `cursor` | string | optional | The previous page’s `x-next-cursor`. | | `limit` | integer | optional | Rows per page; default 1000, and anything above 5000 is read as 5000. | #### Response 200 The rows, as an attachment. `application/x-ndjson`: string. `text/csv`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 503 | — | The audit store is unavailable; retry later. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/org/$ID/audit" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const id = 'ID'; const res = await fetch(`https://superbot.gg/v1/org/${id}/audit`, { method: 'GET', 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( "GET", f"https://superbot.gg/v1/org/{id}/audit", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### List teams `GET /v1/teams` Every team the caller is a live member of, oldest first. A team key sees only its own team. - Operation id: `listTeams` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | optional | Items per page, 1-100. | | `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). | | `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). | #### Response 200 One page of teams. `application/json`: TeamList. - `object` (string, required): One of `list`. - `data` (array of Team, required) - `id` (string, required) - `object` (string, required): One of `team`. - `name` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `member_count` (integer, required) - `created_at` (string, required) - `share_defaults` (object, required): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string, required): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean, required) - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/teams" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/teams`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/teams", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Create a team `POST /v1/teams` Create a team with the caller as its one owner. The owner’s Helper sets up the team key when it next syncs. - Operation id: `createTeam` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Request body `application/json`, required. - `name` (string, required) #### Response 201 The new team. `application/json`: Team. - `id` (string, required) - `object` (string, required): One of `team`. - `name` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `member_count` (integer, required) - `created_at` (string, required) - `share_defaults` (object, required): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string, required): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/teams" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"name":"your-name"}' ``` ```js const res = await fetch(`https://superbot.gg/v1/teams`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"name":"your-name"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/teams", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"name":"your-name"}, ) print(res.status_code, res.json()) ``` ### Get a team `GET /v1/teams/{team_id}` One team the caller is a member of, with the caller’s own role. - Operation id: `getTeam` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Response 200 The team. `application/json`: Team. - `id` (string, required) - `object` (string, required): One of `team`. - `name` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `member_count` (integer, required) - `created_at` (string, required) - `share_defaults` (object, required): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string, required): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/teams/$TEAM_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "GET", f"https://superbot.gg/v1/teams/{team_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Update a team `PATCH /v1/teams/{team_id}` Rename a team or change its sharing settings. Only the fields sent change. Admins and owners only. - Operation id: `updateTeam` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Request body `application/json`, required. - `name` (string) - `share_defaults` (object): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean): Whether an admin must confirm each new member before they receive team secrets. #### Response 200 The updated team. `application/json`: Team. - `id` (string, required) - `object` (string, required): One of `team`. - `name` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `member_count` (integer, required) - `created_at` (string, required) - `share_defaults` (object, required): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string, required): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X PATCH "https://superbot.gg/v1/teams/$TEAM_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"name":"your-name","share_defaults":{"mcp":true,"rules":true,"skills":true},"share_policy":"members"}' ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"name":"your-name","share_defaults":{"mcp":true,"rules":true,"skills":true},"share_policy":"members"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "PATCH", f"https://superbot.gg/v1/teams/{team_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"name":"your-name","share_defaults":{"mcp":True,"rules":True,"skills":True},"share_policy":"members"}, ) print(res.status_code, res.json()) ``` ### Delete a team `DELETE /v1/teams/{team_id}` Delete a team and every membership in it. Owners only. This cannot be undone. - Operation id: `deleteTeam` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Response 200 The team is gone. `application/json`: DeletedTeam. - `id` (string, required) - `object` (string, required): One of `team`. - `deleted` (boolean, required): One of `true`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/teams/$TEAM_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "DELETE", f"https://superbot.gg/v1/teams/{team_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### List team members `GET /v1/teams/{team_id}/members` The team’s live members, paged by user id in join order. - Operation id: `listTeamMembers` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | optional | Items per page, 1-100. | | `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). | | `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). | #### Response 200 One page of members. `application/json`: TeamMemberList. - `object` (string, required): One of `list`. - `data` (array of TeamMember, required) - `object` (string, required): One of `team_member`. - `user_id` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `groups` (array of string, required) - `joined_at` (string, required) - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/teams/$TEAM_ID/members" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/members`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "GET", f"https://superbot.gg/v1/teams/{team_id}/members", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Change a member’s role `PATCH /v1/teams/{team_id}/members/{user_id}` Set a member’s role. You can only grant a role below your own, to a member below your own. Ownership never moves here. - Operation id: `updateTeamMember` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | | `user_id` | string | required | The member’s account id. | #### Request body `application/json`, required. - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. #### Response 200 The member. `application/json`: TeamMember. - `object` (string, required): One of `team_member`. - `user_id` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `groups` (array of string, required) - `joined_at` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X PATCH "https://superbot.gg/v1/teams/$TEAM_ID/members/$USER_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"role":"owner"}' ``` ```js const teamId = 'TEAM_ID'; const userId = 'USER_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/members/${userId}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"role":"owner"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" user_id = "USER_ID" res = requests.request( "PATCH", f"https://superbot.gg/v1/teams/{team_id}/members/{user_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"role":"owner"}, ) print(res.status_code, res.json()) ``` ### Remove a team member `DELETE /v1/teams/{team_id}/members/{user_id}` Remove a member. Admins remove members below them; owners remove anyone except the last owner (409 last_owner). - Operation id: `removeTeamMember` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | | `user_id` | string | required | The member’s account id. | #### Response 200 The member is removed. `application/json`: RemovedTeamMember. - `object` (string, required): One of `team_member`. - `user_id` (string, required) - `deleted` (boolean, required): One of `true`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/teams/$TEAM_ID/members/$USER_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const userId = 'USER_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/members/${userId}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" user_id = "USER_ID" res = requests.request( "DELETE", f"https://superbot.gg/v1/teams/{team_id}/members/{user_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### List pending team invites `GET /v1/teams/{team_id}/invites` Invites not yet accepted, revoked or expired, paged by invite code in the order they were sent. Admins and owners only. - Operation id: `listTeamInvites` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | optional | Items per page, 1-100. | | `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). | | `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). | #### Response 200 One page of invites. `application/json`: TeamInviteList. - `object` (string, required): One of `list`. - `data` (array of TeamInvite, required) - `object` (string, required): One of `team_invite`. - `code` (string, required) - `email` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `created_at` (string, required) - `expires_at` (string) - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/teams/$TEAM_ID/invites" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/invites`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "GET", f"https://superbot.gg/v1/teams/{team_id}/invites", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Invite someone to a team `POST /v1/teams/{team_id}/invites` Email an invite for a role below your own (default member). A pending invite to the same address is replaced. Invites expire after 7 days. - Operation id: `createTeamInvite` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | #### Request body `application/json`, required. - `email` (string, required) - `role` (TeamRole): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. #### Response 201 The invite, already mailed. `application/json`: TeamInvite. - `object` (string, required): One of `team_invite`. - `code` (string, required) - `email` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `created_at` (string, required) - `expires_at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/teams/$TEAM_ID/invites" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"email":"user@example.com"}' ``` ```js const teamId = 'TEAM_ID'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/invites`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"email":"user@example.com"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" res = requests.request( "POST", f"https://superbot.gg/v1/teams/{team_id}/invites", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"email":"user@example.com"}, ) print(res.status_code, res.json()) ``` ### Revoke a team invite `DELETE /v1/teams/{team_id}/invites/{code}` Revoke an invite. Its link stops working at once. - Operation id: `revokeTeamInvite` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | | `code` | string | required | The invite code. | #### Response 200 The invite is revoked. `application/json`: RevokedTeamInvite. - `object` (string, required): One of `team_invite`. - `code` (string, required) - `revoked` (boolean, required): One of `true`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/teams/$TEAM_ID/invites/$CODE" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const code = 'CODE'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/invites/${code}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" code = "CODE" res = requests.request( "DELETE", f"https://superbot.gg/v1/teams/{team_id}/invites/{code}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Resend a team invite `POST /v1/teams/{team_id}/invites/{code}/resend` Replace a pending invite with a fresh code and mail it again. The old link stops working. - Operation id: `resendTeamInvite` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `team_id` | string | required | The team id. | | `code` | string | required | The invite code. | #### Response 200 The new invite, already mailed. `application/json`: TeamInvite. - `object` (string, required): One of `team_invite`. - `code` (string, required) - `email` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `created_at` (string, required) - `expires_at` (string) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/teams/$TEAM_ID/invites/$CODE/resend" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const teamId = 'TEAM_ID'; const code = 'CODE'; const res = await fetch(`https://superbot.gg/v1/teams/${teamId}/invites/${code}/resend`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests team_id = "TEAM_ID" code = "CODE" res = requests.request( "POST", f"https://superbot.gg/v1/teams/{team_id}/invites/{code}/resend", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Accept a team invite `POST /v1/team_invites/{code}/accept` Join the team an invite names. The account’s email must match the invite; an account with no email adds one in Sign-in methods first (`invite_needs_email`). `share` chooses what you pool into the team; MCP servers stay unshared unless you set `mcp`. - Operation id: `acceptTeamInvite` - Group: [Teams](https://superbot.gg/developers/teams.md) - Auth: A caller key holding `teams:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `teams:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `code` | string | required | The invite code. | #### Request body `application/json`. - `share` (object): What to pool into the team, per kind. - `mcp` (boolean) - `rules` (boolean) - `skills` (boolean) #### Response 200 The team you joined. `application/json`: Team. - `id` (string, required) - `object` (string, required): One of `team`. - `name` (string, required) - `role` (TeamRole, required): The caller's role in this team. One of `owner`, `admin`, `editor`, `member`. - `member_count` (integer, required) - `created_at` (string, required) - `share_defaults` (object, required): What a new member pools by default, per kind. - `mcp` (boolean, required) - `rules` (boolean, required) - `skills` (boolean, required) - `share_policy` (string, required): Who may add items to the pool. One of `members`, `editors`. - `require_manual_confirm` (boolean, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/team_invites/$CODE/accept" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"share":{"mcp":true,"rules":true,"skills":true}}' ``` ```js const code = 'CODE'; const res = await fetch(`https://superbot.gg/v1/team_invites/${code}/accept`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"share":{"mcp":true,"rules":true,"skills":true}}), }); console.log(res.status, await res.json()); ``` ```python import os import requests code = "CODE" res = requests.request( "POST", f"https://superbot.gg/v1/team_invites/{code}/accept", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"share":{"mcp":True,"rules":True,"skills":True}}, ) print(res.status_code, res.json()) ``` ## Devices The devices paired to your account. ### Run a job on an agent computer `POST /v1/devices/{device_id}/jobs` Queue one device-shell job on a linked agent computer, by its id. First-party only: a session or a device token of your own Superbot app; agent computer tokens, MCP connectors, caller keys and the account API key are refused (403). An asleep agent computer answers `queued_asleep`; the job waits for its next poll up to 600 s. - Operation id: `createAgentJob` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | An agent computer (`agt_…`) on your account. | #### Request body `application/json`, required. - `kind` (AgentJobKind, required): The device-shell job kinds a first-party device may run on an agent computer. One of `bash`, `bash_write`, `bash_output`, `bash_kill`, `bash_resize`, `read`, `write`, `glob`, `grep`. - `args` (object, required): The relay tool's own args, camelCase, per kind: bash {command, cwd?, timeoutMs?, runInBackground?, interactive?} (interactive: a real tty, answered with bash_write; open a terminal pane with {command: , runInBackground: true, interactive: true}, whose result carries {type: 'terminal', terminalId}); bash_write {terminalId, input, newline?}; bash_output {terminalId, since?, wait?}; bash_kill {terminalId}; bash_resize {terminalId, cols, rows} (a terminal pane's resize of an interactive terminal's tty: integers, cols 20..500, rows 5..200; a non-interactive terminal answers not_a_tty); read {path, line?, limit?}; write {path, content, overwrite?}; glob {pattern, cwd?}; grep {pattern, path?, cwd?}. Unknown keys are refused. #### Response 201 Queued. `application/json`: AgentJobEnqueueResponse. - `job_id` (string, required) - `state` (AgentJobState, required): `queued_asleep`: the agent computer has no open poll; the job waits for its next poll inside the 600 s TTL. `expired`: the TTL ran out before a result. One of `queued`, `queued_asleep`, `claimed`, `done`, `failed`, `expired`. - `expires_at` (string, required): ISO 8601, 600 s after the enqueue. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/devices/$DEVICE_ID/jobs" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"kind":"bash","args":{}}' ``` ```js const deviceId = 'DEVICE_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}/jobs`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"kind":"bash","args":{}}), }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" res = requests.request( "POST", f"https://superbot.gg/v1/devices/{device_id}/jobs", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"kind":"bash","args":{}}, ) print(res.status_code, res.json()) ``` ### Read an agent computer job `GET /v1/devices/{device_id}/jobs/{job_id}` The job and, once it is `done` or `failed`, its result. `wait` (seconds, at most 25) parks the read until the job settles. A job lost to a Superbot restart answers 410 `job_lost_in_restart` (`retryable: true`, `kind`): it may have run on the agent computer, so check before repeating anything that changes state, then send it again. An id nobody minted, another account's, or older than the 600 s job lifetime is 404 `job_not_found`. - Operation id: `getAgentJob` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | An agent computer (`agt_…`) on your account. | | `job_id` | string | required | The job id the enqueue answered. | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `wait` | string | optional | Seconds to wait for the job to settle, 0-25. | #### Response 200 The job. `application/json`: AgentJobView. - `job_id` (string, required) - `device_id` (string, required) - `kind` (AgentJobKind, required): The device-shell job kinds a first-party device may run on an agent computer. One of `bash`, `bash_write`, `bash_output`, `bash_kill`, `bash_resize`, `read`, `write`, `glob`, `grep`. - `state` (AgentJobState, required): `queued_asleep`: the agent computer has no open poll; the job waits for its next poll inside the 600 s TTL. `expired`: the TTL ran out before a result. One of `queued`, `queued_asleep`, `claimed`, `done`, `failed`, `expired`. - `created_at` (string, required) - `expires_at` (string, required) - `result` (AgentJobResult): Present once the state is `done` or `failed`. - `ok` (boolean, required) - `content` (any) - `error` (object) - `code` (string, required) - `message` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 410 | `job_lost_in_restart` | Superbot restarted after the job was queued and its outcome was not kept (`job_lost_in_restart`, `retryable: true`, `kind`). Send the job again once a repeat is safe. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/devices/$DEVICE_ID/jobs/$JOB_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const deviceId = 'DEVICE_ID'; const jobId = 'JOB_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}/jobs/${jobId}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" job_id = "JOB_ID" res = requests.request( "GET", f"https://superbot.gg/v1/devices/{device_id}/jobs/{job_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Stream an agent computer terminal `GET /v1/devices/{device_id}/terminals/{terminal_id}/stream` Server-sent events, every frame `event: terminal` with an AgentTerminalFrame as JSON: `output` (seq strictly increasing), then `exit` or `gone`, after which the stream closes. Resume with `since=` (or Last-Event-ID). Open a terminal with a `bash` job `{command: , runInBackground: true, interactive: true}` (a real tty: prompts, sudo and TUIs work) and type into it with `bash_write`. - Operation id: `streamAgentTerminal` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | An agent computer (`agt_…`) on your account. | | `terminal_id` | string | required | The terminal id a background `bash` job answered. | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `since` | string | optional | Resume after this output seq (a byte cursor). Absent: from the start of the buffer. | #### Response 200 The terminal stream. `text/event-stream`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/devices/$DEVICE_ID/terminals/$TERMINAL_ID/stream" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const deviceId = 'DEVICE_ID'; const terminalId = 'TERMINAL_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}/terminals/${terminalId}/stream`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" terminal_id = "TERMINAL_ID" res = requests.request( "GET", f"https://superbot.gg/v1/devices/{device_id}/terminals/{terminal_id}/stream", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Preview an agent computer code `GET /v1/pair/{user_code}` The details of a pending code an agent computer showed. First-party only: your own Superbot app (a session or its device token). - Operation id: `previewAgentPair` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: none #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `user_code` | string | required | The code the agent computer shows (e.g. `ABCD-EFGH`). | #### Response 200 The pending code. `application/json`: AgentPairPreview. - `kind` (string, required): One of `agent_computer`. - `label` (string, required) - `agent_vendor` (string | null, required) - `ip` (string | null, required) - `geo` (string | null, required) - `tier` (string, required): One of `link`. - `approve_on` (string, required): One of `this_device`, `phone`. - `asked_at` (string): When the agent computer asked for this code (ISO-8601 UTC). Absent on an older edge. - `expires_at` (string): When the code lapses (ISO-8601 UTC). Absent on an older edge. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/pair/$USER_CODE" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const userCode = 'USER_CODE'; const res = await fetch(`https://superbot.gg/v1/pair/${userCode}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests user_code = "USER_CODE" res = requests.request( "GET", f"https://superbot.gg/v1/pair/{user_code}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Approve an agent computer code `POST /v1/pair/{user_code}/approve` Link the agent computer behind a pending code at the link tier (terminal and relay, no synced data). First-party only; a web session with a recent phone is told to finish on the phone (409 approve_on_phone). - Operation id: `approveAgentPair` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: none #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `user_code` | string | required | The code the agent computer shows (e.g. `ABCD-EFGH`). | #### Request body `application/json`. - `label` (string): A new label, 1-32 characters. #### Response 200 Linked. `application/json`: AgentPairApproveResponse. - `device_id` (string, required) - `kind` (string, required): One of `agent_computer`. - `tier` (string, required): One of `link`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/pair/$USER_CODE/approve" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"label":"your-label"}' ``` ```js const userCode = 'USER_CODE'; const res = await fetch(`https://superbot.gg/v1/pair/${userCode}/approve`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"label":"your-label"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests user_code = "USER_CODE" res = requests.request( "POST", f"https://superbot.gg/v1/pair/{user_code}/approve", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"label":"your-label"}, ) print(res.status_code, res.json()) ``` ### Decline an agent computer code `POST /v1/pair/{user_code}/deny` Decline a pending code ("Not me"). The agent computer's next poll of its device code answers `access_denied` (RFC 8628 §3.5) and the code is dead. `reason` `not_me` says the user never asked for it: it is logged with the claimed vendor and the request network, and three distinct accounts reporting one network inside 24 hours count against that network's code limit. First-party only. 404 `not_found` for a code that is unknown, expired, approved or already declined. - Operation id: `denyAgentPair` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: Any live caller key (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: none #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `user_code` | string | required | The code the agent computer shows (e.g. `ABCD-EFGH`). | #### Request body `application/json`. - `reason` (string): Why. Default `cancel`. One of `cancel`, `not_me`. #### Response 200 Declined. `application/json`: AgentPairDenyResponse. - `ok` (boolean, required): One of `true`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/pair/$USER_CODE/deny" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"reason":"cancel"}' ``` ```js const userCode = 'USER_CODE'; const res = await fetch(`https://superbot.gg/v1/pair/${userCode}/deny`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"reason":"cancel"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests user_code = "USER_CODE" res = requests.request( "POST", f"https://superbot.gg/v1/pair/{user_code}/deny", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"reason":"cancel"}, ) print(res.status_code, res.json()) ``` ### List devices `GET /v1/devices` The devices paired to this account, oldest first, paged by device id. `online` filters on presence (seen within the last two minutes). Revoked devices are not listed. - Operation id: `listDevices` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | optional | Items per page, 1-100. | | `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). | | `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). | | `online` | string | optional | Only devices that are (`true`) or are not (`false`) online now. One of `true`, `false`. | #### Response 200 A page of devices. `application/json`: DeviceList. - `object` (string, required): One of `list`. - `data` (array of Device, required) - `id` (string, required) - `object` (string, required): One of `device`. - `kind` (string, required) - `label` (string, required) - `fingerprint` (string, required) - `created_at` (string, required) - `last_seen_at` (string | null, required) - `online` (boolean, required) - `capabilities` (object) - `tools_count` (integer, required) - `hub_port` (integer) - `helper_version` (string) - `held_vendors` (array of string, required) - `held_models` (array of string, required) - `agent` (AgentDeviceFacet): Present only on a Device of kind `agent_computer`. - `agent_vendor` (string, required): The agent VM vendor, as it declared itself at link time. `generic` is any other agent. One of `grok-bot`, `muse`, `dots`, `manus`, `cursor-cloud`, `devin`, `replit`, `genspark`, `kimi`, `generic`. - `tier` (string, required): `link`: terminal and relay only. `data`: link plus the synced data the linking app granted. One of `link`, `data`. - `state` (string, required): `online`: polling now. `asleep`: suspended by its vendor (jobs wait `queued_asleep`). `offline`: not seen recently. One of `online`, `asleep`, `offline`. - `expires_at` (string, required): The next lifecycle deadline (ISO 8601), the one `expiry_kind` names. Warned 3 days ahead. - `expiry_kind` (string, required): `data_idle`: 14 days idle drops the data tier to link. `reconfirm`: the 90-day re-confirm is due (missed: link tier). `link_idle`: 30 days idle unlinks it. One of `data_idle`, `reconfirm`, `link_idle`. - `reconfirm_due_at` (string | null, required): When the data tier must be re-confirmed (POST /me/devices/{device_id}/agent-reconfirm); null at the link tier. - `key` (string): Whether this device holds the account's current end-to-end encryption key, from its own last report. `linked`: it holds the current key. `not_linked`: it holds none (it can still add logins, which reach the other devices). `out_of_date`: it holds an older or a different key. `unknown`: it has not reported, or the account has no key yet. Absent on a device that holds no key (an agent computer, an API key, an MCP connector, the cloud computer, a web browser: browsers never hold the key). A desktop app reports through its Helper (`custody_via`). One of `linked`, `not_linked`, `out_of_date`, `unknown`. - `custody_via` (string): The id of the device whose key this one uses (a desktop app names its Helper); `key` is that device's state. Absent when the device holds its own. - `created_via` (string): Present only on a Device of kind `agent_computer`. `app_link`: linked through the app-minted link, so the vendor was recorded by the app and may be shown as verified. `device_code`: the agent claimed its own vendor at a device-code approval, so show it as unverified. A missing value is `device_code`. One of `app_link`, `device_code`. - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/devices" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/devices`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/devices", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get a device `GET /v1/devices/{device_id}` One device, with its live capabilities when it is connected. - Operation id: `getDevice` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | The device id (a Device `id`). | #### Response 200 The device. `application/json`: Device. - `id` (string, required) - `object` (string, required): One of `device`. - `kind` (string, required) - `label` (string, required) - `fingerprint` (string, required) - `created_at` (string, required) - `last_seen_at` (string | null, required) - `online` (boolean, required) - `capabilities` (object) - `tools_count` (integer, required) - `hub_port` (integer) - `helper_version` (string) - `held_vendors` (array of string, required) - `held_models` (array of string, required) - `agent` (AgentDeviceFacet): Present only on a Device of kind `agent_computer`. - `agent_vendor` (string, required): The agent VM vendor, as it declared itself at link time. `generic` is any other agent. One of `grok-bot`, `muse`, `dots`, `manus`, `cursor-cloud`, `devin`, `replit`, `genspark`, `kimi`, `generic`. - `tier` (string, required): `link`: terminal and relay only. `data`: link plus the synced data the linking app granted. One of `link`, `data`. - `state` (string, required): `online`: polling now. `asleep`: suspended by its vendor (jobs wait `queued_asleep`). `offline`: not seen recently. One of `online`, `asleep`, `offline`. - `expires_at` (string, required): The next lifecycle deadline (ISO 8601), the one `expiry_kind` names. Warned 3 days ahead. - `expiry_kind` (string, required): `data_idle`: 14 days idle drops the data tier to link. `reconfirm`: the 90-day re-confirm is due (missed: link tier). `link_idle`: 30 days idle unlinks it. One of `data_idle`, `reconfirm`, `link_idle`. - `reconfirm_due_at` (string | null, required): When the data tier must be re-confirmed (POST /me/devices/{device_id}/agent-reconfirm); null at the link tier. - `key` (string): Whether this device holds the account's current end-to-end encryption key, from its own last report. `linked`: it holds the current key. `not_linked`: it holds none (it can still add logins, which reach the other devices). `out_of_date`: it holds an older or a different key. `unknown`: it has not reported, or the account has no key yet. Absent on a device that holds no key (an agent computer, an API key, an MCP connector, the cloud computer, a web browser: browsers never hold the key). A desktop app reports through its Helper (`custody_via`). One of `linked`, `not_linked`, `out_of_date`, `unknown`. - `custody_via` (string): The id of the device whose key this one uses (a desktop app names its Helper); `key` is that device's state. Absent when the device holds its own. - `created_via` (string): Present only on a Device of kind `agent_computer`. `app_link`: linked through the app-minted link, so the vendor was recorded by the app and may be shown as verified. `device_code`: the agent claimed its own vendor at a device-code approval, so show it as unverified. A missing value is `device_code`. One of `app_link`, `device_code`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/devices/$DEVICE_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const deviceId = 'DEVICE_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" res = requests.request( "GET", f"https://superbot.gg/v1/devices/{device_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Rename a device `PATCH /v1/devices/{device_id}` Set the device label. The label survives later activity from the device. - Operation id: `updateDevice` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | The device id (a Device `id`). | #### Request body `application/json`, required. - `label` (string, required): The new label, 1-64 printable characters (trimmed). #### Response 200 The renamed device. `application/json`: Device. - `id` (string, required) - `object` (string, required): One of `device`. - `kind` (string, required) - `label` (string, required) - `fingerprint` (string, required) - `created_at` (string, required) - `last_seen_at` (string | null, required) - `online` (boolean, required) - `capabilities` (object) - `tools_count` (integer, required) - `hub_port` (integer) - `helper_version` (string) - `held_vendors` (array of string, required) - `held_models` (array of string, required) - `agent` (AgentDeviceFacet): Present only on a Device of kind `agent_computer`. - `agent_vendor` (string, required): The agent VM vendor, as it declared itself at link time. `generic` is any other agent. One of `grok-bot`, `muse`, `dots`, `manus`, `cursor-cloud`, `devin`, `replit`, `genspark`, `kimi`, `generic`. - `tier` (string, required): `link`: terminal and relay only. `data`: link plus the synced data the linking app granted. One of `link`, `data`. - `state` (string, required): `online`: polling now. `asleep`: suspended by its vendor (jobs wait `queued_asleep`). `offline`: not seen recently. One of `online`, `asleep`, `offline`. - `expires_at` (string, required): The next lifecycle deadline (ISO 8601), the one `expiry_kind` names. Warned 3 days ahead. - `expiry_kind` (string, required): `data_idle`: 14 days idle drops the data tier to link. `reconfirm`: the 90-day re-confirm is due (missed: link tier). `link_idle`: 30 days idle unlinks it. One of `data_idle`, `reconfirm`, `link_idle`. - `reconfirm_due_at` (string | null, required): When the data tier must be re-confirmed (POST /me/devices/{device_id}/agent-reconfirm); null at the link tier. - `key` (string): Whether this device holds the account's current end-to-end encryption key, from its own last report. `linked`: it holds the current key. `not_linked`: it holds none (it can still add logins, which reach the other devices). `out_of_date`: it holds an older or a different key. `unknown`: it has not reported, or the account has no key yet. Absent on a device that holds no key (an agent computer, an API key, an MCP connector, the cloud computer, a web browser: browsers never hold the key). A desktop app reports through its Helper (`custody_via`). One of `linked`, `not_linked`, `out_of_date`, `unknown`. - `custody_via` (string): The id of the device whose key this one uses (a desktop app names its Helper); `key` is that device's state. Absent when the device holds its own. - `created_via` (string): Present only on a Device of kind `agent_computer`. `app_link`: linked through the app-minted link, so the vendor was recorded by the app and may be shown as verified. `device_code`: the agent claimed its own vendor at a device-code approval, so show it as unverified. A missing value is `device_code`. One of `app_link`, `device_code`. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X PATCH "https://superbot.gg/v1/devices/$DEVICE_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"label":"Studio Mac"}' ``` ```js const deviceId = 'DEVICE_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"label":"Studio Mac"}), }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" res = requests.request( "PATCH", f"https://superbot.gg/v1/devices/{device_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"label":"Studio Mac"}, ) print(res.status_code, res.json()) ``` ### Unlink a device `DELETE /v1/devices/{device_id}` Sign the device out: its tokens and the caller keys it minted are revoked. The caller's own device answers 409 `own_device` (sign out from that device instead). - Operation id: `deleteDevice` - Group: [Devices](https://superbot.gg/developers/devices.md) - Auth: A caller key holding `devices:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `devices:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `device_id` | string | required | The device id (a Device `id`). | #### Response 200 The device was unlinked. `application/json`: DeletedDevice. - `id` (string, required) - `object` (string, required): One of `device`. - `deleted` (boolean, required): One of `true`. - `agent_unlink` (AgentUnlink): What unlinking an agent computer did, and the credentials to rotate at the source. - `device_id` (string, required) - `reason` (string, required): One of `user`, `revoked`, `link_idle`. - `cancelled` (object, required) - `jobs` (integer, required) - `terminals` (integer, required) - `loci` (integer, required) - `prompts` (integer, required) - `pair_requests` (integer, required) - `live_sessions` (integer, required) - `automations` (integer, required) - `key` (object, required) - `holder_removed` (boolean, required) - `factor_wraps_removed` (integer, required) - `rotation` (string, required): One of `enqueued`, `no_holder_device`, `not_needed`. - `rotate_at_source` (array of object, required) - `kind` (string, required) - `adapter` (string, required) - `label` (string | null, required) - `class` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X DELETE "https://superbot.gg/v1/devices/$DEVICE_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const deviceId = 'DEVICE_ID'; const res = await fetch(`https://superbot.gg/v1/devices/${deviceId}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests device_id = "DEVICE_ID" res = requests.request( "DELETE", f"https://superbot.gg/v1/devices/{device_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ## Runs Cloud agent runs: start one on a project, follow its events, cancel it, and get a signed webhook when it settles. ### List cloud runs `GET /v1/runs` This account’s cloud runs from every source, oldest first, paged by run id. - Operation id: `listRuns` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `limit` | integer | optional | Items per page, 1-100. | | `after_id` | string | optional | Return the page after this resource id (the previous page’s `last_id`). | | `before_id` | string | optional | Return the page before this resource id (the next page’s `first_id`). | | `status` | string | optional | Only runs in this status. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. | | `source` | string | optional | Only runs started by this source. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. | #### Response 200 A page of runs. `application/json`: RunList. - `object` (string, required): One of `list`. - `data` (array of Run, required) - `id` (string, required) - `object` (string, required): One of `run`. - `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. - `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. - `project` (string, required): The project the run works on. - `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention. - `mode` (string, required): One of `agent`, `plan`, `debug`. - `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`. - `budget` (RunBudget, required): What the run may spend: wall time, USD and legs. - `max_wall_ms` (integer, required) - `max_usd` (number, required) - `max_legs` (integer, required) - `leg_ms` (integer, required) - `usd_spent` (number | null, required) - `served_model` (string | null): The model that served the run, as the runner reported it when the run settled (the same `served_model` the swarm reports). Null until then, and on a run that settled before this field existed. - `served_lane` (string | null): Who served the run’s model calls (the same `served_lane` the swarm reports). Every cloud run is `platform`: Superbot’s own model key, charged in credits to the account. Null on a run that predates this field. One of `platform`, `null`. - `branch` (string | null, required): The branch the work sits on, when it did not land directly. - `landed_commit` (string | null, required) - `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention. - `pr_url` (string | null, required) - `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/`), when the project id is linkable. - `created_at` (string, required) - `updated_at` (string, required) - `has_more` (boolean, required) - `first_id` (string | null, required): Id of the first item on this page; pass as `before_id` for the previous page. - `last_id` (string | null, required): Id of the last item on this page; pass as `after_id` for the next page. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/runs" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/runs`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/runs", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Start a cloud run `POST /v1/runs` Queue a cloud agent run on a project. Refusals: 400 `invalid_mode`, `invalid_landing`, `invalid_prompt`, `missing_space`, `invalid_webhook_url`; 429 `run_concurrency_limit` (the account) or `key_run_limit` (this key, default 5 queued or running), with `Retry-After`. Asks the run raises are answered deny, since a key cannot answer them. - Operation id: `createRun` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:write` #### Request body `application/json`, required. - `project` (string, required): The project to run on. - `prompt` (string, required): What the agent should do. - `mode` (string): One of `agent`, `plan`, `debug`. Default `agent`. - `landing` (string): One of `main`, `pr`. Default `main`. - `budget` (object): Caps for this run. Absent fields fall back to your saved defaults. - `minutes` (number) - `usd` (number) - `legs` (integer) - `webhook_url` (string): A public https URL that receives a signed `run.settled` POST when the run settles. #### Response 201 The queued run. `application/json`: CreatedRun. - `id` (string, required) - `object` (string, required): One of `run`. - `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. - `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. - `project` (string, required): The project the run works on. - `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention. - `mode` (string, required): One of `agent`, `plan`, `debug`. - `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`. - `budget` (RunBudget, required): What the run may spend: wall time, USD and legs. - `max_wall_ms` (integer, required) - `max_usd` (number, required) - `max_legs` (integer, required) - `leg_ms` (integer, required) - `usd_spent` (number | null, required) - `served_model` (string | null): The model that served the run, as the runner reported it when the run settled (the same `served_model` the swarm reports). Null until then, and on a run that settled before this field existed. - `served_lane` (string | null): Who served the run’s model calls (the same `served_lane` the swarm reports). Every cloud run is `platform`: Superbot’s own model key, charged in credits to the account. Null on a run that predates this field. One of `platform`, `null`. - `branch` (string | null, required): The branch the work sits on, when it did not land directly. - `landed_commit` (string | null, required) - `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention. - `pr_url` (string | null, required) - `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/`), when the project id is linkable. - `created_at` (string, required) - `updated_at` (string, required) - `webhook_secret` (string): The signing secret for `webhook_url`, returned ONCE, here. Verify each delivery: `X-Superbot-Signature: t=,v1=` where v1 is HMAC-SHA256(secret, `t + "." + body`). #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/runs" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"project":"prj_7f3a","prompt":"Fix the flaky login test."}' ``` ```js const res = await fetch(`https://superbot.gg/v1/runs`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"project":"prj_7f3a","prompt":"Fix the flaky login test."}), }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "POST", "https://superbot.gg/v1/runs", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"project":"prj_7f3a","prompt":"Fix the flaky login test."}, ) print(res.status_code, res.json()) ``` ### Find the project for a repository `GET /v1/runs/projects` Your projects whose linked repository is `repo`, compared after normalising the URL (scheme, `git@host:` form, a trailing `.git` and case do not matter). Pass a returned `id` as `project` to createRun. Only `id` and `name` are returned. An empty list means no project is linked to that repository. Refusal: 400 `invalid_repo`. - Operation id: `listRunProjects` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:read` #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `repo` | string | required | The repository URL, on any git host: `https://example.com/o/r`, `ssh://git@example.com/o/r.git` or `git@example.com:o/r.git` all match the same project. | #### Response 200 The matching projects, possibly none. `application/json`: RunProjectList. - `projects` (array of object, required) - `id` (string, required): The project id to pass as `project` to createRun. - `name` (string, required): The project’s name in the Superbot app. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fexample.com%2Facme%2Fapp" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const res = await fetch(`https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fexample.com%2Facme%2Fapp`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests res = requests.request( "GET", "https://superbot.gg/v1/runs/projects?repo=https%3A%2F%2Fexample.com%2Facme%2Fapp", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Get a cloud run `GET /v1/runs/{run_id}` One run as it stands now. - Operation id: `getRun` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | required | The run id (a Run `id`). | #### Response 200 The run. `application/json`: Run. - `id` (string, required) - `object` (string, required): One of `run`. - `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. - `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. - `project` (string, required): The project the run works on. - `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention. - `mode` (string, required): One of `agent`, `plan`, `debug`. - `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`. - `budget` (RunBudget, required): What the run may spend: wall time, USD and legs. - `max_wall_ms` (integer, required) - `max_usd` (number, required) - `max_legs` (integer, required) - `leg_ms` (integer, required) - `usd_spent` (number | null, required) - `served_model` (string | null): The model that served the run, as the runner reported it when the run settled (the same `served_model` the swarm reports). Null until then, and on a run that settled before this field existed. - `served_lane` (string | null): Who served the run’s model calls (the same `served_lane` the swarm reports). Every cloud run is `platform`: Superbot’s own model key, charged in credits to the account. Null on a run that predates this field. One of `platform`, `null`. - `branch` (string | null, required): The branch the work sits on, when it did not land directly. - `landed_commit` (string | null, required) - `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention. - `pr_url` (string | null, required) - `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/`), when the project id is linkable. - `created_at` (string, required) - `updated_at` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/runs/$RUN_ID" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const runId = 'RUN_ID'; const res = await fetch(`https://superbot.gg/v1/runs/${runId}`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests run_id = "RUN_ID" res = requests.request( "GET", f"https://superbot.gg/v1/runs/{run_id}", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Follow a run’s events `GET /v1/runs/{run_id}/events` With `Accept: text/event-stream`, server-sent events (`id` is the event `seq`; reconnect with `Last-Event-ID` to resume); the stream ends once the run is final. Otherwise JSON: the events after `after`, long-polled up to `wait` seconds. - Operation id: `listRunEvents` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:read` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:read` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | required | The run id (a Run `id`). | #### Query parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `after` | string | optional | Only events with a greater `seq`. `Last-Event-ID` wins when both are sent. | | `wait` | string | optional | Long-poll: hold the request up to this many seconds (max 25) for a new event. JSON replies only. | #### Response 200 The events. `application/json`: RunEventList. - `object` (string, required): One of `list`. - `data` (array of RunEvent, required) - `object` (string, required): One of `run.event`. - `run_id` (string, required) - `seq` (integer, required): Per-run sequence number; the SSE `id`, and what `after` / `Last-Event-ID` resume from. - `type` (string, required): One of `status`, `result`, `pr`, `note_queued`, `note_delivered`. - `created_at` (string, required) - `note_id` (string): On `note_queued` / `note_delivered`: the note’s id (never its text). - `length` (integer): On `note_queued` / `note_delivered`: the note’s length in characters. - `status` (string): One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. - `branch` (string) - `landed_commit` (string) - `usd_spent` (number) - `served_model` (string): On `result` only: the model that served the run, as `served_model` on the run. - `served_lane` (string): On `result` only: who served the run, as `served_lane` on the run. One of `platform`. - `summary` (string | null): On `result` only: the runner’s end-of-run diagnostic, as `summary` on the run (not a title or an answer). Null under zero data retention. - `pr_url` (string) - `pr_number` (integer) - `pr_state` (string) - `publish_error` (string) - `next_after` (integer, required): Pass as `after` on the next poll. - `done` (boolean, required): True once nothing more will happen to the run. `text/event-stream`: string. #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X GET "https://superbot.gg/v1/runs/$RUN_ID/events" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const runId = 'RUN_ID'; const res = await fetch(`https://superbot.gg/v1/runs/${runId}/events`, { method: 'GET', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests run_id = "RUN_ID" res = requests.request( "GET", f"https://superbot.gg/v1/runs/{run_id}/events", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Cancel a cloud run `POST /v1/runs/{run_id}/cancel` Stop the run. A run that already settled is returned as it is. - Operation id: `cancelRun` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | required | The run id (a Run `id`). | #### Response 200 The run after the cancel. `application/json`: Run. - `id` (string, required) - `object` (string, required): One of `run`. - `status` (string, required): `queued`, `running`, then one of `done`, `failed`, `needs_merge` (the work is on `branch` and waits for a merge) or `cancelled`. One of `queued`, `running`, `done`, `failed`, `needs_merge`, `cancelled`. - `source` (string, required): What started the run. Runs started here are `api`. One of `app`, `api`, `cli`, `routine`, `slack`, `linear`, `jira`, `github`. - `project` (string, required): The project the run works on. - `prompt` (string | null, required): The prompt, which is also the run’s title: show this to name the run. Null under zero data retention. - `mode` (string, required): One of `agent`, `plan`, `debug`. - `landing` (string, required): `main` lands the work on the default branch; `pr` opens a pull request. One of `main`, `pr`. - `budget` (RunBudget, required): What the run may spend: wall time, USD and legs. - `max_wall_ms` (integer, required) - `max_usd` (number, required) - `max_legs` (integer, required) - `leg_ms` (integer, required) - `usd_spent` (number | null, required) - `served_model` (string | null): The model that served the run, as the runner reported it when the run settled (the same `served_model` the swarm reports). Null until then, and on a run that settled before this field existed. - `served_lane` (string | null): Who served the run’s model calls (the same `served_lane` the swarm reports). Every cloud run is `platform`: Superbot’s own model key, charged in credits to the account. Null on a run that predates this field. One of `platform`, `null`. - `branch` (string | null, required): The branch the work sits on, when it did not land directly. - `landed_commit` (string | null, required) - `summary` (string | null, required): The runner’s end-of-run diagnostic once it settles, a machine-readable line for debugging and for telling a failed run from a finished one (for example `done — sandbox fence-only, 127 tool call(s), local space sp_…`), and it can name internal ids. It is not a title and not the run’s answer: name the run by `prompt`, and do not show this text to end users. Null under zero data retention. - `pr_url` (string | null, required) - `url` (string | null, required): A deep link that opens the run’s project in the Superbot app (`superbot://project/`), when the project id is linkable. - `created_at` (string, required) - `updated_at` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/runs/$RUN_ID/cancel" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" ``` ```js const runId = 'RUN_ID'; const res = await fetch(`https://superbot.gg/v1/runs/${runId}/cancel`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, }, }); console.log(res.status, await res.json()); ``` ```python import os import requests run_id = "RUN_ID" res = requests.request( "POST", f"https://superbot.gg/v1/runs/{run_id}/cancel", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", }, ) print(res.status_code, res.json()) ``` ### Steer a running cloud run `POST /v1/runs/{run_id}/messages` Add a note to a run that is queued or running. The run is not restarted: it reads the note at its next step boundary (never mid-step) and carries on with it as a note from you. Notes are applied oldest first. Refusals: 409 `run_not_active` (the run settled); 400 `invalid_note` or `note_too_long` (over 8192 bytes); 429 `too_many_notes` (20 notes already waiting), with `Retry-After`. The run's events record `note_queued` and `note_delivered` with the note id and length, never its text. - Operation id: `sendRunMessage` - Group: [Runs](https://superbot.gg/developers/runs.md) - Auth: A caller key holding `runs:write` (`Authorization: Bearer sbc_…` or `x-api-key: sbc_…`), or a signed-in session. - Scopes: `runs:write` #### Path parameters | Name | Type | Required | Description | | --- | --- | --- | --- | | `run_id` | string | required | The run id (a Run `id`). | #### Request body `application/json`, required. - `text` (string, required): The note, up to 8192 bytes of UTF-8. #### Response 202 The note, queued. `application/json`: RunNote. - `id` (string, required) - `object` (string, required): One of `run.note`. - `run_id` (string, required) - `queued_at` (string, required) #### Errors Every refusal carries `error`, `message`, `doc_url` and `request_id`; the gateway routes answer in the dialect you dialed. | Status | Codes | When | | --- | --- | --- | | 400 | [`invalid_request`](https://superbot.gg/developers#errors-invalid_request) | The request is malformed or a parameter is invalid; `param` names the field. | | 401 | [`unauthorized`](https://superbot.gg/developers#errors-unauthorized) | The bearer is missing, malformed or unknown. | | 403 | [`insufficient_scope`](https://superbot.gg/developers#errors-insufficient_scope) | The key lacks a scope (insufficient_scope), is revoked, or may not call this route. | | 404 | [`not_found`](https://superbot.gg/developers#errors-not_found) | No such resource on this account. | | 409 | [`conflict`](https://superbot.gg/developers#errors-conflict) | The resource is not in a state that allows this change. | | 429 | [`rate_limited`](https://superbot.gg/developers#errors-rate_limited) | Over the per-key request bucket; retry after x-ratelimit-reset. | #### Examples ```sh curl -sS -X POST "https://superbot.gg/v1/runs/$RUN_ID/messages" \ -H "Authorization: Bearer $SUPERBOT_API_KEY" \ -H "content-type: application/json" \ -d '{"text":"Skip the migration for now and focus on the failing test."}' ``` ```js const runId = 'RUN_ID'; const res = await fetch(`https://superbot.gg/v1/runs/${runId}/messages`, { method: 'POST', headers: { Authorization: `Bearer ${process.env.SUPERBOT_API_KEY}`, 'content-type': 'application/json', }, body: JSON.stringify({"text":"Skip the migration for now and focus on the failing test."}), }); console.log(res.status, await res.json()); ``` ```python import os import requests run_id = "RUN_ID" res = requests.request( "POST", f"https://superbot.gg/v1/runs/{run_id}/messages", headers={ "Authorization": f"Bearer {os.environ['SUPERBOT_API_KEY']}", "content-type": "application/json", }, json={"text":"Skip the migration for now and focus on the failing test."}, ) print(res.status_code, res.json()) ```