{ "openapi": "3.1.0", "info": { "title": "Sim API v2 — Workspace Resources", "description": "Version 2 of the Sim REST API for workspace metadata, members, MCP servers, skills, custom tools, credentials, and write-only secrets.", "version": "2.0.0", "contact": { "name": "Sim Support", "email": "help@sim.ai", "url": "https://www.sim.ai" }, "license": { "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" } }, "servers": [ { "url": "https://www.sim.ai", "description": "Production" } ], "tags": [ { "name": "Workspaces", "description": "Read workspace metadata and its effective member roster." }, { "name": "MCP Servers", "description": "Register and manage Model Context Protocol servers." }, { "name": "Skills", "description": "Create and manage reusable instruction documents for agents." }, { "name": "Custom Tools", "description": "Create and manage code-backed tools that agents can call." }, { "name": "Credentials", "description": "Discover providers, create service-account credentials, connect or reconnect OAuth accounts, disconnect credentials, and list connections without secret material." }, { "name": "Secrets", "description": "Set and manage write-only workspace and personal secret values." } ], "security": [ { "apiKey": [] } ], "paths": { "/api/v2/workspaces": { "get": { "operationId": "listWorkspaces", "summary": "List Workspaces", "description": "List active workspaces available to the API key with opaque cursor pagination. A personal API key sees every accessible workspace that permits personal API keys; a workspace API key sees only its bound workspace.", "tags": ["Workspaces"], "parameters": [ { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "schema": { "default": "createdAt", "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "type": "string", "enum": ["name", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "desc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum workspaces to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Public metadata for workspaces available to the API key.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListWorkspacesResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/workspaces/{workspaceId}": { "get": { "operationId": "getWorkspace", "summary": "Get Workspace", "description": "Return public metadata for one accessible workspace. Governance identities, billing identities, and internal membership identifiers are intentionally omitted.", "tags": ["Workspaces"], "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "description": "Workspace to retrieve.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace to retrieve." } } ], "responses": { "200": { "description": "Public workspace metadata.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetWorkspaceResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/workspaces/{workspaceId}/members": { "get": { "operationId": "listWorkspaceMembers", "summary": "List Workspace Members", "description": "List the workspace's effective members ordered by email. Explicit workspace grants and inherited organization-administrator grants are merged; internal membership and billing identities are omitted.", "tags": ["Workspaces"], "parameters": [ { "name": "workspaceId", "in": "path", "required": true, "description": "Workspace to retrieve.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace to retrieve." } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum members to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum members to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "An email-ordered page of effective workspace members.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListWorkspaceMembersResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/mcp-servers": { "get": { "operationId": "listMcpServers", "summary": "List MCP Servers", "description": "List MCP servers registered in a workspace. Request-header values and OAuth client secrets are never returned. The discovery fields stay at their registration defaults until `GET /api/v2/mcp-servers/{id}/tools` runs a discovery.", "tags": ["MCP Servers"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the MCP server.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the MCP server." } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the server name.", "schema": { "description": "Case-insensitive substring match against the server name.", "type": "string", "minLength": 1, "maxLength": 200 } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "schema": { "default": "createdAt", "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "type": "string", "enum": ["name", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "desc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum MCP servers to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum MCP servers to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "MCP servers registered in the workspace.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListMcpServersResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "post": { "operationId": "createMcpServer", "summary": "Create MCP Server", "description": "Register an MCP server in a workspace. The endpoint URL is the server identity, so a URL already registered here is a `409` — reconfigure that server with `PATCH /api/v2/mcp-servers/{id}` instead. Registration never connects to the endpoint: the server comes back `disconnected` and stays unavailable until `GET /api/v2/mcp-servers/{id}/tools` succeeds.", "tags": ["MCP Servers"], "requestBody": { "required": true, "description": "Configuration for a new MCP server.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateMcpServerRequest" } } } }, "responses": { "201": { "description": "The MCP server was registered.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateMcpServerResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/mcp-servers/{id}": { "get": { "operationId": "getMcpServer", "summary": "Get MCP Server", "description": "Fetch one MCP server by identifier. Request-header values and OAuth client secrets are never returned.", "tags": ["MCP Servers"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique MCP server identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique MCP server identifier." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the MCP server.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the MCP server." } } ], "responses": { "200": { "description": "The MCP server.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetMcpServerResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "patch": { "operationId": "updateMcpServer", "summary": "Update MCP Server", "description": "Update the supplied MCP server fields. Omitted fields are retained, except where a field says otherwise. Any change that invalidates authentication revokes the stored OAuth grant, resets `connectionStatus` to `disconnected`, and clears `lastConnected` and `lastError`, so the server must be rediscovered.", "tags": ["MCP Servers"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique MCP server identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique MCP server identifier." } } ], "requestBody": { "required": true, "description": "MCP server fields to change; omitted fields retain their stored values.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMcpServerRequest" } } } }, "responses": { "200": { "description": "The updated MCP server.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateMcpServerResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "delete": { "operationId": "deleteMcpServer", "summary": "Delete MCP Server", "description": "Remove an MCP server and revoke its OAuth tokens. Workflows retain blocks that referenced the server's tools, but those tools can no longer be called.", "tags": ["MCP Servers"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique MCP server identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique MCP server identifier." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the MCP server.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the MCP server." } } ], "responses": { "200": { "description": "The MCP server was deleted.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteMcpServerResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/mcp-servers/{id}/tools": { "get": { "operationId": "listMcpServerTools", "summary": "List MCP Server Tools", "description": "Connect to a registered MCP server and return the tools it exposes. This read has side effects: it opens a live connection to the third-party server and writes `connectionStatus`, `toolCount`, `lastError`, and `lastToolsRefresh`. A `HEAD` skips the effect but is authorized exactly as the `GET` is, so it answers `400`, `401`, `403`, or `404` wherever the `GET` would and an empty `200` otherwise. Skipping the effect means skipping the read that produces the payload, so that `200` carries none of the response headers documented below — it answers whether the `GET` would be allowed, not what the `GET` would return. Discovery is bounded at 1,000 tools and 5 MB of tool payload per server. The bounded set is returned in one page; `nextCursor` is always null. An unreachable, slow, or cooling-down server is a `503`; a stored OAuth grant that no longer works is a `409` with `error.details.code` `MCP_SERVER_REAUTHORIZATION_REQUIRED`, which only a human reauthorizing in Sim can clear. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["MCP Servers"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique MCP server identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique MCP server identifier." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the MCP server.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the MCP server." } }, { "name": "refresh", "in": "query", "required": false, "description": "Bypass the short-lived per-workspace tool cache and reconnect under your own credentials. A cached result reflects whichever workspace member last ran discovery, so this is the only way to pick up a tool added since then; it costs a live round trip.", "schema": { "description": "Bypass the short-lived per-workspace tool cache and reconnect under your own credentials. A cached result reflects whichever workspace member last ran discovery, so this is the only way to pick up a tool added since then; it costs a live round trip.", "type": "boolean" } } ], "responses": { "200": { "description": "Tools exposed by the MCP server.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListMcpServerToolsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/skills": { "get": { "operationId": "listSkills", "summary": "List Skills", "description": "List workspace and built-in skills with opaque cursor pagination. Built-ins are marked read-only. The list omits skill bodies; fetch one skill to read its content.", "tags": ["Skills"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the skill.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the skill name.", "schema": { "description": "Case-insensitive substring match against the skill name.", "type": "string", "minLength": 1, "maxLength": 200 } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "schema": { "default": "createdAt", "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "type": "string", "enum": ["name", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "desc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum skills to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum skills to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Skills available in the workspace.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListSkillsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "post": { "operationId": "createSkill", "summary": "Create Skill", "description": "Create one skill in a workspace. Its kebab-case name must be unique and cannot be reserved by a built-in skill. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Skills"], "requestBody": { "required": true, "description": "Definition of a new skill.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSkillRequest" } } } }, "responses": { "201": { "description": "The skill was created.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSkillResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/skills/{id}": { "get": { "operationId": "getSkill", "summary": "Get Skill", "description": "Fetch one workspace or built-in skill, including its full content. Built-in skills are marked read-only.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the skill.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." } } ], "responses": { "200": { "description": "The skill.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetSkillResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "patch": { "operationId": "updateSkill", "summary": "Update Skill", "description": "Update the supplied fields on a workspace skill. Omitted fields retain their stored values. Built-in skills are read-only. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } } ], "requestBody": { "required": true, "description": "Skill fields to change; at least one editable field is required.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSkillRequest" } } } }, "responses": { "200": { "description": "The updated skill.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSkillResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "delete": { "operationId": "deleteSkill", "summary": "Delete Skill", "description": "Delete a workspace skill. Built-in skills are read-only and cannot be deleted. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the skill.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." } } ], "responses": { "200": { "description": "The skill was deleted.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteSkillResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/skills/{id}/editors": { "get": { "operationId": "listSkillEditors", "summary": "List Skill Editors", "description": "List explicit skill editors and workspace administrators with opaque cursor pagination. Internal user and membership identifiers are never returned.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the skill.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "schema": { "default": "email", "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "type": "string", "enum": ["email", "name"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "asc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum skill editors to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum skill editors to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Users who can edit the skill.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListSkillEditorsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "post": { "operationId": "grantSkillEditor", "summary": "Grant Skill Editor", "description": "Grant editor access to a current workspace member by email. The caller must already be a skill editor or workspace administrator. Workspace administrators already have derived editor access and cannot receive an explicit grant. A retried existing grant returns 200; a newly created grant returns 201. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } } ], "requestBody": { "required": true, "description": "Workspace scope and email of the member to grant.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GrantSkillEditorRequest" } } } }, "responses": { "200": { "description": "The workspace member was already a skill editor.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GrantSkillEditorResponse" } } } }, "201": { "description": "The skill editor grant was created.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GrantSkillEditorResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "delete": { "operationId": "revokeSkillEditor", "summary": "Revoke Skill Editor", "description": "Revoke an explicit editor grant by email. The caller must already be a skill editor or workspace administrator. Workspace administrators have derived access that cannot be revoked. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Skills"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`.", "schema": { "type": "string", "minLength": 1, "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the skill.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." } }, { "name": "email", "in": "query", "required": true, "description": "Email address of a current workspace member.", "schema": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", "description": "Email address of a current workspace member." } } ], "responses": { "200": { "description": "The explicit editor grant was revoked.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RevokeSkillEditorResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/custom-tools": { "get": { "operationId": "listCustomTools", "summary": "List Custom Tools", "description": "List code-backed custom tools defined in a workspace, with opaque cursor pagination. Legacy personal tools are excluded.", "tags": ["Custom Tools"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the custom tool.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the custom tool." } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the tool title.", "schema": { "description": "Case-insensitive substring match against the tool title.", "type": "string", "minLength": 1, "maxLength": 200 } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result.", "schema": { "default": "createdAt", "description": "Field used to sort the result.", "type": "string", "enum": ["title", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "desc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum custom tools to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum custom tools to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Custom tools defined in the workspace.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListCustomToolsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "post": { "operationId": "createCustomTool", "summary": "Create Custom Tool", "description": "Create a code-backed custom tool in a workspace. Its title must be unique because tools resolve by title at call time.", "tags": ["Custom Tools"], "requestBody": { "required": true, "description": "Definition and implementation of a new custom tool.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCustomToolRequest" } } } }, "responses": { "201": { "description": "The custom tool was created.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCustomToolResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/custom-tools/{id}": { "get": { "operationId": "getCustomTool", "summary": "Get Custom Tool", "description": "Fetch one custom tool by identifier, scoped to its workspace.", "tags": ["Custom Tools"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique custom tool identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique custom tool identifier." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the custom tool.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the custom tool." } } ], "responses": { "200": { "description": "The custom tool.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetCustomToolResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "patch": { "operationId": "updateCustomTool", "summary": "Update Custom Tool", "description": "Update the supplied custom tool fields. Omitted fields retain their stored values, and titles must remain unique within the workspace.", "tags": ["Custom Tools"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique custom tool identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique custom tool identifier." } } ], "requestBody": { "required": true, "description": "Custom tool fields to change; at least one editable field is required.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCustomToolRequest" } } } }, "responses": { "200": { "description": "The updated custom tool.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCustomToolResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "delete": { "operationId": "deleteCustomTool", "summary": "Delete Custom Tool", "description": "Delete a custom tool. Agent blocks retain their configuration but can no longer call the deleted tool.", "tags": ["Custom Tools"], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "Unique custom tool identifier.", "schema": { "type": "string", "minLength": 1, "description": "Unique custom tool identifier." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace that owns the custom tool.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the custom tool." } } ], "responses": { "200": { "description": "The custom tool was deleted.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteCustomToolResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/credentials": { "get": { "operationId": "listCredentials", "summary": "List Credentials", "description": "List OAuth and service-account connections visible to the caller. Secret material is never returned.", "tags": ["Credentials"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace whose credentials should be listed.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace whose credentials should be listed." } }, { "name": "type", "in": "query", "required": false, "description": "Restrict results to this credential type.", "schema": { "description": "Restrict results to this credential type.", "type": "string", "enum": ["oauth", "service_account"] } }, { "name": "providerId", "in": "query", "required": false, "description": "Restrict results to credentials for this integration provider.", "schema": { "description": "Restrict results to credentials for this integration provider.", "type": "string", "minLength": 1 } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the credential display name.", "schema": { "description": "Case-insensitive substring match against the credential display name.", "type": "string", "minLength": 1, "maxLength": 200 } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result.", "schema": { "default": "createdAt", "description": "Field used to sort the result.", "type": "string", "enum": ["displayName", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "desc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum credentials to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum credentials to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Credentials visible to the caller.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListCredentialsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "post": { "operationId": "createServiceAccountCredential", "summary": "Create Service-Account Credential", "description": "Verify and store one service-account credential. Use provider discovery to select a service-account provider, then encode its required fields as the JSON object string in credentials. The credentials string is write-only and is never returned. A retried source match returns the existing credential with 200; a newly created credential returns 201. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Credentials"], "requestBody": { "required": true, "description": "Provider identifier, optional display metadata, and a write-only JSON object string containing the fields declared by provider discovery.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateServiceAccountCredentialRequest" } } } }, "responses": { "200": { "description": "An existing credential matched the verified source.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateServiceAccountCredentialResponse" } } } }, "201": { "description": "The service-account credential was created.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateServiceAccountCredentialResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/credentials/providers": { "get": { "operationId": "listCredentialProviders", "summary": "List Credential Providers", "description": "List catalogued OAuth and service-account connection methods and whether each is available to the caller in this workspace and deployment. Optionally search provider names with a case-insensitive substring match. OAuth authorization options contain the exact provider IDs accepted by the browser connection endpoint; service-account methods list the exact create-body fields and mark secret fields write-only. The bounded set is returned in one page; `nextCursor` is always null.", "tags": ["Credentials"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace used to evaluate credential-provider availability and integration policy.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace used to evaluate credential-provider availability and integration policy." } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the credential provider name.", "schema": { "description": "Case-insensitive substring match against the credential provider name.", "type": "string", "minLength": 1, "maxLength": 200 } } ], "responses": { "200": { "description": "Credential provider catalog with caller-specific availability.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListCredentialProvidersResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/credentials/connections": { "post": { "operationId": "createCredentialConnection", "summary": "Create Credential Connection", "description": "Create a short-lived browser URL for connecting an OAuth provider or reconnecting an existing OAuth credential. Open the URL in a browser, sign in as the personal API-key owner, complete provider authorization, then refresh the credentials list. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Credentials"], "requestBody": { "required": true, "description": "For a new connection, provide providerId and displayName. For a reconnect, provide only credentialId; the existing display name is preserved.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCredentialConnectionBody" } } } }, "responses": { "200": { "description": "A short-lived browser authorization URL.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateCredentialConnectionResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "409": { "$ref": "#/components/responses/Conflict" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/credentials/{credentialId}": { "delete": { "operationId": "deleteCredential", "summary": "Disconnect Credential", "description": "Disconnect an OAuth or service-account credential and clear its stored workflow, deployment, paused-run, knowledge-connector, and webhook references. Credential admin access is required. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Credentials"], "parameters": [ { "name": "credentialId", "in": "path", "required": true, "description": "Credential to disconnect.", "schema": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Credential to disconnect." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace expected to own the credential.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace expected to own the credential." } } ], "responses": { "200": { "description": "The credential was disconnected.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteCredentialResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/secrets": { "get": { "operationId": "listSecrets", "summary": "List Secrets", "description": "List workspace and caller-owned personal secret metadata with opaque cursor pagination. Only names, scope, role, and timestamps are returned; secret values are never returned. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Secrets"], "parameters": [ { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace whose secret metadata should be listed.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace whose secret metadata should be listed." } }, { "name": "scope", "in": "query", "required": false, "description": "Restrict results to one ownership scope.", "schema": { "description": "Restrict results to one ownership scope.", "type": "string", "enum": ["workspace", "personal"] } }, { "name": "search", "in": "query", "required": false, "description": "Case-insensitive substring match against the secret name.", "schema": { "description": "Case-insensitive substring match against the secret name.", "type": "string", "minLength": 1, "maxLength": 200 } }, { "name": "sortBy", "in": "query", "required": false, "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "schema": { "default": "name", "description": "Field used to sort the result. Sorting by `name` is case-sensitive and follows the storage collation, so do not rely on a case-insensitive order.", "type": "string", "enum": ["name", "createdAt", "updatedAt"] } }, { "name": "sortOrder", "in": "query", "required": false, "description": "Sort direction.", "schema": { "default": "asc", "description": "Sort direction.", "type": "string", "enum": ["asc", "desc"] } }, { "name": "limit", "in": "query", "required": false, "description": "Maximum secrets to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "schema": { "default": 50, "description": "Maximum secrets to return per page. Must be a whole number from 1 to 100. Defaults to 50.", "type": "integer", "minimum": 1, "maximum": 100 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "schema": { "description": "Opaque cursor from the previous page. Send it back with the same sort and filters; only `limit` may change. Change anything else and pagination must restart without a cursor.", "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "Secret metadata visible to the caller.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ListSecretsResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } }, "/api/v2/secrets/{name}": { "put": { "operationId": "setSecret", "summary": "Set Secret", "description": "Create or replace a workspace or caller-owned personal secret. The value is encrypted at rest, is write-only, and is never included in the response. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Secrets"], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "Secret to create, replace, or delete.", "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_]+$", "description": "Secret to create, replace, or delete." } } ], "requestBody": { "required": true, "description": "Ownership scope and write-only value for the secret.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetSecretRequest" } } } }, "responses": { "200": { "description": "The existing secret value was replaced.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetSecretResponse" } } } }, "201": { "description": "The secret was created.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetSecretResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "413": { "$ref": "#/components/responses/PayloadTooLarge" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } }, "delete": { "operationId": "deleteSecret", "summary": "Delete Secret", "description": "Delete a workspace or caller-owned personal secret without reading or returning its stored value. A workspace API key is rejected with `403`; use a personal API key.", "tags": ["Secrets"], "parameters": [ { "name": "name", "in": "path", "required": true, "description": "Secret to create, replace, or delete.", "schema": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_]+$", "description": "Secret to create, replace, or delete." } }, { "name": "workspaceId", "in": "query", "required": true, "description": "Workspace the request is authorized against. A workspace secret is deleted from it; a personal secret is deleted for the caller in all of their workspaces.", "schema": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace the request is authorized against. A workspace secret is deleted from it; a personal secret is deleted for the caller in all of their workspaces." } }, { "name": "scope", "in": "query", "required": true, "description": "Whether the secret belongs to the workspace or to the caller. A personal secret belongs to the caller across every workspace, not to one workspace.", "schema": { "type": "string", "enum": ["workspace", "personal"], "description": "Whether the secret belongs to the workspace or to the caller. A personal secret belongs to the caller across every workspace, not to one workspace." } } ], "responses": { "200": { "description": "The secret was deleted.", "headers": { "X-RateLimit-Limit": { "$ref": "#/components/headers/X-RateLimit-Limit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/X-RateLimit-Remaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/X-RateLimit-Reset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeleteSecretResponse" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "503": { "$ref": "#/components/responses/ServiceUnavailable" } } } } }, "components": { "securitySchemes": { "apiKey": { "type": "apiKey", "in": "header", "name": "X-API-Key", "description": "Your Sim API key, personal or workspace-scoped. Generate one under Settings, then API Keys. Operations that reject workspace keys say so in their own description." } }, "headers": { "X-RateLimit-Limit": { "description": "Maximum requests allowed in the current window.", "schema": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "title": "Rate limit", "description": "Maximum requests allowed in the current window." } }, "X-RateLimit-Remaining": { "description": "Requests remaining in the current window.", "schema": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "title": "Rate limit remaining", "description": "Requests remaining in the current window." } }, "X-RateLimit-Reset": { "description": "ISO 8601 timestamp when the current rate-limit window resets.", "schema": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "title": "Rate limit reset", "description": "ISO 8601 timestamp when the current rate-limit window resets." } }, "Retry-After": { "description": "Seconds to wait before retrying, sent on `429` and `503`. Add jitter rather than retrying at exactly this offset.", "schema": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "title": "Retry after", "description": "Seconds to wait before retrying, sent on `429` and `503`. Add jitter rather than retrying at exactly this offset." } }, "X-Run-Id": { "description": "Identifier assigned to the workflow run.", "schema": { "type": "string", "minLength": 1, "title": "Run identifier", "description": "Identifier assigned to the workflow run." } } }, "responses": { "BadRequest": { "description": "The request is invalid. This includes a query parameter sent with no value (`?limit=`, `?search=`), which is rejected rather than read as zero, empty, or the parameter default — omit the parameter instead.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "BAD_REQUEST", "message": "Invalid request" } } } } }, "Unauthorized": { "description": "The API key is missing or invalid.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "UNAUTHORIZED", "message": "API key required" } } } } }, "Forbidden": { "description": "The caller lacks the rights this operation requires. When the cause is one a caller can act on, `error.details.code` names it. A resource in a workspace the caller cannot reach at all answers `404` instead, so absence and denial are indistinguishable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "FORBIDDEN", "message": "Insufficient workspace permissions", "details": { "code": "INSUFFICIENT_WORKSPACE_ROLE" } } } } } }, "NotFound": { "description": "The requested resource was not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "NOT_FOUND", "message": "Not found" } } } } }, "Conflict": { "description": "The request conflicts with current resource state.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "CONFLICT", "message": "API key name already exists" } } } } }, "PayloadTooLarge": { "description": "The request, or a resource collection it must materialize, exceeds the allowed size: an oversized request body, a generated artifact past the download ceiling, or a workspace folder tree too large to load in full.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "PAYLOAD_TOO_LARGE", "message": "Request body is too large" } } } } }, "RateLimited": { "description": "The caller exceeded the request rate limit.", "headers": { "Retry-After": { "$ref": "#/components/headers/Retry-After" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "RATE_LIMITED", "message": "API rate limit exceeded", "details": { "retryAfter": "2026-01-01T00:00:30.000Z" } } } } } }, "InternalError": { "description": "An unexpected server error occurred.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "INTERNAL_ERROR", "message": "Internal server error" } } } } }, "ServiceUnavailable": { "description": "A required service is temporarily unavailable. `Retry-After` carries the seconds to wait; treat it as a floor and add jitter. The header is omitted when `error.details.code` is `ASYNC_ENQUEUE_AMBIGUOUS`, because the run may already have started — reconcile against the returned run id instead of retrying.", "headers": { "Retry-After": { "$ref": "#/components/headers/Retry-After" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/V2Error" }, "example": { "error": { "code": "SERVICE_UNAVAILABLE", "message": "Service temporarily unavailable" } } } } } }, "schemas": { "V2Error": { "type": "object", "properties": { "error": { "type": "object", "properties": { "code": { "type": "string", "description": "Stable machine-readable error code." }, "message": { "type": "string", "description": "Human-readable explanation of the error." }, "details": { "description": "Structured error details. On a `403` whose cause a caller can act on, this carries a `code` from a closed set:\n- `INSUFFICIENT_WORKSPACE_ROLE` — The caller has access to the workspace but its role is below the one this operation requires.\n- `PERSONAL_API_KEYS_DISABLED` — The workspace's organization does not allow personal API keys. Use a workspace API key.\n- `WORKSPACE_KEY_OPERATION_NOT_PERMITTED` — This operation is not available to a workspace-scoped API key. Use a personal API key.\n- `PRINCIPAL_KIND_NOT_PERMITTED` — This operation does not accept the caller’s kind of API key.\n- `ORGANIZATION_MEMBERSHIP_REQUIRED` — The caller is not a member of the organization it named.\n- `ORGANIZATION_ADMIN_REQUIRED` — The caller is a member of the organization but not an admin or owner.\n- `ENTERPRISE_PLAN_REQUIRED` — The organization has no active enterprise subscription.\n- `ORGANIZATION_PLAN_REQUIRED` — The organization has no active organization subscription (Pro for Teams, Max for Teams, or Enterprise).\n- `AUDIT_LOGS_DISABLED` — Audit logging is not enabled for this deployment.\n- `SKILL_EDITOR_ACCESS_REQUIRED` — The caller can write in the workspace but is not an editor of this skill.\n- `SECRET_ADMIN_ACCESS_REQUIRED` — The caller can write in the workspace but is not an admin of this secret. Ask a workspace admin, or someone holding admin on the secret, to grant access or set the value.\n- `WORKSPACE_RESOURCE_LIMIT_REACHED` — The workspace already holds the maximum number of resources of this kind. Delete one, or contact Sim to raise the limit; the message names the ceiling.\n- `PUBLIC_SHARING_NOT_ALLOWED` — The workspace's organization does not permit sharing this resource publicly. An organization admin controls the policy.\n- `CREDENTIAL_ADMIN_ACCESS_REQUIRED` — The caller can reach the workspace but cannot administer this credential.\n- `MCP_SERVER_URL_NOT_ALLOWED` — The supplied MCP server URL is outside the allowed domains or resolves to an internal address." } }, "required": ["code", "message"], "additionalProperties": false, "description": "Canonical error details." } }, "required": ["error"], "additionalProperties": false, "title": "v2 error response", "description": "Canonical error envelope returned by the public v2 API.", "examples": [ { "error": { "code": "BAD_REQUEST", "message": "The request is invalid." } } ] }, "V2Workspace": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Unique workspace identifier." }, "name": { "type": "string", "description": "Workspace display name." }, "color": { "type": "string", "description": "Workspace color as a hexadecimal color value." }, "logoUrl": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Workspace logo URL, or null when none is configured." }, "memberCount": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Number of effective members, including inherited organization administrators." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the workspace was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the workspace was last updated." } }, "required": ["id", "name", "color", "logoUrl", "memberCount", "createdAt", "updatedAt"], "additionalProperties": false, "title": "Workspace", "description": "Public metadata for an accessible workspace." }, "ListWorkspacesResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2Workspace" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List workspaces response", "description": "Public metadata for workspaces available to the API key.", "examples": [ { "data": [ { "id": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "name": "Engineering", "color": "#33C482", "logoUrl": null, "memberCount": 14, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } ], "nextCursor": null } ] }, "GetWorkspaceResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Workspace" } }, "required": ["data"], "additionalProperties": false, "title": "Get workspace response", "description": "Public metadata for one workspace.", "examples": [ { "data": { "id": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "name": "Engineering", "color": "#33C482", "logoUrl": null, "memberCount": 14, "createdAt": "2026-01-15T10:30:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "V2WorkspaceMember": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", "description": "Member email address and public member identifier." }, "name": { "type": "string", "description": "Member display name." }, "image": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Member profile image URL, or null when absent." }, "role": { "type": "string", "enum": ["admin", "write", "read"], "description": "Effective role in the workspace." }, "isExternal": { "type": "boolean", "description": "Whether the member belongs to a different organization than the workspace. True only for an explicitly granted member whose own organization differs; inherited organization-administrator access is always reported as false, so this does not detect every outside caller." }, "joinedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when access was granted." } }, "required": ["email", "name", "image", "role", "isExternal", "joinedAt"], "additionalProperties": false, "title": "Workspace member", "description": "An effective workspace member and their public access role." }, "ListWorkspaceMembersResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2WorkspaceMember" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List workspace members response", "description": "A cursor-paginated page of effective workspace members.", "examples": [ { "data": [ { "email": "jane@example.com", "name": "Jane Smith", "image": null, "role": "admin", "isExternal": false, "joinedAt": "2026-01-15T10:30:00.000Z" } ], "nextCursor": null } ] }, "V2McpServer": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique server identifier derived from the workspace and endpoint URL." }, "name": { "type": "string", "description": "Server display name." }, "description": { "description": "Optional server description.", "type": "string" }, "transport": { "default": "streamable-http", "description": "Transport used to communicate with the server.", "type": "string", "enum": ["streamable-http"] }, "authType": { "description": "Authentication method used by the server.", "type": "string", "enum": ["none", "headers", "oauth"] }, "url": { "description": "Server endpoint URL.", "type": "string" }, "timeout": { "description": "Per-request timeout in milliseconds.", "type": "number" }, "retries": { "description": "Number of retries attempted per request.", "type": "number" }, "enabled": { "type": "boolean", "description": "Whether the server tools are available to workflows." }, "connectionStatus": { "description": "Result of the most recent connection attempt. Registration and re-registration establish no connection — the auth-type probe they may send does not count as one — so a server begins, and returns to, `disconnected` until a tool discovery runs.", "type": "string", "enum": ["connected", "disconnected", "error"] }, "lastError": { "description": "Message from the most recent failed connection, or null when absent. A re-registration clears it, since the configuration it described no longer applies.", "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "toolCount": { "description": "Number of tools discovered on the server.", "type": "number" }, "lastToolsRefresh": { "description": "ISO 8601 timestamp of the most recent tool-list refresh.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "lastConnected": { "description": "ISO 8601 timestamp of the most recent successful connection. Absent until the server completes one; registering a server does not set it.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "createdAt": { "description": "ISO 8601 timestamp when the server was registered.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "updatedAt": { "description": "ISO 8601 timestamp when the server was last updated.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "oauthClientId": { "description": "Pre-registered OAuth client identifier, when configured.", "type": "string" }, "hasHeaders": { "type": "boolean", "description": "Whether any request headers are configured." }, "headerNames": { "type": "array", "items": { "type": "string", "description": "Configured header name." }, "description": "Names of configured request headers. Header values are never returned." }, "hasOauthClientSecret": { "type": "boolean", "description": "Whether an OAuth client secret is stored. The value is never returned." } }, "required": [ "id", "name", "transport", "enabled", "createdAt", "updatedAt", "hasHeaders", "headerNames", "hasOauthClientSecret" ], "additionalProperties": false, "title": "MCP server", "description": "Public MCP server configuration without write-only credential values." }, "ListMcpServersResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2McpServer" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List MCP servers response", "description": "MCP servers registered in the workspace.", "examples": [ { "data": [ { "id": "mcp-3f7a9c21", "name": "Docs server", "description": "Internal documentation tools", "transport": "streamable-http", "authType": "headers", "url": "https://mcp.example.com/sse", "timeout": 30000, "retries": 3, "enabled": true, "connectionStatus": "connected", "lastError": null, "toolCount": 7, "lastToolsRefresh": "2026-06-20T14:02:11.000Z", "lastConnected": "2026-06-20T14:02:11.000Z", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "hasHeaders": true, "headerNames": ["Authorization"], "hasOauthClientSecret": false } ], "nextCursor": null } ] }, "CreateMcpServerResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2McpServer" } }, "required": ["data"], "additionalProperties": false, "title": "Create MCP server response", "description": "The registered MCP server without write-only credentials.", "examples": [ { "data": { "id": "mcp-3f7a9c21", "name": "Docs server", "description": "Internal documentation tools", "transport": "streamable-http", "authType": "headers", "url": "https://mcp.example.com/sse", "timeout": 30000, "retries": 3, "enabled": true, "connectionStatus": "disconnected", "lastError": null, "toolCount": 0, "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "hasHeaders": true, "headerNames": ["Authorization"], "hasOauthClientSecret": false } } ] }, "CreateMcpServerRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace in which to register the server." }, "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Server display name." }, "description": { "description": "Optional server description.", "type": "string", "maxLength": 2000 }, "transport": { "description": "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create.", "default": "streamable-http", "type": "string", "enum": ["streamable-http"] }, "url": { "type": "string", "minLength": 1, "maxLength": 2048, "description": "Absolute HTTP or HTTPS endpoint URL without `{{ENV_VAR}}` references. It determines server identity and is immutable: delete and recreate the server to change endpoints." }, "authType": { "description": "Authentication method. When omitted, and no `headers` are sent, registration probes the endpoint once to classify it, falling back to `headers` when the probe fails or the server does not advertise OAuth. A server publishing RFC 9728 metadata is therefore stored as `oauth`, and headers configured afterwards will not authenticate — send this field explicitly to pin the method.", "type": "string", "enum": ["none", "headers", "oauth"] }, "headers": { "description": "Write-only request headers sent to the server. Replaced wholesale rather than merged on update: sending this field drops every stored header it does not repeat.", "writeOnly": true, "type": "object", "propertyNames": { "type": "string", "minLength": 1 }, "additionalProperties": { "type": "string", "description": "Header value sent to the MCP server." } }, "timeout": { "description": "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create.", "default": 30000, "type": "integer", "minimum": 1000, "maximum": 300000 }, "retries": { "description": "Number of retries per request. Applied server-side as 3 when omitted on create.", "default": 3, "type": "integer", "minimum": 0, "maximum": 10 }, "enabled": { "description": "Whether the server tools are available to workflows. Applied server-side as true when omitted on create.", "default": true, "type": "boolean" }, "oauthClientId": { "description": "Pre-registered OAuth client identifier. Changing it on update revokes the stored OAuth grant and forces reauthorization.", "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ] }, "oauthClientSecret": { "description": "Write-only pre-registered OAuth client secret. Sending it on update as null or a new value revokes the stored OAuth grant and forces reauthorization, as does switching away from OAuth authentication.", "writeOnly": true, "anyOf": [ { "type": "string", "maxLength": 2048 }, { "type": "null" } ] } }, "required": ["workspaceId", "name", "url"], "additionalProperties": false, "title": "Create MCP server request", "description": "Configuration for a new MCP server.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "name": "Docs server", "url": "https://mcp.example.com/sse", "authType": "headers", "headers": { "Authorization": "Bearer YOUR_TOKEN" } } ] }, "GetMcpServerResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2McpServer" } }, "required": ["data"], "additionalProperties": false, "title": "Get MCP server response", "description": "One MCP server without write-only credentials.", "examples": [ { "data": { "id": "mcp-3f7a9c21", "name": "Docs server", "description": "Internal documentation tools", "transport": "streamable-http", "authType": "headers", "url": "https://mcp.example.com/sse", "timeout": 30000, "retries": 3, "enabled": true, "connectionStatus": "connected", "lastError": null, "toolCount": 7, "lastToolsRefresh": "2026-06-20T14:02:11.000Z", "lastConnected": "2026-06-20T14:02:11.000Z", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "hasHeaders": true, "headerNames": ["Authorization"], "hasOauthClientSecret": false } } ] }, "UpdateMcpServerResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2McpServer" } }, "required": ["data"], "additionalProperties": false, "title": "Update MCP server response", "description": "The updated MCP server.", "examples": [ { "data": { "id": "mcp-3f7a9c21", "name": "Docs server", "description": "Internal documentation tools", "transport": "streamable-http", "authType": "headers", "url": "https://mcp.example.com/sse", "timeout": 30000, "retries": 3, "enabled": false, "connectionStatus": "connected", "lastError": null, "toolCount": 7, "lastToolsRefresh": "2026-06-20T14:02:11.000Z", "lastConnected": "2026-06-20T14:02:11.000Z", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "hasHeaders": true, "headerNames": ["Authorization"], "hasOauthClientSecret": false } } ] }, "UpdateMcpServerRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the MCP server." }, "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Server display name." }, "description": { "description": "Optional server description.", "type": "string", "maxLength": 2000 }, "transport": { "description": "Transport used to communicate with the server. Applied server-side as `streamable-http` when omitted on create.", "default": "streamable-http", "type": "string", "enum": ["streamable-http"] }, "url": { "description": "Immutable server URL. When provided, it must equal the current URL; use delete and create to change endpoints.", "type": "string", "minLength": 1, "maxLength": 2048 }, "authType": { "description": "Authentication method. When omitted, and no `headers` are sent, registration probes the endpoint once to classify it, falling back to `headers` when the probe fails or the server does not advertise OAuth. A server publishing RFC 9728 metadata is therefore stored as `oauth`, and headers configured afterwards will not authenticate — send this field explicitly to pin the method.", "type": "string", "enum": ["none", "headers", "oauth"] }, "headers": { "description": "Write-only request headers sent to the server. Replaced wholesale rather than merged on update: sending this field drops every stored header it does not repeat.", "writeOnly": true, "type": "object", "propertyNames": { "type": "string", "minLength": 1 }, "additionalProperties": { "type": "string", "description": "Header value sent to the MCP server." } }, "timeout": { "description": "Per-request timeout in milliseconds. Applied server-side as 30000 when omitted on create.", "default": 30000, "type": "integer", "minimum": 1000, "maximum": 300000 }, "retries": { "description": "Number of retries per request. Applied server-side as 3 when omitted on create.", "default": 3, "type": "integer", "minimum": 0, "maximum": 10 }, "enabled": { "description": "Whether the server tools are available to workflows. Applied server-side as true when omitted on create.", "default": true, "type": "boolean" }, "oauthClientId": { "description": "Pre-registered OAuth client identifier. Changing it on update revokes the stored OAuth grant and forces reauthorization.", "anyOf": [ { "type": "string", "maxLength": 512 }, { "type": "null" } ] }, "oauthClientSecret": { "description": "Write-only pre-registered OAuth client secret. Sending it on update as null or a new value revokes the stored OAuth grant and forces reauthorization, as does switching away from OAuth authentication.", "writeOnly": true, "anyOf": [ { "type": "string", "maxLength": 2048 }, { "type": "null" } ] } }, "required": ["workspaceId"], "additionalProperties": false, "title": "Update MCP server request", "description": "MCP server fields to change; omitted fields retain their stored values.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "enabled": false } ] }, "V2McpServerDeleteData": { "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the deleted MCP server." }, "deleted": { "type": "boolean", "const": true, "description": "Whether the server was deleted." } }, "required": ["id", "deleted"], "additionalProperties": false, "title": "Delete MCP server data", "description": "MCP server deletion acknowledgement." }, "DeleteMcpServerResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2McpServerDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Delete MCP server response", "description": "Acknowledgement that the MCP server was deleted.", "examples": [ { "data": { "id": "mcp-3f7a9c21", "deleted": true } } ] }, "V2McpTool": { "type": "object", "properties": { "name": { "type": "string", "description": "Tool name, as the MCP server reports it." }, "description": { "description": "Tool description reported by the server.", "type": "string" }, "inputSchema": { "type": "object", "properties": { "type": { "type": "string", "const": "object", "description": "JSON Schema type of the argument object. MCP requires `object`." }, "properties": { "description": "Argument schemas keyed by argument name.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "description": "Server-defined JSON Schema for one tool argument." } }, "required": { "description": "Names of the arguments the tool requires.", "type": "array", "items": { "type": "string", "description": "Name of a required argument." } } }, "required": ["type"], "additionalProperties": { "description": "Additional JSON Schema keyword reported by the server." }, "description": "JSON Schema for the tool's arguments, as reported by the server." }, "serverId": { "type": "string", "description": "Identifier of the MCP server exposing the tool." }, "serverName": { "type": "string", "description": "Display name of the MCP server exposing the tool." } }, "required": ["name", "inputSchema", "serverId", "serverName"], "additionalProperties": false, "title": "MCP tool", "description": "A tool exposed by a registered MCP server." }, "ListMcpServerToolsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2McpTool" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Always `null` — this list has no `cursor` or `limit` param and returns its whole bounded set in one page. Present so the list can gain pages later without a shape change." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List MCP server tools response", "description": "Tools exposed by the MCP server.", "examples": [ { "data": [ { "name": "search_docs", "description": "Search the internal documentation", "inputSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "Search terms" } }, "required": ["query"] }, "serverId": "mcp-3f7a9c21", "serverName": "Docs server" } ], "nextCursor": null } ] }, "V2SkillSummary": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." }, "name": { "type": "string", "description": "Kebab-case name that agents use to reference the skill." }, "description": { "type": "string", "description": "One-line summary of when the skill applies." }, "readOnly": { "type": "boolean", "description": "Whether this is a built-in skill that cannot be modified or deleted." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the skill was created. Built-in skills report the Unix epoch." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the skill was last updated. Built-in skills report the Unix epoch." } }, "required": ["id", "name", "description", "readOnly", "createdAt", "updatedAt"], "additionalProperties": false, "title": "Skill summary", "description": "Public summary metadata for a workspace or built-in skill." }, "ListSkillsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2SkillSummary" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List skills response", "description": "Skill summaries available in the workspace.", "examples": [ { "data": [ { "id": "V1StGXR8Z5jdHi6BmyT", "name": "refund-policy", "description": "How support should handle refund requests", "readOnly": false, "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } ], "nextCursor": null } ] }, "V2Skill": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique skill identifier. A built-in skill is `builtin-` followed by its name, for example `builtin-research`." }, "name": { "type": "string", "description": "Kebab-case name that agents use to reference the skill." }, "description": { "type": "string", "description": "One-line summary of when the skill applies." }, "readOnly": { "type": "boolean", "description": "Whether this is a built-in skill that cannot be modified or deleted." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the skill was created. Built-in skills report the Unix epoch." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the skill was last updated. Built-in skills report the Unix epoch." }, "content": { "type": "string", "description": "Skill body containing the instructions given to the agent." } }, "required": ["id", "name", "description", "readOnly", "createdAt", "updatedAt", "content"], "additionalProperties": false, "title": "Skill", "description": "A workspace or built-in skill including its instruction body." }, "CreateSkillResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Skill" } }, "required": ["data"], "additionalProperties": false, "title": "Create skill response", "description": "The created skill including its content.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "name": "refund-policy", "description": "How support should handle refund requests", "readOnly": false, "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "content": "# Refund policy\n\nAlways check the order date first." } } ] }, "CreateSkillRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace in which to create the skill." }, "name": { "type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$", "description": "Kebab-case name, unique within the workspace and not reserved by a built-in skill." }, "description": { "type": "string", "minLength": 1, "maxLength": 1024, "description": "One-line summary of when the skill applies." }, "content": { "type": "string", "minLength": 1, "maxLength": 50000, "description": "Skill body containing the instructions given to the agent." } }, "required": ["workspaceId", "name", "description", "content"], "additionalProperties": false, "title": "Create skill request", "description": "Definition of a new skill.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "name": "refund-policy", "description": "How support should handle refund requests", "content": "# Refund policy\n\nAlways check the order date first." } ] }, "GetSkillResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Skill" } }, "required": ["data"], "additionalProperties": false, "title": "Get skill response", "description": "One skill including its full content.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "name": "refund-policy", "description": "How support should handle refund requests", "readOnly": false, "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "content": "# Refund policy\n\nAlways check the order date first." } } ] }, "UpdateSkillResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Skill" } }, "required": ["data"], "additionalProperties": false, "title": "Update skill response", "description": "The updated skill including its full content.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "name": "refund-policy", "description": "Updated refund guidance", "readOnly": false, "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z", "content": "# Refund policy\n\nAlways check the order date first." } } ] }, "UpdateSkillRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." }, "name": { "description": "New kebab-case skill name.", "type": "string", "minLength": 1, "maxLength": 64, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, "description": { "description": "New one-line summary of when the skill applies.", "type": "string", "minLength": 1, "maxLength": 1024 }, "content": { "description": "Replacement skill body.", "type": "string", "minLength": 1, "maxLength": 50000 } }, "required": ["workspaceId"], "additionalProperties": false, "title": "Update skill request", "description": "Skill fields to change; at least one editable field is required.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "description": "Updated refund guidance" } ] }, "V2SkillDeleteData": { "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the deleted skill." }, "deleted": { "type": "boolean", "const": true, "description": "Whether the skill was deleted." } }, "required": ["id", "deleted"], "additionalProperties": false, "title": "Delete skill data", "description": "Skill deletion acknowledgement." }, "DeleteSkillResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2SkillDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Delete skill response", "description": "Acknowledgement that the skill was deleted.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "deleted": true } } ] }, "V2SkillEditor": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", "description": "Email address of the skill editor." }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Display name of the skill editor." }, "image": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Profile image URL of the skill editor." }, "isWorkspaceAdmin": { "type": "boolean", "description": "Whether editor access is derived from workspace administration." } }, "required": ["email", "name", "image", "isWorkspaceAdmin"], "additionalProperties": false, "title": "Skill editor", "description": "Public identity fields for a user who can edit a skill." }, "ListSkillEditorsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2SkillEditor" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List skill editors response", "description": "Public identity fields for users who can edit the skill.", "examples": [ { "data": [ { "email": "jane@example.com", "name": "Jane Smith", "image": null, "isWorkspaceAdmin": false } ], "nextCursor": null } ] }, "GrantSkillEditorResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2SkillEditor" } }, "required": ["data"], "additionalProperties": false, "title": "Grant skill editor response", "description": "Public identity fields for the editor.", "examples": [ { "data": { "email": "jane@example.com", "name": "Jane Smith", "image": null, "isWorkspaceAdmin": false } } ] }, "GrantSkillEditorRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the skill." }, "email": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", "description": "Email address of a current workspace member." } }, "required": ["workspaceId", "email"], "additionalProperties": false, "title": "Grant skill editor request", "description": "Workspace scope and email of the member to grant.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "email": "jane@example.com" } ] }, "V2SkillEditorDeleteData": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$", "description": "Email address whose explicit editor grant was revoked." }, "revoked": { "type": "boolean", "const": true, "description": "Whether the explicit editor grant was revoked." } }, "required": ["email", "revoked"], "additionalProperties": false, "title": "Revoke skill editor data", "description": "Skill editor revocation acknowledgement." }, "RevokeSkillEditorResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2SkillEditorDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Revoke skill editor response", "description": "Acknowledgement that the explicit editor grant was revoked.", "examples": [ { "data": { "email": "jane@example.com", "revoked": true } } ] }, "V2CustomTool": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique custom tool identifier." }, "title": { "type": "string", "description": "Display title, unique within the workspace." }, "schema": { "type": "object", "properties": { "type": { "type": "string", "const": "function", "description": "Function declaration discriminator." }, "function": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "description": "Function name presented to the model." }, "description": { "description": "Optional explanation of what the function does.", "type": "string" }, "parameters": { "type": "object", "properties": { "type": { "type": "string", "description": "JSON Schema type for the arguments, usually `object`." }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "description": "Caller-defined JSON Schema for one tool argument." }, "description": "Caller-defined argument schemas keyed by argument name." }, "required": { "description": "Names of required arguments.", "type": "array", "items": { "type": "string" } } }, "required": ["type", "properties"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "JSON Schema describing the arguments accepted by the tool." } }, "required": ["name", "parameters"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "OpenAI-style function definition." } }, "required": ["type", "function"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "OpenAI-style function declaration describing the callable tool surface." }, "code": { "type": "string", "description": "Tool implementation executed in the sandboxed function runtime." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the tool was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the tool was last updated." } }, "required": ["id", "title", "schema", "code", "createdAt", "updatedAt"], "additionalProperties": false, "title": "Custom tool", "description": "A workspace custom tool and its callable function declaration." }, "ListCustomToolsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2CustomTool" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List custom tools response", "description": "Custom tools defined in the workspace.", "examples": [ { "data": [ { "id": "V1StGXR8Z5jdHi6BmyT", "title": "lookup_order", "schema": { "type": "function", "function": { "name": "lookup_order", "description": "Look up an order by id", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": ["orderId"] } } }, "code": "return { ok: true }", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } ], "nextCursor": null } ] }, "CreateCustomToolResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CustomTool" } }, "required": ["data"], "additionalProperties": false, "title": "Create custom tool response", "description": "The created custom tool.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "title": "lookup_order", "schema": { "type": "function", "function": { "name": "lookup_order", "description": "Look up an order by id", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": ["orderId"] } } }, "code": "return { ok: true }", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "CreateCustomToolRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace in which to create the custom tool." }, "title": { "type": "string", "minLength": 1, "maxLength": 200, "description": "Display title, unique within the workspace." }, "schema": { "type": "object", "properties": { "type": { "type": "string", "const": "function", "description": "Function declaration discriminator." }, "function": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "description": "Function name presented to the model." }, "description": { "description": "Optional explanation of what the function does.", "type": "string" }, "parameters": { "type": "object", "properties": { "type": { "type": "string", "description": "JSON Schema type for the arguments, usually `object`." }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "description": "Caller-defined JSON Schema for one tool argument." }, "description": "Caller-defined argument schemas keyed by argument name." }, "required": { "description": "Names of required arguments.", "type": "array", "items": { "type": "string" } } }, "required": ["type", "properties"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "JSON Schema describing the arguments accepted by the tool." } }, "required": ["name", "parameters"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "OpenAI-style function definition." } }, "required": ["type", "function"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "OpenAI-style function declaration describing the callable tool surface." }, "code": { "type": "string", "maxLength": 100000, "description": "Tool implementation executed in the sandboxed function runtime." } }, "required": ["workspaceId", "title", "schema", "code"], "additionalProperties": false, "title": "Create custom tool request", "description": "Definition and implementation of a new custom tool.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "title": "lookup_order", "schema": { "type": "function", "function": { "name": "lookup_order", "description": "Look up an order by id", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": ["orderId"] } } }, "code": "return { ok: true }" } ] }, "GetCustomToolResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CustomTool" } }, "required": ["data"], "additionalProperties": false, "title": "Get custom tool response", "description": "One custom tool.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "title": "lookup_order", "schema": { "type": "function", "function": { "name": "lookup_order", "description": "Look up an order by id", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": ["orderId"] } } }, "code": "return { ok: true }", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "UpdateCustomToolResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CustomTool" } }, "required": ["data"], "additionalProperties": false, "title": "Update custom tool response", "description": "The updated custom tool.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "title": "lookup_order", "schema": { "type": "function", "function": { "name": "lookup_order", "description": "Look up an order by id", "parameters": { "type": "object", "properties": { "orderId": { "type": "string" } }, "required": ["orderId"] } } }, "code": "return { ok: false }", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "UpdateCustomToolRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that owns the custom tool." }, "title": { "description": "New display title for the tool.", "type": "string", "minLength": 1, "maxLength": 200 }, "schema": { "description": "Replacement function declaration.", "type": "object", "properties": { "type": { "type": "string", "const": "function", "description": "Function declaration discriminator." }, "function": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "description": "Function name presented to the model." }, "description": { "description": "Optional explanation of what the function does.", "type": "string" }, "parameters": { "type": "object", "properties": { "type": { "type": "string", "description": "JSON Schema type for the arguments, usually `object`." }, "properties": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "description": "Caller-defined JSON Schema for one tool argument." }, "description": "Caller-defined argument schemas keyed by argument name." }, "required": { "description": "Names of required arguments.", "type": "array", "items": { "type": "string" } } }, "required": ["type", "properties"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "JSON Schema describing the arguments accepted by the tool." } }, "required": ["name", "parameters"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." }, "description": "OpenAI-style function definition." } }, "required": ["type", "function"], "additionalProperties": { "description": "Caller-defined extension value preserved by the public API." } }, "code": { "description": "Replacement tool implementation.", "type": "string", "maxLength": 100000 } }, "required": ["workspaceId"], "additionalProperties": false, "title": "Update custom tool request", "description": "Custom tool fields to change; at least one editable field is required.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "code": "return { ok: false }" } ] }, "V2CustomToolDeleteData": { "type": "object", "properties": { "id": { "type": "string", "description": "Identifier of the deleted custom tool." }, "deleted": { "type": "boolean", "const": true, "description": "Whether the custom tool was deleted." } }, "required": ["id", "deleted"], "additionalProperties": false, "title": "Delete custom tool data", "description": "Custom tool deletion acknowledgement." }, "DeleteCustomToolResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CustomToolDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Delete custom tool response", "description": "Acknowledgement that the custom tool was deleted.", "examples": [ { "data": { "id": "V1StGXR8Z5jdHi6BmyT", "deleted": true } } ] }, "V2Credential": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique credential identifier." }, "type": { "type": "string", "enum": ["oauth", "service_account"], "description": "Authenticated connection type." }, "displayName": { "type": "string", "description": "Credential display name." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional credential description." }, "providerId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Integration provider authenticated by this credential." }, "accountId": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Linked account identifier for OAuth credentials." }, "hasServiceAccountKey": { "type": "boolean", "description": "Whether a service-account payload is stored. Its contents are never returned." }, "role": { "type": "string", "enum": ["admin", "member"], "description": "Caller role for the credential." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the credential was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the credential was last updated." } }, "required": [ "id", "type", "displayName", "description", "providerId", "accountId", "hasServiceAccountKey", "role", "createdAt", "updatedAt" ], "additionalProperties": false, "title": "Credential", "description": "Public authenticated-connection metadata without secret material." }, "ListCredentialsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2Credential" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List credentials response", "description": "Credential metadata visible to the caller.", "examples": [ { "data": [ { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "type": "service_account", "displayName": "Zoom service account", "description": null, "providerId": "zoom-service-account", "accountId": null, "hasServiceAccountKey": true, "role": "admin", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } ], "nextCursor": null } ] }, "V2CredentialProvider": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "oauth", "description": "Browser-based OAuth connection method." }, "serviceId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Stable credential-provider identifier." }, "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Credential provider display name." }, "description": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Credential provider description." }, "providerFamily": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Owning provider family identifier." }, "available": { "type": "boolean", "description": "Whether this caller can connect the provider in the current deployment." }, "supportsReconnect": { "type": "boolean", "description": "Whether existing credentials for this service can be reconnected." }, "authorizationOptions": { "minItems": 1, "maxItems": 10, "type": "array", "items": { "type": "object", "properties": { "providerId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Exact OAuth provider identifier accepted by the connection endpoint." }, "label": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Human-readable authorization-server label." } }, "required": ["providerId", "label"], "additionalProperties": false }, "description": "Authorization servers available for this OAuth service." } }, "required": [ "type", "serviceId", "name", "description", "providerFamily", "available", "supportsReconnect", "authorizationOptions" ], "additionalProperties": false }, { "type": "object", "properties": { "type": { "type": "string", "const": "service_account", "description": "Direct service-account credential method." }, "serviceId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Stable credential-provider identifier." }, "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Credential provider display name." }, "description": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Credential provider description." }, "providerFamily": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Owning provider family identifier." }, "available": { "type": "boolean", "description": "Whether this caller can connect the provider in the current deployment." }, "providerId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Exact service-account provider ID accepted by credential creation." }, "docsUrl": { "type": "string", "format": "uri", "description": "Setup guide for the provider." }, "helpText": { "description": "Provider-specific setup guidance.", "type": "string", "minLength": 1, "maxLength": 2000 }, "requiresClientGeneratedCredentialId": { "type": "boolean", "description": "Whether the caller must generate and submit the credential ID before setup." }, "fields": { "minItems": 1, "maxItems": 20, "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Exact create-body field name." }, "label": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Human-readable field label." }, "placeholder": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Suggested input placeholder." }, "required": { "type": "boolean", "description": "Whether the field is required for the selected flow." }, "secret": { "type": "boolean", "description": "Whether the submitted field is write-only secret material." }, "multiline": { "type": "boolean", "description": "Whether the field is intended for multi-line input." }, "requiredForAuthMethods": { "description": "Authentication methods for which this field is required.", "minItems": 1, "maxItems": 10, "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 64 } }, "options": { "description": "Fixed values accepted by a selector field.", "minItems": 1, "maxItems": 20, "type": "array", "items": { "type": "object", "properties": { "value": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Submitted option value." }, "label": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Human-readable option label." } }, "required": ["value", "label"], "additionalProperties": false } }, "hint": { "description": "Provider-specific setup guidance.", "type": "string", "minLength": 1, "maxLength": 2000 } }, "required": ["id", "label", "placeholder", "required", "secret", "multiline"], "additionalProperties": false }, "description": "Create-body fields accepted by this provider. Secret fields are write-only." } }, "required": [ "type", "serviceId", "name", "description", "providerFamily", "available", "providerId", "docsUrl", "requiresClientGeneratedCredentialId", "fields" ], "additionalProperties": false } ], "title": "Credential Provider", "description": "An OAuth or service-account connection method available to a workspace." }, "ListCredentialProvidersResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2CredentialProvider" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Always `null` — this list has no `cursor` or `limit` param and returns its whole bounded set in one page. Present so the list can gain pages later without a shape change." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List credential providers response", "description": "OAuth and service-account connection methods.", "examples": [ { "data": [ { "type": "oauth", "serviceId": "salesforce", "name": "Salesforce", "description": "Connect to Salesforce CRM data and operations.", "providerFamily": "salesforce", "available": true, "supportsReconnect": true, "authorizationOptions": [ { "providerId": "salesforce", "label": "Production" }, { "providerId": "salesforce-sandbox", "label": "Sandbox" } ] }, { "type": "service_account", "serviceId": "zoom-service-account", "providerId": "zoom-service-account", "name": "Zoom server-to-server app", "description": "Connect Zoom with a server-to-server app.", "providerFamily": "zoom", "available": true, "docsUrl": "https://docs.sim.ai/integrations/zoom-service-account", "requiresClientGeneratedCredentialId": false, "fields": [ { "id": "clientId", "label": "Client ID", "placeholder": "Paste the client ID", "required": true, "secret": false, "multiline": false }, { "id": "clientSecret", "label": "Client secret", "placeholder": "Paste the client secret", "required": true, "secret": true, "multiline": false }, { "id": "orgId", "label": "Account ID", "placeholder": "Paste the account ID", "required": true, "secret": false, "multiline": false } ] } ], "nextCursor": null } ] }, "CreateServiceAccountCredentialResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Credential" } }, "required": ["data"], "additionalProperties": false, "title": "Create service-account credential response", "description": "Verified credential metadata without secret material.", "examples": [ { "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "type": "service_account", "displayName": "Zoom service account", "description": null, "providerId": "zoom-service-account", "accountId": null, "hasServiceAccountKey": true, "role": "admin", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "CreateServiceAccountCredentialRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that will own the credential." }, "type": { "type": "string", "const": "service_account", "description": "Service-account credential discriminator." }, "providerId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Exact service-account provider ID returned by provider discovery." }, "displayName": { "description": "Optional name; providers may derive one from the verified account identity.", "type": "string", "minLength": 1, "maxLength": 255 }, "description": { "description": "Optional credential description.", "type": "string", "maxLength": 500 }, "id": { "description": "Required only when provider discovery requests a client-generated ID.", "type": "string", "format": "uuid", "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$" }, "credentials": { "type": "string", "minLength": 1, "maxLength": 131072, "description": "Write-only JSON object string containing the fields declared by credential-provider discovery.", "writeOnly": true } }, "required": ["workspaceId", "type", "providerId", "credentials"], "additionalProperties": false, "title": "Create service-account credential request", "description": "Provider identifier, optional display metadata, and a write-only JSON object string containing the fields declared by provider discovery." }, "V2CredentialConnectionAuthorization": { "type": "object", "properties": { "authorizationUrl": { "type": "string", "format": "uri", "description": "Short-lived Sim browser URL that starts the OAuth authorization flow." }, "expiresAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the connection link expires." } }, "required": ["authorizationUrl", "expiresAt"], "additionalProperties": false, "title": "Credential Connection Authorization", "description": "A short-lived browser entrypoint for an OAuth connection flow." }, "CreateCredentialConnectionResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CredentialConnectionAuthorization" } }, "required": ["data"], "additionalProperties": false, "title": "Create credential connection response", "description": "Short-lived Sim browser entrypoint and its expiry.", "examples": [ { "data": { "authorizationUrl": "https://www.sim.ai/api/auth/oauth2/authorize?draftId=draft-123", "expiresAt": "2026-06-20T14:17:11.000Z" } } ] }, "CreateCredentialConnectionBody": { "anyOf": [ { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace that will own the credential." }, "providerId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Exact OAuth provider ID returned by credential-provider discovery." }, "displayName": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Name shown for the new credential in Sim." } }, "required": ["workspaceId", "providerId", "displayName"], "additionalProperties": false }, { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace expected to own the credential." }, "credentialId": { "type": "string", "minLength": 1, "maxLength": 255, "description": "Existing OAuth credential to reconnect in place." } }, "required": ["workspaceId", "credentialId"], "additionalProperties": false } ], "title": "Create credential connection body", "description": "For a new connection, provide providerId and displayName. For a reconnect, provide only credentialId; the existing display name is preserved." }, "V2CredentialDeleteData": { "type": "object", "properties": { "id": { "type": "string", "minLength": 1, "description": "Disconnected credential identifier." }, "deleted": { "type": "boolean", "const": true, "description": "Whether the credential was disconnected." } }, "required": ["id", "deleted"], "additionalProperties": false, "title": "Delete credential data", "description": "Credential disconnection acknowledgement." }, "DeleteCredentialResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2CredentialDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Disconnect credential response", "description": "Acknowledgement that the credential was disconnected.", "examples": [ { "data": { "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "deleted": true } } ] }, "V2Secret": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_]+$", "description": "Secret name containing only letters, numbers, and underscores." }, "scope": { "type": "string", "enum": ["workspace", "personal"], "description": "Whether the secret belongs to the workspace or to the caller. A personal secret belongs to the caller across every workspace, not to one workspace." }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "What the secret is for, as set on the workspace secret. Always null for a personal secret, which has no shared audience." }, "role": { "type": "string", "enum": ["admin", "member"], "description": "Caller role for the secret." }, "createdAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the secret was created." }, "updatedAt": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the secret was last updated." } }, "required": ["name", "scope", "description", "role", "createdAt", "updatedAt"], "additionalProperties": false, "title": "Secret metadata", "description": "Public secret metadata without the stored secret value." }, "ListSecretsResponse": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/V2Secret" }, "description": "Items in the current page." }, "nextCursor": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Opaque cursor for the next page. Send it back as `cursor`; `null` means there is nothing further to fetch. Never construct one yourself." } }, "required": ["data", "nextCursor"], "additionalProperties": false, "title": "List secrets response", "description": "Secret metadata visible to the caller without stored values.", "examples": [ { "data": [ { "name": "STRIPE_API_KEY", "scope": "workspace", "description": "Production billing key — rotate quarterly.", "role": "admin", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } ], "nextCursor": null } ] }, "SetSecretResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2Secret" } }, "required": ["data"], "additionalProperties": false, "title": "Set secret response", "description": "Metadata for the created or replaced secret without its value.", "examples": [ { "data": { "name": "STRIPE_API_KEY", "scope": "workspace", "description": "Production billing key — rotate quarterly.", "role": "admin", "createdAt": "2026-06-01T09:14:00.000Z", "updatedAt": "2026-06-20T14:02:11.000Z" } } ] }, "SetSecretRequest": { "type": "object", "properties": { "workspaceId": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Workspace the request is authorized against. A workspace secret is written to it; a personal secret is written to the caller and is available in all of their workspaces." }, "scope": { "type": "string", "enum": ["workspace", "personal"], "description": "Whether the secret belongs to the workspace or to the caller. A personal secret belongs to the caller across every workspace, not to one workspace." }, "value": { "type": "string", "minLength": 1, "maxLength": 65536, "description": "Write-only secret value. It is never returned.", "writeOnly": true }, "description": { "description": "What the secret is for, shown to teammates. Workspace scope only — sending it for a personal secret is rejected. Omit it to leave an existing description untouched; send null or an empty string to clear one.", "anyOf": [ { "type": "string", "maxLength": 500 }, { "type": "null" } ] } }, "required": ["workspaceId", "scope", "value"], "additionalProperties": false, "title": "Set secret request", "description": "Ownership scope and write-only value for the secret.", "examples": [ { "workspaceId": "a91c4b2e-6d3f-4e8a-b5c7-0d9e2f1a8c64", "scope": "workspace", "value": "YOUR_SECRET_VALUE" } ] }, "V2SecretDeleteData": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^[A-Za-z0-9_]+$", "description": "Secret name containing only letters, numbers, and underscores." }, "scope": { "type": "string", "enum": ["workspace", "personal"], "description": "Whether the secret belongs to the workspace or to the caller. A personal secret belongs to the caller across every workspace, not to one workspace." }, "deleted": { "type": "boolean", "const": true, "description": "Whether the secret was deleted." } }, "required": ["name", "scope", "deleted"], "additionalProperties": false, "title": "Delete secret data", "description": "Secret deletion acknowledgement without the stored value." }, "DeleteSecretResponse": { "type": "object", "properties": { "data": { "description": "Response data.", "$ref": "#/components/schemas/V2SecretDeleteData" } }, "required": ["data"], "additionalProperties": false, "title": "Delete secret response", "description": "Acknowledgement that the secret was deleted.", "examples": [ { "data": { "name": "STRIPE_API_KEY", "scope": "workspace", "deleted": true } } ] } } }, "x-generated-by": "scripts/generate-openapi.ts" }